Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/9/pc/mtrr.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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