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/ppc/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        <ureg.h>
    3 #include        "../port/lib.h"
    4 #include        "mem.h"
    5 #include        "dat.h"
    6 #include        "fns.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 reclamation 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, i;
   45         ulong memsize;
   46 
   47         memsize = conf.npage * BY2PG;
   48         if(ptabsize == 0) {
   49                 /* heuristically size the hash table */
   50                 lhash = 10;
   51                 mem = (1<<23);
   52                 while(mem < memsize) {
   53                         lhash++;
   54                         mem <<= 1;
   55                 }
   56                 ptabsize = (1<<(lhash+6));
   57                 ptabmask = (1<<lhash)-1;
   58         }
   59         m->ptabbase = (ulong)xspanalloc(ptabsize, 0, ptabsize);
   60         /* set page table base address */
   61         putsdr1(PADDR(m->ptabbase) | (ptabmask>>10));
   62         m->mmupid = PIDBASE;
   63         m->sweepcolor = 0;
   64         m->trigcolor = COLMASK;
   65 
   66         for(i = 0; i < 16; i++)
   67                 putsr(i<<28, 0);
   68 }
   69 
   70 static int
   71 work(void*)
   72 {
   73         return PIDCOLOR(m->mmupid) == m->trigcolor;
   74 }
   75 
   76 void
   77 mmusweep(void*)
   78 {
   79         Proc *p;
   80         int i, x, sweepcolor;
   81         ulong *ptab, *ptabend, ptecol;
   82 
   83         for(;;) {
   84                 if(PIDCOLOR(m->mmupid) != m->trigcolor)
   85                         sleep(&m->sweepr, work, nil);
   86 
   87                 sweepcolor = m->sweepcolor;
   88                 x = splhi();
   89                 p = proctab(0);
   90                 for(i = 0; i < conf.nproc; i++, p++)
   91                         if(PIDCOLOR(p->mmupid) == sweepcolor)
   92                                 p->mmupid = 0;
   93                 splx(x);
   94 
   95                 ptab = (ulong*)m->ptabbase;
   96                 ptabend = (ulong*)(m->ptabbase+ptabsize);
   97                 ptecol = PTECOL(sweepcolor);
   98                 while(ptab < ptabend) {
   99                         if((*ptab & PTECOL(3)) == ptecol){
  100                                 *ptab = 0;
  101                         }
  102                         ptab += 2;
  103                 }
  104 
  105                 m->sweepcolor = (sweepcolor+1) & COLMASK;
  106                 m->trigcolor = (m->trigcolor+1) & COLMASK;
  107         }
  108 }
  109 
  110 int
  111 newmmupid(void)
  112 {
  113         int pid, newcolor, i, x;
  114         Proc *p;
  115 
  116         pid = m->mmupid++;
  117         if(m->mmupid > PIDMAX){
  118                 /* Used up all mmupids, start again from first.  Flush the tlb
  119                  * to delete any entries with old pids remaining, then reassign
  120                  * all pids.
  121                  */
  122                 m->mmupid = PIDBASE;
  123                 x = splhi();
  124                 tlbflushall();
  125                 p = proctab(0);
  126                 for(i = 0; i < conf.nproc; i++, p++)
  127                         p->mmupid = 0;
  128                 splx(x);
  129                 wakeup(&m->sweepr);
  130         }
  131         newcolor = PIDCOLOR(m->mmupid);
  132         if(newcolor != PIDCOLOR(pid)) {
  133                 if(newcolor == m->sweepcolor) {
  134                         /* desperation time.  can't block here.  punt to fault/putmmu */
  135                         print("newmmupid: %uld: no free mmu pids\n", up->pid);
  136                         if(m->mmupid == PIDBASE)
  137                                 m->mmupid = PIDMAX;
  138                         else
  139                                 m->mmupid--;
  140                         pid = 0;
  141                 }
  142                 else if(newcolor == m->trigcolor)
  143                         wakeup(&m->sweepr);
  144         }
  145         up->mmupid = pid;
  146         return pid;
  147 }
  148 
  149 void
  150 flushmmu(void)
  151 {
  152         int x;
  153 
  154         x = splhi();
  155         up->newtlb = 1;
  156         mmuswitch(up);
  157         splx(x);
  158 }
  159 
  160 /*
  161  * called with splhi
  162  */
  163 void
  164 mmuswitch(Proc *p)
  165 {
  166         int i, mp;
  167         ulong r;
  168 
  169         if(p->kp) {
  170                 for(i = 0; i < 8; i++)
  171                         putsr(i<<28, 0);
  172                 return;
  173         }
  174 
  175         if(p->newtlb) {
  176                 p->mmupid = 0;
  177                 p->newtlb = 0;
  178         }
  179         mp = p->mmupid;
  180         if(mp == 0)
  181                 mp = newmmupid();
  182 
  183         for(i = 0; i < 8; i++){
  184                 r = VSID(mp, i)|BIT(1)|BIT(2);
  185                 putsr(i<<28, r);
  186         }
  187 }
  188 
  189 void
  190 mmurelease(Proc* p)
  191 {
  192         p->mmupid = 0;
  193 }
  194 
  195 void
  196 putmmu(ulong va, ulong pa, Page *pg)
  197 {
  198         int mp;
  199         char *ctl;
  200         ulong *p, *ep, *q, pteg;
  201         ulong vsid, hash;
  202         ulong ptehi, x;
  203         static ulong pva;
  204 
  205         /*
  206          *      If mmupid is 0, mmuswitch/newmmupid was unable to assign us
  207          *      a pid, hence we faulted.  Keep calling sched() until the mmusweep
  208          *      proc catches up, and we are able to get a pid.
  209          */
  210         while((mp = up->mmupid) == 0)
  211                 sched();
  212 
  213         vsid = VSID(mp, va>>28);
  214         hash = (vsid ^ ((va>>12)&0xffff)) & ptabmask;
  215         ptehi = PTE0(1, vsid, 0, va);
  216         pteg = m->ptabbase + BY2PTEG*hash;
  217 
  218         p = (ulong*)pteg;
  219         ep = (ulong*)(pteg+BY2PTEG);
  220         q = nil;
  221 
  222         while(p < ep) {
  223                 x = p[0];
  224                 if(x == ptehi) {
  225                         q = p;
  226                         break;
  227                 }
  228                 if(q == nil && (x & BIT(0)) == 0)
  229                         q = p;
  230                 p += 2;
  231         }
  232         if(q == nil) {
  233                 q = (ulong*)(pteg+m->slotgen);
  234                 m->slotgen = (m->slotgen + BY2PTE) & (BY2PTEG-1);
  235         }
  236 
  237         if (q[0] != ptehi || q[1] != pa){
  238                 tlbflush(va);
  239                 m->tlbpurge++;
  240         }
  241         q[0] = ptehi;
  242         q[1] = pa;
  243 
  244         ctl = &pg->cachectl[m->machno];
  245         switch(*ctl) {
  246         case PG_NEWCOL:
  247         default:
  248                 panic("putmmu: %d\n", *ctl);
  249                 break;
  250         case PG_TXTFLUSH:
  251                 dcflush((void*)pg->va, BY2PG);
  252                 icflush((void*)pg->va, BY2PG);
  253                 *ctl = PG_NOFLUSH;
  254                 break;
  255         case PG_NOFLUSH:
  256                 break;
  257         }
  258 
  259 }
  260 
  261 void
  262 checkmmu(ulong, ulong)
  263 {
  264 }
  265 
  266 void
  267 countpagerefs(ulong*, int)
  268 {
  269 }
  270 
  271 /*
  272  * Return the number of bytes that can be accessed via KADDR(pa).
  273  * If pa is not a valid argument to KADDR, return 0.
  274  */
  275 ulong
  276 cankaddr(ulong pa)
  277 {
  278         if(pa >= -KZERO)
  279                 return 0;
  280         return -KZERO - pa;
  281 }
  282 

Cache object: e6e839fb6a09d7915ed461180de3b1e9


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