fault.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. /*
  16. * Fault calls fixfault which ends up calling newpage, which
  17. * might fail to allocate a page for the right color. So, we
  18. * might enter a loop and retry forever.
  19. * We first try with the desired color, and then with any
  20. * other one, if we failed for some time.
  21. */
  22. int
  23. fault(uintptr addr, int read)
  24. {
  25. Segment *s;
  26. char *sps;
  27. int i, color;
  28. if(up->nlocks) print("fault nlocks %d\n", up->nlocks);
  29. sps = up->psstate;
  30. up->psstate = "Fault";
  31. spllo();
  32. m->pfault++;
  33. for(i = 0;; i++) {
  34. s = seg(up, addr, 1); /* leaves s->lk qlocked if seg != nil */
  35. if(s == 0) {
  36. up->psstate = sps;
  37. return -1;
  38. }
  39. if(!read && (s->type&SG_RONLY)) {
  40. qunlock(&s->lk);
  41. up->psstate = sps;
  42. return -1;
  43. }
  44. color = s->color;
  45. if(i > 3)
  46. color = -1;
  47. if(fixfault(s, addr, read, 1, color) == 0)
  48. break;
  49. /*
  50. * See the comment in newpage that describes
  51. * how to get here.
  52. */
  53. if(i > 0 && (i%1000) == 0)
  54. print("fault: tried %d times\n", i);
  55. }
  56. up->psstate = sps;
  57. return 0;
  58. }
  59. static void
  60. faulterror(char *s, Chan *c, int freemem)
  61. {
  62. char buf[ERRMAX];
  63. if(c && c->path){
  64. snprint(buf, sizeof buf, "%s accessing %s: %s", s, c->path->s, up->errstr);
  65. s = buf;
  66. }
  67. if(up->nerrlab) {
  68. postnote(up, 1, s, NDebug);
  69. error(s);
  70. }
  71. pexit(s, freemem);
  72. }
  73. int
  74. fixfault(Segment *s, uintptr addr, int read, int dommuput, int color)
  75. {
  76. int type;
  77. int ref;
  78. Pte **p, *etp;
  79. uintptr soff;
  80. uintmem pgsz;
  81. uint mmuattr;
  82. Page **pg, *lkp, *new;
  83. Page *(*fn)(Segment*, uintptr);
  84. pgsz = m->pgsz[s->pgszi];
  85. addr &= ~(pgsz-1);
  86. soff = addr-s->base;
  87. p = &s->map[soff/PTEMAPMEM];
  88. if(*p == 0)
  89. *p = ptealloc(s);
  90. etp = *p;
  91. pg = &etp->pages[(soff&(PTEMAPMEM-1))/pgsz];
  92. type = s->type&SG_TYPE;
  93. if(pg < etp->first)
  94. etp->first = pg;
  95. if(pg > etp->last)
  96. etp->last = pg;
  97. mmuattr = 0;
  98. switch(type) {
  99. default:
  100. panic("fault");
  101. break;
  102. case SG_TEXT: /* Demand load */
  103. if(pagedout(*pg))
  104. pio(s, addr, soff, pg, color);
  105. mmuattr = PTERONLY|PTEVALID;
  106. (*pg)->modref = PG_REF;
  107. break;
  108. case SG_BSS:
  109. case SG_SHARED: /* Zero fill on demand */
  110. case SG_STACK:
  111. if(*pg == 0) {
  112. new = newpage(1, &s, addr, pgsz, color);
  113. if(s == 0)
  114. return -1;
  115. *pg = new;
  116. }
  117. goto common;
  118. case SG_DATA:
  119. common: /* Demand load/pagein/copy on write */
  120. if(pagedout(*pg))
  121. pio(s, addr, soff, pg, color);
  122. /*
  123. * It's only possible to copy on write if
  124. * we're the only user of the segment.
  125. */
  126. if(read && conf.copymode == 0 && s->ref == 1) {
  127. mmuattr = PTERONLY|PTEVALID;
  128. (*pg)->modref |= PG_REF;
  129. break;
  130. }
  131. lkp = *pg;
  132. lock(lkp);
  133. ref = lkp->ref;
  134. if(ref > 1) {
  135. unlock(lkp);
  136. new = newpage(0, &s, addr, pgsz, color);
  137. if(s == 0)
  138. return -1;
  139. *pg = new;
  140. copypage(lkp, *pg);
  141. putpage(lkp);
  142. }
  143. else {
  144. /* save a copy of the original for the image cache */
  145. if(lkp->image != nil)
  146. duppage(lkp);
  147. unlock(lkp);
  148. }
  149. mmuattr = PTEWRITE|PTEVALID;
  150. (*pg)->modref = PG_MOD|PG_REF;
  151. break;
  152. case SG_PHYSICAL:
  153. if(*pg == 0) {
  154. fn = s->pseg->pgalloc;
  155. if(fn)
  156. *pg = (*fn)(s, addr);
  157. else {
  158. new = smalloc(sizeof(Page));
  159. new->va = addr;
  160. new->pa = s->pseg->pa+(addr-s->base);
  161. new->ref = 1;
  162. new->pgszi = s->pseg->pgszi;
  163. *pg = new;
  164. }
  165. }
  166. mmuattr = PTEVALID;
  167. if((s->pseg->attr & SG_RONLY) == 0)
  168. mmuattr |= PTEWRITE;
  169. if((s->pseg->attr & SG_CACHED) == 0)
  170. mmuattr |= PTEUNCACHED;
  171. (*pg)->modref = PG_MOD|PG_REF;
  172. break;
  173. }
  174. qunlock(&s->lk);
  175. if(dommuput){
  176. assert(segppn(s, (*pg)->pa) == (*pg)->pa);
  177. mmuput(addr, *pg, mmuattr);
  178. }
  179. return 0;
  180. }
  181. void
  182. pio(Segment *s, uintptr addr, uint32_t soff, Page **p, int color)
  183. {
  184. Page *new;
  185. KMap *k;
  186. Chan *c;
  187. int n, ask;
  188. uintmem pgsz;
  189. char *kaddr;
  190. uint32_t daddr;
  191. Page *loadrec;
  192. loadrec = *p;
  193. daddr = ask = 0;
  194. c = nil;
  195. pgsz = m->pgsz[s->pgszi];
  196. if(loadrec == nil) { /* from a text/data image */
  197. daddr = s->fstart+soff;
  198. new = lookpage(s->image, daddr);
  199. if(new != nil) {
  200. *p = new;
  201. return;
  202. }
  203. c = s->image->c;
  204. ask = s->flen-soff;
  205. if(ask > pgsz)
  206. ask = pgsz;
  207. }
  208. else
  209. panic("no swap");
  210. qunlock(&s->lk);
  211. new = newpage(0, 0, addr, pgsz, color);
  212. k = kmap(new);
  213. kaddr = (char*)VA(k);
  214. while(waserror()) {
  215. if(strcmp(up->errstr, Eintr) == 0)
  216. continue;
  217. kunmap(k);
  218. putpage(new);
  219. faulterror(Eioload, c, 0);
  220. }
  221. n = c->dev->read(c, kaddr, ask, daddr);
  222. if(n != ask)
  223. faulterror(Eioload, c, 0);
  224. if(ask < pgsz)
  225. memset(kaddr+ask, 0, pgsz-ask);
  226. poperror();
  227. kunmap(k);
  228. qlock(&s->lk);
  229. if(loadrec == nil) { /* This is demand load */
  230. /*
  231. * race, another proc may have gotten here first while
  232. * s->lk was unlocked
  233. */
  234. if(*p == nil) {
  235. new->daddr = daddr;
  236. cachepage(new, s->image);
  237. *p = new;
  238. }
  239. else
  240. putpage(new);
  241. }
  242. else
  243. panic("no swap");
  244. if(s->flushme)
  245. memset((*p)->cachectl, PG_TXTFLUSH, sizeof((*p)->cachectl));
  246. }
  247. /*
  248. * Called only in a system call
  249. */
  250. int
  251. okaddr(uintptr addr, int32_t len, int write)
  252. {
  253. Segment *s;
  254. if(len >= 0) {
  255. for(;;) {
  256. s = seg(up, addr, 0);
  257. if(s == 0 || (write && (s->type&SG_RONLY)))
  258. break;
  259. if(addr+len > s->top) {
  260. len -= s->top - addr;
  261. addr = s->top;
  262. continue;
  263. }
  264. return 1;
  265. }
  266. }
  267. return 0;
  268. }
  269. void*
  270. validaddr(void* addr, int32_t len, int write)
  271. {
  272. if(!okaddr(PTR2UINT(addr), len, write)){
  273. pprint("suicide: invalid address %#p/%ld in sys call pc=%#p\n",
  274. addr, len, userpc(nil));
  275. pexit("Suicide", 0);
  276. }
  277. return UINT2PTR(addr);
  278. }
  279. /*
  280. * &s[0] is known to be a valid address.
  281. * Assume 2M pages, so it works for both 2M and 1G pages.
  282. * Note this won't work for 4*KiB pages!
  283. */
  284. void*
  285. vmemchr(void *s, int c, int n)
  286. {
  287. int m;
  288. uintptr a;
  289. void *t;
  290. a = PTR2UINT(s);
  291. while(ROUNDUP(a, BIGPGSZ) != ROUNDUP(a+n-1, BIGPGSZ)){
  292. /* spans pages; handle this page */
  293. m = BIGPGSZ - (a & (BIGPGSZ-1));
  294. t = memchr(UINT2PTR(a), c, m);
  295. if(t)
  296. return t;
  297. a += m;
  298. n -= m;
  299. if((a & KZERO) != KZERO)
  300. validaddr(UINT2PTR(a), 1, 0);
  301. }
  302. /* fits in one page */
  303. return memchr(UINT2PTR(a), c, n);
  304. }
  305. Segment*
  306. seg(Proc *p, uintptr addr, int dolock)
  307. {
  308. Segment **s, **et, *n;
  309. et = &p->seg[NSEG];
  310. for(s = p->seg; s < et; s++) {
  311. n = *s;
  312. if(n == 0)
  313. continue;
  314. if(addr >= n->base && addr < n->top) {
  315. if(dolock == 0)
  316. return n;
  317. qlock(&n->lk);
  318. if(addr >= n->base && addr < n->top)
  319. return n;
  320. qunlock(&n->lk);
  321. }
  322. }
  323. return 0;
  324. }