FreeBSD/Linux Kernel Cross Reference
sys/pc/mtrr.c
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
|