The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/fault.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 int
    9 fault(ulong addr, int read)
   10 {
   11         Segment *s;
   12         char *sps;
   13 
   14         if(up == nil)
   15                 panic("fault: nil up");
   16         if(up->nlocks.ref)
   17                 print("fault: nlocks %ld\n", up->nlocks.ref);
   18 
   19         sps = up->psstate;
   20         up->psstate = "Fault";
   21         spllo();
   22 
   23         m->pfault++;
   24         for(;;) {
   25                 s = seg(up, addr, 1);           /* leaves s->lk qlocked if seg != nil */
   26                 if(s == 0) {
   27                         up->psstate = sps;
   28                         return -1;
   29                 }
   30 
   31                 if(!read && (s->type&SG_RONLY)) {
   32                         qunlock(&s->lk);
   33                         up->psstate = sps;
   34                         return -1;
   35                 }
   36 
   37                 if(fixfault(s, addr, read, 1) == 0)
   38                         break;
   39         }
   40 
   41         up->psstate = sps;
   42         return 0;
   43 }
   44 
   45 static void
   46 faulterror(char *s, Chan *c, int freemem)
   47 {
   48         char buf[ERRMAX];
   49 
   50         if(c && c->path){
   51                 snprint(buf, sizeof buf, "%s accessing %s: %s", s, c->path->s, up->errstr);
   52                 s = buf;
   53         }
   54         if(up->nerrlab) {
   55                 postnote(up, 1, s, NDebug);
   56                 error(s);
   57         }
   58         pexit(s, freemem);
   59 }
   60 
   61 void    (*checkaddr)(ulong, Segment *, Page *);
   62 ulong   addr2check;
   63 
   64 int
   65 fixfault(Segment *s, ulong addr, int read, int doputmmu)
   66 {
   67         int type;
   68         int ref;
   69         Pte **p, *etp;
   70         ulong mmuphys=0, soff;
   71         Page **pg, *lkp, *new;
   72         Page *(*fn)(Segment*, ulong);
   73 
   74         addr &= ~(BY2PG-1);
   75         soff = addr-s->base;
   76         p = &s->map[soff/PTEMAPMEM];
   77         if(*p == 0)
   78                 *p = ptealloc();
   79 
   80         etp = *p;
   81         pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG];
   82         type = s->type&SG_TYPE;
   83 
   84         if(pg < etp->first)
   85                 etp->first = pg;
   86         if(pg > etp->last)
   87                 etp->last = pg;
   88 
   89         switch(type) {
   90         default:
   91                 panic("fault");
   92                 break;
   93 
   94         case SG_TEXT:                   /* Demand load */
   95                 if(pagedout(*pg))
   96                         pio(s, addr, soff, pg);
   97 
   98                 mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID;
   99                 (*pg)->modref = PG_REF;
  100                 break;
  101 
  102         case SG_BSS:
  103         case SG_SHARED:                 /* Zero fill on demand */
  104         case SG_STACK:
  105                 if(*pg == 0) {
  106                         new = newpage(1, &s, addr);
  107                         if(s == 0)
  108                                 return -1;
  109 
  110                         *pg = new;
  111                 }
  112                 goto common;
  113 
  114         case SG_DATA:
  115         common:                 /* Demand load/pagein/copy on write */
  116                 if(pagedout(*pg))
  117                         pio(s, addr, soff, pg);
  118 
  119                 /*
  120                  *  It's only possible to copy on write if
  121                  *  we're the only user of the segment.
  122                  */
  123                 if(read && conf.copymode == 0 && s->ref == 1) {
  124                         mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID;
  125                         (*pg)->modref |= PG_REF;
  126                         break;
  127                 }
  128 
  129                 lkp = *pg;
  130                 lock(lkp);
  131 
  132                 if(lkp->image == &swapimage)
  133                         ref = lkp->ref + swapcount(lkp->daddr);
  134                 else
  135                         ref = lkp->ref;
  136                 if(ref > 1) {
  137                         unlock(lkp);
  138 
  139                         if(swapfull()){
  140                                 qunlock(&s->lk);
  141                                 pprint("swap space full\n");
  142                                 faulterror(Enoswap, nil, 1);
  143                         }
  144 
  145                         new = newpage(0, &s, addr);
  146                         if(s == 0)
  147                                 return -1;
  148                         *pg = new;
  149                         copypage(lkp, *pg);
  150                         putpage(lkp);
  151                 }
  152                 else {
  153                         /* save a copy of the original for the image cache */
  154                         if(lkp->image && !swapfull())
  155                                 duppage(lkp);
  156 
  157                         unlock(lkp);
  158                 }
  159                 mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID;
  160                 (*pg)->modref = PG_MOD|PG_REF;
  161                 break;
  162 
  163         case SG_PHYSICAL:
  164                 if(*pg == 0) {
  165                         fn = s->pseg->pgalloc;
  166                         if(fn)
  167                                 *pg = (*fn)(s, addr);
  168                         else {
  169                                 new = smalloc(sizeof(Page));
  170                                 new->va = addr;
  171                                 new->pa = s->pseg->pa+(addr-s->base);
  172                                 new->ref = 1;
  173                                 *pg = new;
  174                         }
  175                 }
  176 
  177                 if (checkaddr && addr == addr2check)
  178                         (*checkaddr)(addr, s, *pg);
  179                 mmuphys = PPN((*pg)->pa) |PTEWRITE|PTEUNCACHED|PTEVALID;
  180                 (*pg)->modref = PG_MOD|PG_REF;
  181                 break;
  182         }
  183         qunlock(&s->lk);
  184 
  185         if(doputmmu)
  186                 putmmu(addr, mmuphys, *pg);
  187 
  188         return 0;
  189 }
  190 
  191 void
  192 pio(Segment *s, ulong addr, ulong soff, Page **p)
  193 {
  194         Page *new;
  195         KMap *k;
  196         Chan *c;
  197         int n, ask;
  198         char *kaddr;
  199         ulong daddr;
  200         Page *loadrec;
  201 
  202 retry:
  203         loadrec = *p;
  204         if(loadrec == 0) {      /* from a text/data image */
  205                 daddr = s->fstart+soff;
  206                 new = lookpage(s->image, daddr);
  207                 if(new != nil) {
  208                         *p = new;
  209                         return;
  210                 }
  211         }
  212         else {                  /* from a swap image */
  213                 daddr = swapaddr(loadrec);
  214                 new = lookpage(&swapimage, daddr);
  215                 if(new != nil) {
  216                         putswap(loadrec);
  217                         *p = new;
  218                         return;
  219                 }
  220         }
  221 
  222 
  223         qunlock(&s->lk);
  224 
  225         new = newpage(0, 0, addr);
  226         k = kmap(new);
  227         kaddr = (char*)VA(k);
  228 
  229         if(loadrec == 0) {                      /* This is demand load */
  230                 c = s->image->c;
  231                 while(waserror()) {
  232                         if(strcmp(up->errstr, Eintr) == 0)
  233                                 continue;
  234                         kunmap(k);
  235                         putpage(new);
  236                         faulterror("sys: demand load I/O error", c, 0);
  237                 }
  238 
  239                 ask = s->flen-soff;
  240                 if(ask > BY2PG)
  241                         ask = BY2PG;
  242 
  243                 n = devtab[c->type]->read(c, kaddr, ask, daddr);
  244                 if(n != ask)
  245                         faulterror(Eioload, c, 0);
  246                 if(ask < BY2PG)
  247                         memset(kaddr+ask, 0, BY2PG-ask);
  248 
  249                 poperror();
  250                 kunmap(k);
  251                 qlock(&s->lk);
  252 
  253                 /*
  254                  *  race, another proc may have gotten here first while
  255                  *  s->lk was unlocked
  256                  */
  257                 if(*p == 0) { 
  258                         new->daddr = daddr;
  259                         cachepage(new, s->image);
  260                         *p = new;
  261                 }
  262                 else
  263                         putpage(new);
  264         }
  265         else {                          /* This is paged out */
  266                 c = swapimage.c;
  267                 if(waserror()) {
  268                         kunmap(k);
  269                         putpage(new);
  270                         qlock(&s->lk);
  271                         qunlock(&s->lk);
  272                         faulterror("sys: page in I/O error", c, 0);
  273                 }
  274 
  275                 n = devtab[c->type]->read(c, kaddr, BY2PG, daddr);
  276                 if(n != BY2PG)
  277                         faulterror(Eioload, c, 0);
  278 
  279                 poperror();
  280                 kunmap(k);
  281                 qlock(&s->lk);
  282 
  283                 /*
  284                  *  race, another proc may have gotten here first
  285                  *  (and the pager may have run on that page) while
  286                  *  s->lk was unlocked
  287                  */
  288                 if(*p != loadrec){
  289                         if(!pagedout(*p)){
  290                                 /* another process did it for me */
  291                                 putpage(new);
  292                                 goto done;
  293                         } else {
  294                                 /* another process and the pager got in */
  295                                 putpage(new);
  296                                 goto retry;
  297                         }
  298                 }
  299 
  300                 new->daddr = daddr;
  301                 cachepage(new, &swapimage);
  302                 *p = new;
  303                 putswap(loadrec);
  304         }
  305 
  306 done:
  307         if(s->flushme)
  308                 memset((*p)->cachectl, PG_TXTFLUSH, sizeof((*p)->cachectl));
  309 }
  310 
  311 /*
  312  * Called only in a system call
  313  */
  314 int
  315 okaddr(ulong addr, ulong len, int write)
  316 {
  317         Segment *s;
  318 
  319         if((long)len >= 0) {
  320                 for(;;) {
  321                         s = seg(up, addr, 0);
  322                         if(s == 0 || (write && (s->type&SG_RONLY)))
  323                                 break;
  324 
  325                         if(addr+len > s->top) {
  326                                 len -= s->top - addr;
  327                                 addr = s->top;
  328                                 continue;
  329                         }
  330                         return 1;
  331                 }
  332         }
  333         pprint("suicide: invalid address %#lux/%lud in sys call pc=%#lux\n", addr, len, userpc());
  334         return 0;
  335 }
  336 
  337 void
  338 validaddr(ulong addr, ulong len, int write)
  339 {
  340         if(!okaddr(addr, len, write))
  341                 pexit("Suicide", 0);
  342 }
  343 
  344 /*
  345  * &s[0] is known to be a valid address.
  346  */
  347 void*
  348 vmemchr(void *s, int c, int n)
  349 {
  350         int m;
  351         ulong a;
  352         void *t;
  353 
  354         a = (ulong)s;
  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);
  359                 if(t)
  360                         return t;
  361                 a += m;
  362                 n -= m;
  363                 if(a < KZERO)
  364                         validaddr(a, 1, 0);
  365         }
  366 
  367         /* fits in one page */
  368         return memchr((void*)a, c, n);
  369 }
  370 
  371 Segment*
  372 seg(Proc *p, ulong addr, int dolock)
  373 {
  374         Segment **s, **et, *n;
  375 
  376         et = &p->seg[NSEG];
  377         for(s = p->seg; s < et; s++) {
  378                 n = *s;
  379                 if(n == 0)
  380                         continue;
  381                 if(addr >= n->base && addr < n->top) {
  382                         if(dolock == 0)
  383                                 return n;
  384 
  385                         qlock(&n->lk);
  386                         if(addr >= n->base && addr < n->top)
  387                                 return n;
  388                         qunlock(&n->lk);
  389                 }
  390         }
  391 
  392         return 0;
  393 }
  394 
  395 extern void checkmmu(ulong, ulong);
  396 void
  397 checkpages(void)
  398 {
  399         int checked;
  400         ulong addr, off;
  401         Pte *p;
  402         Page *pg;
  403         Segment **sp, **ep, *s;
  404         
  405         if(up == nil)
  406                 return;
  407 
  408         checked = 0;
  409         for(sp=up->seg, ep=&up->seg[NSEG]; sp<ep; sp++){
  410                 s = *sp;
  411                 if(s == nil)
  412                         continue;
  413                 qlock(&s->lk);
  414                 for(addr=s->base; addr<s->top; addr+=BY2PG){
  415                         off = addr - s->base;
  416                         p = s->map[off/PTEMAPMEM];
  417                         if(p == 0)
  418                                 continue;
  419                         pg = p->pages[(off&(PTEMAPMEM-1))/BY2PG];
  420                         if(pg == 0 || pagedout(pg))
  421                                 continue;
  422                         checkmmu(addr, pg->pa);
  423                         checked++;
  424                 }
  425                 qunlock(&s->lk);
  426         }
  427         print("%ld %s: checked %d page table entries\n", up->pid, up->text, checked);
  428 }

Cache object: 8c1b1775508dd974efbc85f6a1542650


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.