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/mtx/mmu.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        "io.h"
    7 
    8 /*
    9  *      We have one page table per processor.
   10  *
   11  *      Different processes are distinguished via the VSID field in
   12  *      the segment registers.  As flushing the entire page table is an
   13  *      expensive operation, we implement an aging algorithm for
   14  *      mmu pids, with a background kproc to purge stale pids en mass.
   15  *
   16  *      This needs modifications to run on a multiprocessor.
   17  */
   18 
   19 static ulong    ptabsize;                       /* number of bytes in page table */
   20 static ulong    ptabmask;               /* hash mask */
   21 
   22 /*
   23  *      VSID is 24 bits.  3 are required to distinguish segments in user
   24  *      space (kernel space only uses the BATs).  pid 0 is reserved.
   25  *      The top 2 bits of the pid are used as a `color' for the background
   26  *      pid reclaimation algorithm.
   27  */
   28 
   29 enum {
   30         PIDBASE = 1,
   31         PIDBITS = 21,
   32         COLBITS = 2,
   33         PIDMAX = ((1<<PIDBITS)-1),
   34         COLMASK = ((1<<COLBITS)-1),
   35 };
   36 
   37 #define VSID(pid, i)    (((pid)<<3)|i)
   38 #define PIDCOLOR(pid)   ((pid)>>(PIDBITS-COLBITS))
   39 #define PTECOL(color)   PTE0(1, VSID(((color)<<(PIDBITS-COLBITS)), 0), 0, 0)
   40 
   41 void
   42 mmuinit(void)
   43 {
   44         int lhash, mem;
   45         extern ulong memsize;   /* passed in from ROM monitor */
   46 
   47         if(ptabsize == 0) {
   48                 /* heuristically size the hash table */
   49                 lhash = 10;
   50                 mem = (1<<23);
   51                 while(mem < memsize) {
   52                         lhash++;
   53                         mem <<= 1;
   54                 }
   55                 ptabsize = (1<<(lhash+6));
   56                 ptabmask = (1<<lhash)-1;
   57         }
   58 
   59         m->ptabbase = (ulong)xspanalloc(ptabsize, 0, ptabsize);
   60         putsdr1(PADDR(m->ptabbase) | (ptabmask>>10));
   61         m->mmupid = PIDBASE;
   62         m->sweepcolor = 0;
   63         m->trigcolor = COLMASK;
   64 }
   65 
   66 static int
   67 work(void*)
   68 {
   69         return PIDCOLOR(m->mmupid) == m->trigcolor;
   70 }
   71 
   72 void
   73 mmusweep(void*)
   74 {
   75         Proc *p;
   76         int i, x, sweepcolor;
   77         ulong *ptab, *ptabend, ptecol;
   78 
   79         for(;;) {
   80                 if(PIDCOLOR(m->mmupid) != m->trigcolor)
   81                         sleep(&m->sweepr, work, nil);
   82 
   83                 sweepcolor = m->sweepcolor;
   84                 x = splhi();
   85                 p = proctab(0);
   86                 for(i = 0; i < conf.nproc; i++, p++)
   87                         if(PIDCOLOR(p->mmupid) == sweepcolor)
   88                                 p->mmupid = 0;
   89                 splx(x);
   90 
   91                 ptab = (ulong*)m->ptabbase;
   92                 ptabend = (ulong*)(m->ptabbase+ptabsize);
   93                 ptecol = PTECOL(sweepcolor);
   94                 while(ptab < ptabend) {
   95                         if((*ptab & PTECOL(3)) == ptecol)
   96                                 *ptab = 0;
   97                         ptab += 2;
   98                 }
   99                 tlbflushall();
  100 
  101                 m->sweepcolor = (sweepcolor+1) & COLMASK;
  102                 m->trigcolor = (m->trigcolor+1) & COLMASK;
  103         }
  104 }
  105 
  106 int
  107 newmmupid(void)
  108 {
  109         int pid, newcolor;
  110 
  111         pid = m->mmupid++;
  112         if(m->mmupid > PIDMAX)
  113                 m->mmupid = PIDBASE;
  114         newcolor = PIDCOLOR(m->mmupid);
  115         if(newcolor != PIDCOLOR(pid)) {
  116                 if(newcolor == m->sweepcolor) {
  117                         /* desperation time.  can't block here.  punt to fault/putmmu */
  118                         print("newmmupid: %uld: no free mmu pids\n", up->pid);
  119                         if(m->mmupid == PIDBASE)
  120                                 m->mmupid = PIDMAX;
  121                         else
  122                                 m->mmupid--;
  123                         pid = 0;
  124                 }
  125                 else if(newcolor == m->trigcolor)
  126                         wakeup(&m->sweepr);
  127         }
  128         up->mmupid = pid;
  129         return pid;
  130 }
  131 
  132 void
  133 flushmmu(void)
  134 {
  135         int x;
  136 
  137         x = splhi();
  138         up->newtlb = 1;
  139         mmuswitch(up);
  140         splx(x);
  141 }
  142 
  143 /*
  144  * called with splhi
  145  */
  146 void
  147 mmuswitch(Proc *p)
  148 {
  149         int i, mp;
  150 
  151         if(p->kp) {
  152                 for(i = 0; i < 8; i++)
  153                         putsr(i<<28, 0);
  154                 return;
  155         }
  156 
  157         if(p->newtlb) {
  158                 p->mmupid = 0;
  159                 p->newtlb = 0;
  160         }
  161         mp = p->mmupid;
  162         if(mp == 0)
  163                 mp = newmmupid();
  164 
  165         for(i = 0; i < 8; i++)
  166                 putsr(i<<28, VSID(mp, i)|BIT(1)|BIT(2));
  167 }
  168 
  169 void
  170 mmurelease(Proc* p)
  171 {
  172         p->mmupid = 0;
  173 }
  174 
  175 void
  176 putmmu(ulong va, ulong pa, Page *pg)
  177 {
  178         int mp;
  179         char *ctl;
  180         ulong *p, *ep, *q, pteg;
  181         ulong vsid, ptehi, x, hash;
  182 
  183         /*
  184          *      If mmupid is 0, mmuswitch/newmmupid was unable to assign us
  185          *      a pid, hence we faulted.  Keep calling sched() until the mmusweep
  186          *      proc catches up, and we are able to get a pid.
  187          */
  188         while((mp = up->mmupid) == 0)
  189                 sched();
  190 
  191         vsid = VSID(mp, va>>28);
  192         hash = (vsid ^ (va>>12)&0xffff) & ptabmask;
  193         ptehi = PTE0(1, vsid, 0, va);
  194 
  195         pteg = m->ptabbase + BY2PTEG*hash;
  196         p = (ulong*)pteg;
  197         ep = (ulong*)(pteg+BY2PTEG);
  198         q = nil;
  199         tlbflush(va);
  200         while(p < ep) {
  201                 x = p[0];
  202                 if(x == ptehi) {
  203                         q = p;
  204                         break;
  205                 }
  206                 if(q == nil && (x & BIT(0)) == 0)
  207                         q = p;
  208                 p += 2;
  209         }
  210         if(q == nil) {
  211                 q = (ulong*)(pteg+m->slotgen);
  212                 m->slotgen = (m->slotgen + BY2PTE) & (BY2PTEG-1);
  213         }
  214         q[0] = ptehi;
  215         q[1] = pa;
  216         sync();
  217 
  218         ctl = &pg->cachectl[m->machno];
  219         switch(*ctl) {
  220         case PG_NEWCOL:
  221         default:
  222                 panic("putmmu: %d\n", *ctl);
  223                 break;
  224         case PG_NOFLUSH:
  225                 break;
  226         case PG_TXTFLUSH:
  227                 dcflush((void*)pg->va, BY2PG);
  228                 icflush((void*)pg->va, BY2PG);
  229                 *ctl = PG_NOFLUSH;
  230                 break;
  231         }
  232 }
  233 
  234 void
  235 checkmmu(ulong, ulong)
  236 {
  237 }
  238 
  239 void
  240 countpagerefs(ulong*, int)
  241 {
  242 }
  243 
  244 /*
  245  * Return the number of bytes that can be accessed via KADDR(pa).
  246  * If pa is not a valid argument to KADDR, return 0.
  247  */
  248 ulong
  249 cankaddr(ulong pa)
  250 {
  251         ulong kzero;
  252 
  253         kzero = -KZERO;
  254         if(pa >= kzero)
  255                 return 0;
  256         return kzero - pa;
  257 }

Cache object: 252cc26996d615ff232f18edc5d20831


[ 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.