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;
144 panic("fault: lkp->ref %d < 1", lkp->ref);
145 if(lkp->image == &swapimage)
146 ref = lkp->ref + swapcount(lkp->daddr);
149 if(ref == 1 && lkp->image){
150 /* save a copy of the original for the image cache */
156 new = newpage(0, &s, addr);
163 mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID;
164 (*pg)->modref = PG_MOD|PG_REF;
169 fn = s->pseg->pgalloc;
171 *pg = (*fn)(s, addr);
173 new = smalloc(sizeof(Page));
175 new->pa = s->pseg->pa+(addr-s->base);
181 if (checkaddr && addr == addr2check)
182 (*checkaddr)(addr, s, *pg);
183 mmuphys = PPN((*pg)->pa) |PTEWRITE|PTEUNCACHED|PTEVALID;
184 (*pg)->modref = PG_MOD|PG_REF;
190 putmmu(addr, mmuphys, *pg);
196 pio(Segment *s, ulong addr, ulong soff, Page **p)
208 if(loadrec == 0) { /* from a text/data image */
209 daddr = s->fstart+soff;
210 new = lookpage(s->image, daddr);
221 else { /* from a swap image */
222 daddr = swapaddr(loadrec);
223 new = lookpage(&swapimage, daddr);
235 new = newpage(0, 0, addr);
237 kaddr = (char*)VA(k);
240 if(strcmp(up->errstr, Eintr) == 0)
244 faulterror(Eioload, c, 0);
246 n = devtab[c->type]->read(c, kaddr, ask, daddr);
250 memset(kaddr+ask, 0, BY2PG-ask);
255 if(loadrec == 0) { /* This is demand load */
257 * race, another proc may have gotten here first while
262 cachepage(new, s->image);
268 else { /* This is paged out */
270 * race, another proc may have gotten here first
271 * (and the pager may have run on that page) while
276 /* another process did it for me */
280 /* another process and the pager got in */
284 /* another process segfreed the page */
286 memset((void*)VA(k), 0, ask);
294 cachepage(new, &swapimage);
301 memset((*p)->cachectl, PG_TXTFLUSH, sizeof((*p)->cachectl));
305 * Called only in a system call
308 okaddr(ulong addr, ulong len, int write)
314 s = seg(up, addr, 0);
315 if(s == 0 || (write && (s->type&SG_RONLY)))
318 if(addr+len > s->top) {
319 len -= s->top - addr;
326 pprint("suicide: invalid address %#lux/%lud in sys call pc=%#lux\n", addr, len, userpc());
331 validaddr(ulong addr, ulong len, int write)
333 if(!okaddr(addr, len, write)){
334 postnote(up, 1, "sys: bad address in syscall", NDebug);
340 * &s[0] is known to be a valid address.
343 vmemchr(void *s, int c, int n)
350 while(PGROUND(a) != PGROUND(a+n-1)){
351 /* spans pages; handle this page */
352 m = BY2PG - (a & (BY2PG-1));
353 t = memchr((void*)a, c, m);
362 /* fits in one page */
363 return memchr((void*)a, c, n);
367 seg(Proc *p, ulong addr, int dolock)
369 Segment **s, **et, *n;
372 for(s = p->seg; s < et; s++) {
376 if(addr >= n->base && addr < n->top) {
381 if(addr >= n->base && addr < n->top)
390 extern void checkmmu(ulong, ulong);
398 Segment **sp, **ep, *s;
404 for(sp=up->seg, ep=&up->seg[NSEG]; sp<ep; sp++){
409 for(addr=s->base; addr<s->top; addr+=BY2PG){
410 off = addr - s->base;
411 p = s->map[off/PTEMAPMEM];
414 pg = p->pages[(off&(PTEMAPMEM-1))/BY2PG];
415 if(pg == 0 || pagedout(pg))
417 checkmmu(addr, pg->pa);
422 print("%ld %s: checked %d page table entries\n", up->pid, up->text, checked);