Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * minimal acpi support for multiprocessors.
3
 *
4
 * avoids AML but that's only enough to discover
5
 * the processors, not the interrupt routing details.
6
 */
7
#include "u.h"
8
#include "../port/lib.h"
9
#include "mem.h"
10
#include "dat.h"
11
#include "fns.h"
12
#include "io.h"
13
#include "mp.h"
14
#include "mpacpi.h"
15
 
16
/* 8c says: out of fixed registers */
17
#define L64GET(p)	((uvlong)L32GET((p)+4) << 32 | L32GET(p))
18
 
19
enum {
20
	/* apic types */
21
	Apiclproc,
22
	Apicio,
23
	Apicintrsrcoverride,
24
	Apicnmisrc,
25
	Apiclnmi,
26
	Apicladdroverride,
27
	Apicios,
28
	Apicls,
29
	Apicintrsrc,
30
	Apiclx2,
31
	Apiclx2nmi,
32
 
33
	PcmpUsed = 1ul<<31,		/* Apic->flags addition */
34
 
35
	Lapicbase = 0x1b,		/* msr */
36
 
37
	Lapicae	= 1<<11,		/* apic enable in Lapicbase */
38
};
39
 
40
#define dprint(...)	if(mpdebug) print(__VA_ARGS__); else USED(mpdebug)
41
 
42
/* from mp.c */
43
int	mpdebug;
44
int	mpmachno;
45
Apic	mpapic[MaxAPICNO+1];
46
int	machno2apicno[MaxAPICNO+1];	/* inverse map: machno -> APIC ID */
47
 
48
Apic	*bootapic;
49
 
50
static int nprocid;
51
 
52
static uvlong
53
l64get(uchar *p)
54
{
55
	return L64GET(p);
56
}
57
 
58
int
59
apicset(Apic *apic, int type, int apicno, int f)
60
{
61
	if(apicno > MaxAPICNO)
62
		return -1;
63
	apic->type = type;
64
	apic->apicno = apicno;
65
	apic->flags = f | PcmpEN | PcmpUsed;
66
	return 0;
67
}
68
 
69
int
70
mpnewproc(Apic *apic, int apicno, int f)
71
{
72
	if(apic->flags & PcmpUsed) {
73
		print("mpnewproc: apic already enabled\n");
74
		return -1;
75
	}
76
	if (apicset(apic, PcmpPROCESSOR, apicno, f) < 0)
77
		return -1;
78
	apic->lintr[1] = apic->lintr[0] = ApicIMASK;
79
	/* botch! just enumerate */
80
	if(apic->flags & PcmpBP)
81
		apic->machno = 0;
82
	else
83
		apic->machno = ++mpmachno;
84
	machno2apicno[apic->machno] = apicno;
85
	return 0;
86
}
87
 
88
static int
89
mpacpiproc(uchar *p, ulong laddr)
90
{
91
	int id, f;
92
	ulong *vladdr;
93
	vlong base;
94
	char *already;
95
	Apic *apic;
96
 
97
	/* p bytes: type (0), len (8), cpuid, cpu_lapic id, flags[4] */
98
	id = p[3];
99
	/* cpu unusable flag or id out of range? */
100
	if((L32GET(p+4) & 1) == 0 || id > MaxAPICNO)
101
		return -1;
102
 
103
	vladdr = nil;
104
	already = "";
105
	f = 0;
106
	apic = &mpapic[id];
107
	dprint("\tmpacpiproc: apic %#p\n", apic);
108
	apic->paddr = laddr;
109
	if (nprocid++ == 0) {
110
		f = PcmpBP;
111
		vladdr = vmap(apic->paddr, 1024);
112
		if(apic->addr == nil){
113
			print("proc apic %d: failed to map %#p\n", id,
114
				apic->paddr);
115
			already = "(fail)";
116
		}
117
		bootapic = apic;
118
	}
119
	apic->addr = vladdr;
120
 
121
	if(apic->flags & PcmpUsed)
122
		already = "(on)";
123
	else
124
		mpnewproc(apic, id, f);
125
 
126
	if (0)
127
		dprint("\tapic proc %d/%d apicid %d flags%s%s %s\n", nprocid-1,
128
			apic->machno, id, f & PcmpBP? " boot": "",
129
			f & PcmpEN? " enabled": "", already);
130
	USED(already);
131
 
132
	rdmsr(Lapicbase, &base);
133
	if (!(base & Lapicae)) {
134
		dprint("mpacpiproc: enabling lapic\n");
135
		wrmsr(Lapicbase, base | Lapicae);
136
	}
137
	return 0;
138
}
139
 
140
static void
141
mpacpicpus(Madt *madt)
142
{
143
	int i, n;
144
	ulong laddr;
145
	uchar *p;
146
 
147
	laddr = L32GET(madt->addr);
148
	dprint("APIC mpacpicpus(%#p) lapic addr %#lux, flags %#ux\n",
149
		madt, laddr, L32GET(madt->flags));
150
 
151
	n = L32GET(&madt->sdthdr[4]);
152
	p = madt->structures;
153
	dprint("\t%d structures at %#p\n",n, p);
154
	/* byte 0 is assumed to be type, 1 is assumed to be length */
155
	for(i = offsetof(Madt, structures[0]); i < n; i += p[1], p += p[1])
156
		switch(p[0]){
157
		case Apiclproc:
158
			mpacpiproc(p, laddr);
159
			break;
160
		}
161
}
162
 
163
/* returns nil iff checksum is bad */
164
static void *
165
mpacpirsdchecksum(void* addr, int length)
166
{
167
	uchar *p, sum;
168
 
169
	sum = 0;
170
	for(p = addr; length-- > 0; p++)
171
		sum += *p;
172
	return sum == 0? addr: nil;
173
}
174
 
175
/* call func for each acpi table found */
176
static void
177
mpacpiscan(void (*func)(uchar *))
178
{
179
	int asize, i, tbllen, sdtlen;
180
	uintptr dhpa, sdtpa;
181
	uchar *tbl, *sdt;
182
	Rsd *rsd;
183
 
184
	dprint("ACPI...");
185
	if((rsd = sigsearch("RSD PTR ")) == nil) {
186
		dprint("none\n");
187
		return;
188
	}
189
 
190
	dprint("rsd %#p physaddr %#ux length %ud %#llux rev %d oem %.6s\n",
191
		rsd, L32GET(rsd->raddr), L32GET(rsd->length),
192
		l64get(rsd->xaddr), rsd->revision, (char*)rsd->oemid);
193
 
194
	if(rsd->revision == 2){
195
		if(mpacpirsdchecksum(rsd, 36) == nil)
196
			return;
197
		asize = 8;
198
		sdtpa = l64get(rsd->xaddr);
199
	} else {
200
		if(mpacpirsdchecksum(rsd, 20) == nil)
201
			return;
202
		asize = 4;
203
		sdtpa = L32GET(rsd->raddr);
204
	}
205
 
206
	if((sdt = vmap(sdtpa, 8)) == nil)
207
		return;
208
	if((sdt[0] != 'R' && sdt[0] != 'X') || memcmp(sdt+1, "SDT", 3) != 0){
209
		vunmap(sdt, 8);
210
		return;
211
	}
212
	sdtlen = L32GET(sdt + 4);
213
	vunmap(sdt, 8);
214
 
215
	if((sdt = vmap(sdtpa, sdtlen)) == nil)
216
		return;
217
	if(mpacpirsdchecksum(sdt, sdtlen) != nil)
218
		for(i = 36; i < sdtlen; i += asize){
219
			if(asize == 8)
220
				dhpa = l64get(sdt+i);
221
			else
222
				dhpa = L32GET(sdt+i);
223
 
224
			if((tbl = vmap(dhpa, 8)) == nil)
225
				continue;
226
			tbllen = L32GET(tbl + 4);
227
			vunmap(tbl, 8);
228
 
229
			if((tbl = vmap(dhpa, tbllen)) == nil)
230
				continue;
231
			if(mpacpirsdchecksum(tbl, tbllen) != nil)
232
				(*func)(tbl);
233
			vunmap(tbl, tbllen);
234
		}
235
	vunmap(sdt, sdtlen);
236
}
237
 
238
static void
239
mpacpitbl(uchar *p)
240
{
241
	/* for now, just activate any idle cpus */
242
	if (memcmp(p, "APIC", 4) == 0)
243
		mpacpicpus((Madt *)p);
244
}
245
 
246
static void
247
mpacpi(void)
248
{
249
	mpdebug = getconf("*debugmp") != nil;
250
	mpacpiscan(mpacpitbl);
251
}
252
 
253
void	(*mpacpifunc)(void) = mpacpi;