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