# HG changeset patch # User Erik Quanstrom # Date 1322669986 -3600 # Node ID 789f76abad99ca2d9d9f6f8f76456b0bc3b3fb2b # Parent 3e33bfb8d2f26ab23786c87cfbdea86fc15ae72c apic: allow overlapping lapic and iopaic ids it is common for modern systems to have overlapping ioapic and lapic ids. such systems can't boot unless we seperate the lapic and ioapic namespaces. R=nixiedev, nemo, quanstro CC=nix-dev http://codereview.appspot.com/5434085 Committer: Noah Evans diff -r 3e33bfb8d2f2 -r 789f76abad99 sys/src/nix/k10/apic.c --- a/sys/src/nix/k10/apic.c Wed Nov 30 12:55:02 2011 +0100 +++ b/sys/src/nix/k10/apic.c Wed Nov 30 17:19:46 2011 +0100 @@ -73,6 +73,9 @@ static u8int* apicbase; static int apmachno = 1; +Apic xlapic[Napic]; +Mach *xlapicmachptr[Napic]; /* maintained, but unused */ + static u32int apicrget(int r) { @@ -121,7 +124,7 @@ print("apicinit%d: out of range\n", apicno); return; } - if((apic = &xapic[apicno])->useable){ + if((apic = &xlapic[apicno])->useable){ print("apicinit%d: already initialised\n", apicno); return; } @@ -147,28 +150,33 @@ apic->machno = apmachno++; } +static void +apicdump0(Apic *apic, int i) +{ + if(!apic->useable || apic->addr != 0) + return; + DBG("apic%d: machno %d lint0 %#8.8ux lint1 %#8.8ux\n", + i, apic->machno, apic->lvt[0], apic->lvt[1]); + DBG(" tslvt %#8.8ux pclvt %#8.8ux elvt %#8.8ux\n", + apicrget(Tslvt), apicrget(Pclvt), apicrget(Elvt)); + DBG(" tlvt %#8.8ux lint0 %#8.8ux lint1 %#8.8ux siv %#8.8ux\n", + apicrget(Tlvt), apicrget(Lint0), + apicrget(Lint1), apicrget(Siv)); +} + void apicdump(void) { int i; - Apic *apic; if(!DBGFLG) return; DBG("apicbase %#p apmachno %d\n", apicbase, apmachno); - for(i = 0; i < Napic; i++){ - apic = &xapic[i]; - if(!apic->useable || apic->addr != 0) - continue; - DBG("apic%d: machno %d lint0 %#8.8ux lint1 %#8.8ux\n", - i, apic->machno, apic->lvt[0], apic->lvt[1]); - DBG(" tslvt %#8.8ux pclvt %#8.8ux elvt %#8.8ux\n", - apicrget(Tslvt), apicrget(Pclvt), apicrget(Elvt)); - DBG(" tlvt %#8.8ux lint0 %#8.8ux lint1 %#8.8ux siv %#8.8ux\n", - apicrget(Tlvt), apicrget(Lint0), - apicrget(Lint1), apicrget(Siv)); - } + for(i = 0; i < Napic; i++) + apicdump0(xlapic + i, i); + for(i = 0; i < Napic; i++) + apicdump0(xioapic + i, i); } static void @@ -189,7 +197,7 @@ return 0; if((apicno = ((apicrget(Id)>>24) & 0xff)) >= Napic) return 0; - apic = &xapic[apicno]; + apic = &xlapic[apicno]; if(!apic->useable || apic->addr != nil) return 0; @@ -200,7 +208,7 @@ */ ver = apicrget(Ver); nlvt = ((ver>>16) & 0xff) + 1; - if(nlvt > nelem(apic->lvt)){ + if(nlvt-1 > nelem(apic->lvt)){ print("apicinit%d: nlvt %d > max (%d)\n", apicno, nlvt-1, nelem(apic->lvt)); nlvt = nelem(apic->lvt); @@ -309,7 +317,7 @@ if(m->machno == 0) apicrput(Tp, 0); - xapicmachptr[apicno] = sys->machptr[m->machno]; + xlapicmachptr[apicno] = sys->machptr[m->machno]; return 1; } @@ -321,7 +329,7 @@ Apic *apic; vlong period; - apic = &xapic[(apicrget(Id)>>24) & 0xff]; + apic = &xlapic[(apicrget(Id)>>24) & 0xff]; pl = splhi(); lock(&m->apictimerlock); diff -r 3e33bfb8d2f2 -r 789f76abad99 sys/src/nix/k10/apic.h --- a/sys/src/nix/k10/apic.h Wed Nov 30 12:55:02 2011 +0100 +++ b/sys/src/nix/k10/apic.h Wed Nov 30 17:19:46 2011 +0100 @@ -1,18 +1,24 @@ /* * There are 2 flavours of APIC, Local APIC and IOAPIC, - * which share one APIC ID space. Each I/O APIC has a unique address, - * Local APICs are all at the same address as they can only be - * accessed by the local CPU. + * Each I/O APIC has a unique physical address, + * Local APICs are all at the same physical address as they can only be + * accessed by the local CPU. APIC ids are unique to the + * APIC type, so an IOAPIC and APIC both with id 0 is ok. */ -typedef struct { - int useable; /* en */ +typedef struct Ioapic Ioapic; +typedef struct Lapic Lapic; +typedef struct Apic Apic; +struct Ioapic { Lock; /* IOAPIC: register access */ u32int* addr; /* IOAPIC: register base */ int nrdt; /* IOAPIC: size of RDT */ int gsib; /* IOAPIC: global RDT index */ +}; +struct Lapic { int machno; /* APIC */ + u32int lvt[6]; int nlvt; int ver; @@ -21,7 +27,13 @@ vlong max; vlong min; vlong div; -} Apic; +}; + +struct Apic { + int useable; /* en */ + Ioapic; + Lapic; +}; enum { Nbus = 32, @@ -64,8 +76,9 @@ Im = 0x00010000, /* Interrupt Mask */ }; -Apic xapic[Napic]; -Mach* xapicmachptr[Napic]; /* maintained, but unused */ +extern Apic xlapic[Napic]; +extern Apic xioapic[Napic]; +extern Mach *xlapicmachptr[Napic]; /* maintained, but unused */ #define l16get(p) (((p)[1]<<8)|(p)[0]) #define l32get(p) (((u32int)l16get(p+2)<<16)|l16get(p)) diff -r 3e33bfb8d2f2 -r 789f76abad99 sys/src/nix/k10/ioapic.c --- a/sys/src/nix/k10/ioapic.c Wed Nov 30 12:55:02 2011 +0100 +++ b/sys/src/nix/k10/ioapic.c Wed Nov 30 17:19:46 2011 +0100 @@ -40,6 +40,8 @@ static Lock idtnolock; static int idtno = IdtIOAPIC; +Apic xioapic[Napic]; + static void rtblget(Apic* apic, int sel, u32int* hi, u32int* lo) { @@ -76,7 +78,7 @@ if(busno >= Nbus || apicno >= Napic || nrdtarray >= Nrdt) return; - apic = &xapic[apicno]; + apic = &xioapic[apicno]; if(!apic->useable || intin >= apic->nrdt) return; @@ -101,7 +103,7 @@ if(id >= Napic) return; - apic = &xapic[id]; + apic = &xioapic[id]; if(apic->useable || (apic->addr = vmap(pa, 1024)) == nil) return; apic->useable = 1; @@ -134,7 +136,7 @@ return; for(i = 0; i < Napic; i++){ - apic = &xapic[i]; + apic = &xioapic[i]; if(!apic->useable || apic->addr == 0) continue; DBG("ioapic %d addr %#p nrdt %d gsib %d\n", @@ -152,7 +154,7 @@ DBG("iointr bus %d:\n", i); while(rdt != nil){ DBG(" apic %ld devno %#ux (%d %d) intin %d lo %#ux\n", - rdt->apic-xapic, rdt->devno, rdt->devno>>2, + rdt->apic-xioapic, rdt->devno, rdt->devno>>2, rdt->devno & 0x03, rdt->intin, rdt->lo); rdt = rdt->next; } @@ -165,7 +167,7 @@ int i; Apic *apic; - for(apic = xapic; apic < &xapic[Napic]; apic++){ + for(apic = xioapic; apic < &xioapic[Napic]; apic++){ if(!apic->useable || apic->addr == nil) continue; for(i = 0; i < apic->nrdt; i++){ @@ -181,7 +183,7 @@ static void ioapicintrdd(u32int* hi, u32int* lo) { - int i; + static int i; /* * Set delivery mode (lo) and destination field (hi), @@ -204,16 +206,14 @@ * to more than one thread in a core, or to use a "noise" core. * But, as usual, Intel make that an onerous task. */ - /* we are routing all to zero. Sorry Jim [It was Ron's idea]*/ - for(i = 0;;i++){ - if(!xapic[i].useable || xapic[i].addr != 0) + for(;; i = (i+1) % nelem(xlapic)){ + if(!xlapic[i].useable) continue; - if(sys->machptr[xapic[i].machno] == nil) + if(sys->machptr[xlapic[i].machno] == nil) continue; - if(sys->machptr[xapic[i].machno]->online != 0) + if(sys->machptr[xlapic[i].machno]->online != 0) break; } - *hi = i<<24; *lo |= Pm|MTf; } diff -r 3e33bfb8d2f2 -r 789f76abad99 sys/src/nix/k10/mp.c --- a/sys/src/nix/k10/mp.c Wed Nov 30 12:55:02 2011 +0100 +++ b/sys/src/nix/k10/mp.c Wed Nov 30 17:19:46 2011 +0100 @@ -88,22 +88,27 @@ mpintrprint("APIC ID out of range", p); return 0; } - apic = &xapic[p[6]]; - if(!apic->useable){ - mpintrprint("unuseable APIC", p); - return 0; - } switch(p[0]){ default: mpintrprint("INTIN botch", p); return 0; case 3: /* IOINTR */ + apic = &xioapic[p[6]]; + if(!apic->useable){ + mpintrprint("unuseable ioapic", p); + return 0; + } if(p[7] >= apic->nrdt){ mpintrprint("IO INTIN out of range", p); return 0; } break; case 4: /* LINTR */ + apic = &xlapic[p[6]]; + if(!apic->useable){ + mpintrprint("unuseable lapic", p); + return 0; + } if(p[7] >= nelem(apic->lvt)){ mpintrprint("LOCAL INTIN out of range", p); return 0; @@ -295,13 +300,13 @@ */ if(p[6] == 0xff){ for(i = 0; i < Napic; i++){ - if(!xapic[i].useable || xapic[i].addr != nil) + if(!xlapic[i].useable || xlapic[i].addr != nil) continue; - xapic[i].lvt[p[7]] = lo; + xlapic[i].lvt[p[7]] = lo; } } else - xapic[p[6]].lvt[p[7]] = lo; + xlapic[p[6]].lvt[p[7]] = lo; p += 8; break; } diff -r 3e33bfb8d2f2 -r 789f76abad99 sys/src/nix/k10/sipi.c --- a/sys/src/nix/k10/sipi.c Wed Nov 30 12:55:02 2011 +0100 +++ b/sys/src/nix/k10/sipi.c Wed Nov 30 17:19:46 2011 +0100 @@ -40,7 +40,7 @@ * with any unused space elided. */ for(apicno = 0; apicno < Napic; apicno++){ - apic = &xapic[apicno]; + apic = &xlapic[apicno]; if(!apic->useable || apic->addr || apic->machno == 0) continue;