2 #include "../port/lib.h"
6 #include "../port/error.h"
9 fault(ulong addr, int read)
16 panic("fault: nil up");
18 print("fault: nlocks %ld\n", up->nlocks.ref);
20 pnd = up->notepending;
22 up->psstate = "Fault";
28 s = seg(up, addr, 1); /* leaves s->lk qlocked if seg != nil */
34 if(!read && (s->type&SG_RONLY)) {
40 if(fixfault(s, addr, read, 1) == 0)
52 up->notepending |= pnd;
58 faulterror(char *s, Chan *c, int freemem)
63 snprint(buf, sizeof buf, "%s accessing %s: %s", s, c->path->s, up->errstr);
67 postnote(up, 1, s, NDebug);
73 void (*checkaddr)(ulong, Segment *, Page *);
77 fixfault(Segment *s, ulong addr, int read, int doputmmu)
82 ulong mmuphys=0, soff;
83 Page **pg, *lkp, *new;
84 Page *(*fn)(Segment*, ulong);
88 p = &s->map[soff/PTEMAPMEM];
93 pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG];
94 type = s->type&SG_TYPE;
106 case SG_TEXT: /* Demand load */
108 pio(s, addr, soff, pg);
110 mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID;
111 (*pg)->modref = PG_REF;
115 case SG_SHARED: /* Zero fill on demand */
118 new = newpage(1, &s, addr);
127 common: /* Demand load/pagein/copy on write */
129 pio(s, addr, soff, pg);
132 * It's only possible to copy on write if
133 * we're the only user of the segment.
135 if(read && conf.copymode == 0 && s->ref == 1) {
136 mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID;
137 (*pg)->modref |= PG_REF;
145 panic("fault %#p ref == 0", lkp);
146 if(lkp->image == &swapimage)
147 ref += swapcount(lkp->daddr);
148 if(ref == 1 && lkp->image) {
150 * save a copy of the original for the image cache
151 * and uncache the page. page might temporarily be
152 * unlocked while trying to acquire palloc lock so
153 * recheck ref in case it got grabbed.
161 new = newpage(0, &s, addr);
168 mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID;
169 (*pg)->modref = PG_MOD|PG_REF;
174 fn = s->pseg->pgalloc;
176 *pg = (*fn)(s, addr);
178 new = smalloc(sizeof(Page));
180 new->pa = s->pseg->pa+(addr-s->base);
186 if (checkaddr && addr == addr2check)
187 (*checkaddr)(addr, s, *pg);
188 mmuphys = PPN((*pg)->pa) |PTEWRITE|PTEUNCACHED|PTEVALID;
189 (*pg)->modref = PG_MOD|PG_REF;
195 putmmu(addr, mmuphys, *pg);
201 pio(Segment *s, ulong addr, ulong soff, Page **p)
213 if(loadrec == 0) { /* from a text/data image */
214 daddr = s->fstart+soff;
215 new = lookpage(s->image, daddr);
226 else { /* from a swap image */
227 daddr = swapaddr(loadrec);
228 new = lookpage(&swapimage, daddr);
240 new = newpage(0, 0, addr);
242 kaddr = (char*)VA(k);
245 if(strcmp(up->errstr, Eintr) == 0)
249 faulterror(Eioload, c, 0);
251 n = devtab[c->type]->read(c, kaddr, ask, daddr);
255 memset(kaddr+ask, 0, BY2PG-ask);
260 if(loadrec == 0) { /* This is demand load */
262 * race, another proc may have gotten here first while
267 cachepage(new, s->image);
273 else { /* This is paged out */
275 * race, another proc may have gotten here first
276 * (and the pager may have run on that page) while
281 /* another process did it for me */
285 /* another process and the pager got in */
289 /* another process segfreed the page */
291 memset((void*)VA(k), 0, ask);
299 cachepage(new, &swapimage);
306 memset((*p)->cachectl, PG_TXTFLUSH, sizeof((*p)->cachectl));
310 * Called only in a system call
313 okaddr(ulong addr, ulong len, int write)
319 s = seg(up, addr, 0);
320 if(s == 0 || (write && (s->type&SG_RONLY)))
323 if(addr+len > s->top) {
324 len -= s->top - addr;
331 pprint("suicide: invalid address %#lux/%lud in sys call pc=%#lux\n", addr, len, userpc());
336 validaddr(ulong addr, ulong len, int write)
338 if(!okaddr(addr, len, write)){
339 postnote(up, 1, "sys: bad address in syscall", NDebug);
345 * &s[0] is known to be a valid address.
348 vmemchr(void *s, int c, int n)
355 while(PGROUND(a) != PGROUND(a+n-1)){
356 /* spans pages; handle this page */
357 m = BY2PG - (a & (BY2PG-1));
358 t = memchr((void*)a, c, m);
367 /* fits in one page */
368 return memchr((void*)a, c, n);
372 seg(Proc *p, ulong addr, int dolock)
374 Segment **s, **et, *n;
377 for(s = p->seg; s < et; s++) {
381 if(addr >= n->base && addr < n->top) {
386 if(addr >= n->base && addr < n->top)
395 extern void checkmmu(ulong, ulong);
403 Segment **sp, **ep, *s;
409 for(sp=up->seg, ep=&up->seg[NSEG]; sp<ep; sp++){
414 for(addr=s->base; addr<s->top; addr+=BY2PG){
415 off = addr - s->base;
416 p = s->map[off/PTEMAPMEM];
419 pg = p->pages[(off&(PTEMAPMEM-1))/BY2PG];
420 if(pg == 0 || pagedout(pg))
422 checkmmu(addr, pg->pa);
427 print("%ld %s: checked %d page table entries\n", up->pid, up->text, checked);