support x2lapic as it might be turned on and it is a tiny bit faster. Reference: /n/atom/patch/applied/x2lapic Date: Thu Sep 17 05:18:38 CES 2015 Signed-off-by: quanstro@quanstro.net --- /sys/src/nix/k10/lapic.c Thu Sep 17 05:18:16 2015 +++ /sys/src/nix/k10/lapic.c Thu Sep 17 05:18:17 2015 @@ -71,8 +71,17 @@ DivX1 = 0x0000000b, /* Divide by 1 */ }; +enum { + Lapicbase = 0x1b, /* apic base msr */ + Xbp = 1<<8, /* boot processor */ + Xen = 1<<10, /* enable xapic */ + Xextd = 1<<11, /* enable x2apic */ + X2en = Xen|Xextd, +}; + static u32int* lapicbase; static int lapmachno = 1; +static int hasx2apic; static Lapic xlapic[Napic]; @@ -89,16 +98,51 @@ return nil; } -static u32int +static u64int lapicrget(int r) { - return lapicbase[r/4]; + if(hasx2apic) + return rdmsr(0x800 + r/16); + else + return lapicbase[r/4]; } static void -lapicrput(int r, u32int data) +lapicrput(int r, u64int data) +{ + if(hasx2apic) + wrmsr(0x800 + r/16, data); + else + lapicbase[r/4] = data; +} + +static u32int +r2id(u32int r) { - lapicbase[r/4] = data; + if(hasx2apic) + return r; + else + return r>>24; +} + +static u64int +id2r(u32int r) +{ + if(hasx2apic) + return r; + else + return r<<24; +} + +static void +lapicputic(u64int v) +{ + if(hasx2apic) + lapicrput(Iclo, v); + else{ + lapicrput(Ichi, v>>32); + lapicrput(Iclo, v); + } } int @@ -147,34 +191,73 @@ return r; } +static int +x2conf(void) +{ + char *s; + + s = getconf("*x2lapic"); + if(s != nil && strtol(s, nil, 0) != 0) + return 0; + return -1; +} + +static void +enablex2apic(void) +{ + u64int r; + r = rdmsr(0x1b); + if((r & 3<<10) != 3<<10) + wrmsr(0x1b, r | 3<<10); +} + +/* support in cpuid:ax=1 -> cx:21 */ +static void +probe(int lapicno, uintmem pa) +{ + u64int r; + + r = rdmsr(Lapicbase); + if((r & X2en) == X2en){ + print("lapic: probe: x2lapic enabled\n"); + hasx2apic = 1; + }else if(lapicno >= 255 || x2conf() == 0){ + print("lapic: probe: enable x2lapic\n"); + hasx2apic = 1; + wrmsr(Lapicbase, r | X2en); + }else{ + adrmapck(pa, 1024, Ammio, Mfree, Cnone); + if((lapicbase = vmap(pa, 1024)) == nil) + panic("lapicinit%d: can't map lapicbase %#P", lapicno, pa); + } +} + void lapicinit(int lapicno, uintmem pa, int isbp) { Lapic *apic; + static int once; /* * Mark the LAPIC useable if it has a good ID, and the registers can - * be mapped. There is x2LAPIC to be dealt with at some point. + * be mapped. */ DBG("lapicinit: lapicno %d pa %#P isbp %d caller %#p\n", lapicno, pa, isbp, getcallerpc(&lapicno)); - addarchfile("lapic", 0444, lapicread, nil); + if(once == 0){ + once = 1; + probe(lapicno, pa); + addarchfile("lapic", 0444, lapicread, nil); + DBG("lapicinit%d: lapicbase %#P -> %#p\n", lapicno, pa, lapicbase); + } if(lapicno >= Napic){ - panic("lapicinit%d: out of range", lapicno); + panic("lapicinit: %d: out of range", lapicno); return; } if((apic = &xlapic[lapicno])->useable){ print("lapicinit%d: already initialised\n", lapicno); return; } - if(lapicbase == nil){ - adrmapck(pa, 1024, Ammio, Mfree, Cnone); - if((lapicbase = vmap(pa, 1024)) == nil){ - panic("lapicinit%d: can't map lapicbase %#P", lapicno, pa); - return; - } - DBG("lapicinit%d: lapicbase %#P -> %#p\n", lapicno, pa, lapicbase); - } apic->useable = 1; /* @@ -219,9 +302,9 @@ return; DBG("lapic%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", + DBG(" tslvt %#.16llux pclvt %#.16llux elvt %#.16llux\n", lapicrget(Tslvt), lapicrget(Pclvt), lapicrget(Elvt)); - DBG(" tlvt %#8.8ux lint0 %#8.8ux lint1 %#8.8ux siv %#8.8ux\n", + DBG(" tlvt %#.16llux lint0 %#.16llux lint1 %#.16llux siv %#.16llux\n", lapicrget(Tlvt), lapicrget(Lint0), lapicrget(Lint1), lapicrget(Siv)); } @@ -244,19 +327,19 @@ { Lapic *apic; u64int tsc; - u32int dfr, ver; + u32int ver; int apicno, nlvt; - if(lapicbase == nil) + if(hasx2apic) + enablex2apic(); + else if(lapicbase == nil) panic("lapiconline: no lapic base"); - if((apicno = ((lapicrget(Id)>>24) & 0xff)) >= Napic) + if((apicno = r2id(lapicrget(Id))) >= Napic) panic("lapic: id too large %d", apicno); if(apicno != m->apicno){ panic("lapic: %d != %d", m->apicno, apicno); - dfr = lapicrget(Id) & ~(0xff<<24); - dfr |= m->apicno<<24; - lapicrput(Id, dfr); + lapicrput(Id, m->apicno); apicno = m->apicno; } apic = &xlapic[apicno]; @@ -280,17 +363,6 @@ apic->ver = ver & 0xff; /* - * These don't really matter in Physical mode; - * set the defaults anyway. - */ -// if(memcmp(m->cpuinfo, "AuthenticAMD", 12) == 0) -// dfr = 0xf0000000; -// else - dfr = 0xffffffff; - lapicrput(Df, dfr); - lapicrput(Ld, 0x00000000); - - /* * Disable interrupts until ready by setting the Task Priority * register to 0xff. */ @@ -399,34 +471,30 @@ lapicsipi(int lapicno, uintmem pa) { int i; - u32int crhi, crlo; + u32int crlo; + u64int rid; /* * SIPI - Start-up IPI. - * To do: checks on lapic validity. */ - crhi = lapicno<<24; - lapicrput(Ichi, crhi); - lapicrput(Iclo, DSnone|TMlevel|Lassert|MTir); + rid = id2r(lapicno)<<32; + lapicputic(rid|DSnone|TMlevel|Lassert|MTir); microdelay(200); - lapicrput(Iclo, DSnone|TMlevel|MTir); + lapicputic(rid|DSnone|TMlevel|MTir); delay(10); crlo = DSnone|TMedge|MTsipi|((u32int)pa/(4*KiB)); for(i = 0; i < 2; i++){ - lapicrput(Ichi, crhi); - lapicrput(Iclo, crlo); + lapicputic(rid|crlo); microdelay(200); } } - void lapicipi(int lapicno) { - lapicrput(Ichi, lapicno<<24); - lapicrput(Iclo, DSnone|TMedge|Lassert|MTf|IdtIPI); + lapicputic(id2r(lapicno)<<32|DSnone|TMedge|Lassert|MTf|IdtIPI); while(lapicrget(Iclo) & Ds) - ; + pause(); } void