1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 8 void faulterror(char*); 9 10 int 11 fault(ulong addr, int read) 12 { 13 Segment *s; 14 char *sps; 15 16 sps = u->p->psstate; 17 u->p->psstate = "Fault"; 18 spllo(); 19 20 m->pfault++; 21 for(;;) { 22 s = seg(u->p, addr, 1); 23 if(s == 0) { 24 u->p->psstate = sps; 25 return -1; 26 } 27 28 if(!read && (s->type&SG_RONLY)) { 29 qunlock(&s->lk); 30 u->p->psstate = sps; 31 return -1; 32 } 33 34 if(fixfault(s, addr, read, 1) == 0) 35 break; 36 } 37 38 u->p->psstate = sps; 39 return 0; 40 } 41 42 int 43 fixfault(Segment *s, ulong addr, int read, int doputmmu) 44 { 45 int type; 46 Pte **p, *etp; 47 ulong mmuphys=0, soff; 48 Page **pg, *lkp, *new; 49 Page *(*fn)(Segment*, ulong); 50 51 addr &= ~(BY2PG-1); 52 soff = addr-s->base; 53 p = &s->map[soff/PTEMAPMEM]; 54 if(*p == 0) 55 *p = ptealloc(); 56 57 etp = *p; 58 pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 59 type = s->type&SG_TYPE; 60 61 if(pg < etp->first) 62 etp->first = pg; 63 if(pg > etp->last) 64 etp->last = pg; 65 66 switch(type) { 67 default: 68 panic("fault"); 69 break; 70 71 case SG_TEXT: 72 if(pagedout(*pg)) /* Demand load */ 73 pio(s, addr, soff, pg); 74 75 mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; 76 (*pg)->modref = PG_REF; 77 break; 78 79 case SG_SHDATA: /* Shared data */ 80 if(pagedout(*pg)) 81 pio(s, addr, soff, pg); 82 83 lkp = *pg; 84 lock(lkp); 85 if(lkp->image) 86 duppage(lkp); 87 unlock(lkp); 88 goto done; 89 90 case SG_BSS: 91 case SG_SHARED: /* Zero fill on demand */ 92 case SG_STACK: 93 if(*pg == 0) { 94 new = newpage(1, &s, addr); 95 if(s == 0) 96 return -1; 97 98 *pg = new; 99 } 100 /* NO break */ 101 102 case SG_DATA: /* Demand load/pagein/copy on write */ 103 if(pagedout(*pg)) 104 pio(s, addr, soff, pg); 105 106 if(type == SG_SHARED) 107 goto done; 108 109 if(read && conf.copymode == 0) { 110 mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; 111 (*pg)->modref |= PG_REF; 112 break; 113 } 114 115 lkp = *pg; 116 lock(lkp); 117 if(lkp->ref > 1) { 118 unlock(lkp); 119 new = newpage(0, &s, addr); 120 if(s == 0) 121 return -1; 122 *pg = new; 123 copypage(lkp, *pg); 124 putpage(lkp); 125 } 126 else { 127 /* put a duplicate of a text page back onto the free list */ 128 if(lkp->image) 129 duppage(lkp); 130 131 unlock(lkp); 132 } 133 done: 134 mmuphys = PPN((*pg)->pa) | PTEWRITE|PTEVALID; 135 (*pg)->modref = PG_MOD|PG_REF; 136 break; 137 138 case SG_PHYSICAL: 139 if(*pg == 0) { 140 fn = s->pseg->pgalloc; 141 if(fn) 142 *pg = (*fn)(s, addr); 143 else { 144 new = smalloc(sizeof(Page)); 145 new->va = addr; 146 new->pa = s->pseg->pa+(addr-s->base); 147 new->ref = 1; 148 *pg = new; 149 } 150 } 151 152 mmuphys = PPN((*pg)->pa) |PTEWRITE|PTEUNCACHED|PTEVALID; 153 (*pg)->modref = PG_MOD|PG_REF; 154 /* print("v %lux p %lux\n", addr, mmuphys); /**/ 155 break; 156 } 157 158 if(s->flushme) 159 memset((*pg)->cachectl, PG_TXTFLUSH, sizeof(new->cachectl)); 160 161 qunlock(&s->lk); 162 163 if(doputmmu) 164 putmmu(addr, mmuphys, *pg); 165 166 return 0; 167 } 168 169 void 170 pio(Segment *s, ulong addr, ulong soff, Page **p) 171 { 172 Page *new; 173 KMap *k; 174 Chan *c; 175 int n, ask; 176 char *kaddr; 177 ulong daddr; 178 Page *loadrec; 179 180 loadrec = *p; 181 if(loadrec == 0) { 182 daddr = s->fstart+soff; /* Compute disc address */ 183 new = lookpage(s->image, daddr); 184 } 185 else { 186 daddr = swapaddr(loadrec); 187 new = lookpage(&swapimage, daddr); 188 if(new) 189 putswap(loadrec); 190 } 191 192 if(new) { /* Page found from cache */ 193 *p = new; 194 return; 195 } 196 197 qunlock(&s->lk); 198 199 new = newpage(0, 0, addr); 200 k = kmap(new); 201 kaddr = (char*)VA(k); 202 203 if(loadrec == 0) { /* This is demand load */ 204 c = s->image->c; 205 while(waserror()) { 206 if(strcmp(u->error, Eintr) == 0) 207 continue; 208 kunmap(k); 209 putpage(new); 210 faulterror("sys: demand load I/O error"); 211 } 212 213 ask = s->flen-soff; 214 if(ask > BY2PG) 215 ask = BY2PG; 216 217 n = (*devtab[c->type].read)(c, kaddr, ask, daddr); 218 if(n != ask){ 219 print("demand load: %s: %d %d\n", u->error, n, ask); 220 error(Eioload); 221 } 222 if(ask < BY2PG) 223 memset(kaddr+ask, 0, BY2PG-ask); 224 225 poperror(); 226 kunmap(k); 227 qlock(&s->lk); 228 if(*p == 0) { /* Someone may have got there first */ 229 new->daddr = daddr; 230 cachepage(new, s->image); 231 *p = new; 232 } 233 else 234 putpage(new); 235 } 236 else { /* This is paged out */ 237 c = swapimage.c; 238 239 if(waserror()) { 240 kunmap(k); 241 putpage(new); 242 qlock(&s->lk); 243 qunlock(&s->lk); 244 faulterror("sys: page in I/O error"); 245 } 246 247 n = (*devtab[c->type].read)(c, kaddr, BY2PG, daddr); 248 if(n != BY2PG){ 249 print("page in: %s: %d %d\n", u->error, n, BY2PG); 250 error(Eioload); 251 } 252 253 poperror(); 254 kunmap(k); 255 qlock(&s->lk); 256 257 if(pagedout(*p)) { 258 new->daddr = daddr; 259 cachepage(new, &swapimage); 260 putswap(*p); 261 *p = new; 262 } 263 else 264 putpage(new); 265 } 266 } 267 268 void 269 faulterror(char *s) 270 { 271 if(u->nerrlab) { 272 postnote(u->p, 1, s, NUser); 273 error(s); 274 } 275 pexit(s, 1); 276 } 277 278 /* 279 * Called only in a system call 280 */ 281 int 282 okaddr(ulong addr, ulong len, int write) 283 { 284 Segment *s; 285 286 if((long)len >= 0) { 287 for(;;) { 288 s = seg(u->p, addr, 0); 289 if(s == 0 || (write && (s->type&SG_RONLY))) 290 break; 291 292 if(addr+len > s->top) { 293 len -= s->top - addr; 294 addr = s->top; 295 continue; 296 } 297 return 1; 298 } 299 } 300 pprint("suicide: invalid address 0x%lux in sys call pc=0x%lux\n", addr, userpc()); 301 return 0; 302 } 303 304 void 305 validaddr(ulong addr, ulong len, int write) 306 { 307 if(!okaddr(addr, len, write)) 308 pexit("Suicide", 0); 309 } 310 311 /* 312 * &s[0] is known to be a valid address. 313 */ 314 void* 315 vmemchr(void *s, int c, int n) 316 { 317 int m; 318 char *t; 319 ulong a; 320 321 a = (ulong)s; 322 m = BY2PG - (a & (BY2PG-1)); 323 if(m < n){ 324 t = vmemchr(s, c, m); 325 if(t) 326 return t; 327 if(!(a & KZERO)) 328 validaddr(a+m, 1, 0); 329 return vmemchr((void*)(a+m), c, n-m); 330 } 331 /* 332 * All in one page 333 */ 334 return memchr(s, c, n); 335 } 336 337 Segment* 338 seg(Proc *p, ulong addr, int dolock) 339 { 340 Segment **s, **et, *n; 341 342 et = &p->seg[NSEG]; 343 for(s = p->seg; s < et; s++) 344 if(n = *s){ 345 if(addr >= n->base && addr < n->top) { 346 if(dolock == 0) 347 return n; 348 349 qlock(&n->lk); 350 if(addr >= n->base && addr < n->top) 351 return n; 352 qunlock(&n->lk); 353 } 354 } 355 356 return 0; 357 } 358