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/pc/mtrr.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 typedef struct Mtrreg Mtrreg;
    9 typedef struct Mtrrop Mtrrop;
   10 
   11 enum {
   12         /*
   13          * MTRR Physical base/mask are indexed by
   14          *      MTRRPhys{Base|Mask}N = MTRRPhys{Base|Mask}0 + 2*i
   15          */
   16         MTRRPhysBase0 = 0x200,
   17         MTRRPhysMask0 = 0x201,
   18         MTRRDefaultType = 0x2FF,
   19         MTRRCap = 0xFE,
   20 
   21         /* cpuid extended function codes */
   22         Exthighfunc = 1ul << 31,
   23         Extprocsigamd,
   24         Extprocname0,
   25         Extprocname1,
   26         Extprocname2,
   27         Exttlbl1,
   28         Extl2,
   29         Extapm,
   30         Extaddrsz,
   31 };
   32 
   33 enum {
   34         CR4PageGlobalEnable     = 1 << 7,
   35         CR0CacheDisable         = 1 << 30,
   36 };
   37 
   38 enum {
   39         Uncacheable     = 0,
   40         Writecomb       = 1,
   41         Unknown1        = 2,
   42         Unknown2        = 3,
   43         Writethru       = 4,
   44         Writeprot       = 5,
   45         Writeback       = 6,
   46 };
   47 
   48 enum {
   49         Capvcnt = 0xff,         /* mask: # of variable-range MTRRs we have */
   50         Capwc   = 1<<8,         /* flag: have write combining? */
   51         Capfix  = 1<<10,        /* flag: have fixed MTRRs? */
   52         Deftype = 0xff,         /* default MTRR type */
   53         Deffixena = 1<<10,      /* fixed-range MTRR enable */
   54         Defena  = 1<<11,        /* MTRR enable */
   55 };
   56 
   57 struct Mtrreg {
   58         vlong   base;
   59         vlong   mask;
   60 };
   61 struct Mtrrop {
   62         Mtrreg  *reg;
   63         int     slot;
   64 };
   65 
   66 static char *types[] = {
   67 [Uncacheable]   "uc",
   68 [Writecomb]     "wc",
   69 [Unknown1]      "uk1",
   70 [Unknown2]      "uk2",
   71 [Writethru]     "wt",
   72 [Writeprot]     "wp",
   73 [Writeback]     "wb",
   74                 nil
   75 };
   76 
   77 static char *
   78 type2str(int type)
   79 {
   80         if(type < 0 || type >= nelem(types))
   81                 return nil;
   82         return types[type];
   83 }
   84 
   85 static int
   86 str2type(char *str)
   87 {
   88         char **p;
   89 
   90         for(p = types; *p != nil; p++)
   91                 if (strcmp(str, *p) == 0)
   92                         return p - types;
   93         return -1;
   94 }
   95 
   96 static vlong
   97 physmask(void)
   98 {
   99         ulong regs[4];
  100 
  101         cpuid(Exthighfunc, regs);
  102         if(regs[0] < Extaddrsz)                 /* ax */
  103                 return (1ULL << 36) - 1;        /* cpu does not tell */
  104 
  105         cpuid(Extaddrsz, regs);
  106         return (1LL << (regs[0] & 0xFF)) - 1;   /* ax */
  107 }
  108 
  109 static int
  110 overlap(uintptr b1, long s1, uintptr b2, long s2)
  111 {
  112         if(b1 > b2)
  113                 return overlap(b2, s2, b1, s1);
  114         if(b1 + s1 > b2)
  115                 return 1;
  116         return 0;
  117 }
  118 
  119 static int
  120 ispow2(ulong ul)
  121 {
  122         return (ul & (ul - 1)) == 0;
  123 }
  124 
  125 static void
  126 mtrrdec(Mtrreg *mtrr, uintptr *ptr, long *size, int *type, int *ok)
  127 {
  128         if(ptr != nil)
  129                 *ptr = mtrr->base & ~(BY2PG-1);
  130         if(type != nil)
  131                 *type = mtrr->base & 0xff;
  132         if(size != nil)
  133                 *size = (physmask() ^ (mtrr->mask & ~(BY2PG-1))) + 1;
  134         if(ok != nil)
  135                 *ok = (mtrr->mask >> 11) & 1;
  136 }
  137 
  138 static void
  139 mtrrenc(Mtrreg *mtrr, uintptr ptr, long size, int type, int ok)
  140 {
  141         mtrr->base = ptr | (type & 0xff);
  142         mtrr->mask = (physmask() & ~(size - 1)) | (ok? 1<<11: 0);
  143 }
  144 
  145 /*
  146  * i is the index of the MTRR, and is multiplied by 2 because
  147  * mask and base offsets are interleaved.
  148  */
  149 static void
  150 mtrrget(Mtrreg *mtrr, int i)
  151 {
  152         rdmsr(MTRRPhysBase0 + 2*i, &mtrr->base);
  153         rdmsr(MTRRPhysMask0 + 2*i, &mtrr->mask);
  154 }
  155 
  156 static void
  157 mtrrput(Mtrreg *mtrr, int i)
  158 {
  159         wrmsr(MTRRPhysBase0 + 2*i, mtrr->base);
  160         wrmsr(MTRRPhysMask0 + 2*i, mtrr->mask);
  161 }
  162 
  163 static void
  164 mtrrop(Mtrrop **op)
  165 {
  166         int s;
  167         ulong cr0, cr4;
  168         vlong def;
  169         static long bar1, bar2;
  170 
  171         s = splhi();            /* avoid race with mtrrclock */
  172 
  173 // iprint("cpu%d enter mtrrop\n", m->machno);
  174 
  175         /*
  176          * wait for all CPUs to sync here, so that the MTRR setup gets
  177          * done at roughly the same time on all processors.
  178          */
  179         _xinc(&bar1);
  180         while(bar1 < conf.nmach)
  181                 microdelay(10);
  182 
  183         cr4 = getcr4();
  184         putcr4(cr4 & ~CR4PageGlobalEnable);
  185         cr0 = getcr0();
  186         wbinvd();
  187         putcr0(cr0 | CR0CacheDisable);
  188         wbinvd();
  189         rdmsr(MTRRDefaultType, &def);
  190         wrmsr(MTRRDefaultType, def & ~(vlong)Defena);
  191 
  192         mtrrput((*op)->reg, (*op)->slot);
  193 
  194         wbinvd();
  195         wrmsr(MTRRDefaultType, def);
  196         putcr0(cr0);
  197         putcr4(cr4);
  198 
  199         /*
  200          * wait for all CPUs to sync up again, so that we don't continue
  201          * executing while the MTRRs are still being set up.
  202          */
  203         _xinc(&bar2);
  204         while(bar2 < conf.nmach)
  205                 microdelay(10);
  206         *op = nil;
  207         _xdec(&bar1);
  208         while(bar1 > 0)
  209                 microdelay(10);
  210         _xdec(&bar2);
  211         splx(s);
  212 }
  213 
  214 static Mtrrop *postedop;
  215 
  216 void
  217 mtrrclock(void)                         /* called from clock interrupt */
  218 {
  219         if(postedop != nil)
  220                 mtrrop(&postedop);
  221 }
  222 
  223 int
  224 mtrr(uintptr base, long size, char *tstr)
  225 {
  226         int i, vcnt, slot, type;
  227         vlong def, cap;
  228         Mtrreg entry;
  229         Mtrrop op;
  230         static int tickreg;
  231         static QLock mtrrlk;
  232 
  233         if(!(m->cpuiddx & Mtrr))
  234                 error("mtrr not supported");
  235         if(base & (BY2PG-1) || size & (BY2PG-1) || size <= 0)
  236                 error("mtrr base or size not 4k aligned or size <= 0");
  237         if(base + size < base)
  238                 error("mtrr range exceeds 4G");
  239         if(!ispow2(size))
  240                 error("mtrr size not power of 2");
  241         if(base & (size - 1))
  242                 error("mtrr base not naturally aligned");
  243 
  244         if((type = str2type(tstr)) == -1)
  245                 error("mtrr bad type");
  246 
  247         rdmsr(MTRRCap, &cap);
  248         rdmsr(MTRRDefaultType, &def);
  249 
  250         switch(type){
  251         default:
  252                 error("mtrr unknown type");
  253                 break;
  254         case Writecomb:
  255                 if(!(cap & Capwc))
  256                         error("mtrr type wc (write combining) unsupported");
  257                 /* fallthrough */
  258         case Uncacheable:
  259         case Writethru:
  260         case Writeprot:
  261         case Writeback:
  262                 break;
  263         }
  264 
  265         slot = -1;
  266         vcnt = cap & Capvcnt;
  267         for(i = 0; i < vcnt; i++){
  268                 int mtype, mok;
  269                 long msize;
  270                 uintptr mp;
  271                 Mtrreg mtrr;
  272 
  273                 mtrrget(&mtrr, i);
  274                 mtrrdec(&mtrr, &mp, &msize, &mtype, &mok);
  275                 if(!mok)
  276                         slot = i;
  277                 else if(mp == base && msize == size){
  278                         slot = i;
  279                         break;
  280                 }
  281                 if(mok && overlap(mp, msize, base, size))
  282                         error("mtrr range overlaps existing definition");
  283         }
  284         if(slot == -1)
  285                 error("no free mtrr slots");
  286         qlock(&mtrrlk);
  287         mtrrenc(&entry, base, size, type, 1);
  288         op.reg = &entry;
  289         op.slot = slot;
  290         postedop = &op;
  291         mtrrop(&postedop);
  292         qunlock(&mtrrlk);
  293         return 0;
  294 }
  295 
  296 int
  297 mtrrprint(char *buf, long bufsize)
  298 {
  299         int i, vcnt;
  300         long n;
  301         vlong cap, def;
  302         Mtrreg mtrr;
  303 
  304         n = 0;
  305         if(!(m->cpuiddx & Mtrr))
  306                 return 0;
  307         rdmsr(MTRRCap, &cap);
  308         rdmsr(MTRRDefaultType, &def);
  309         n += snprint(buf+n, bufsize-n, "cache default %s\n",
  310                 type2str(def & Deftype));
  311         vcnt = cap & Capvcnt;
  312         for(i = 0; i < vcnt; i++){
  313                 int type, ok;
  314                 long size;
  315                 uintptr base;
  316 
  317                 mtrrget(&mtrr, i);
  318                 mtrrdec(&mtrr, &base, &size, &type, &ok);
  319                 if(ok)
  320                         n += snprint(buf+n, bufsize-n, "cache 0x%lux %lud %s\n",
  321                                 base, size, type2str(type));
  322         }
  323         return n;
  324 }

Cache object: 44b1b08a9e1727284d1eda5b8ccf4270


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