Date: Fri, 14 Nov 1997 17:12:15 -0600 From: Jonathan Lemon <jlemon@americantv.com> To: hackers@freebsd.org Subject: FreeBSD Pentium Bug fix (proposed) Message-ID: <19971114171214.44521@right.PCS>
next in thread | raw e-mail | index | archive | help
Alright, I've been watching the debate about the LOCK CMPXCHG8 bug, and decided to take a crack at it. While I believe that for the most case, this is probably just a tempest in a teapot, for some, it probably represents a serious DOS that should be addressed. IMHO, the "take page fault on any trapno < 7" solution is a very ugly hack, but it got me thinking about a better way to solve this. The solution seems to depend on the fact that a page fault has a higher priority than an illegal instruction fault, and thus, if both are posted first, then the page fault takes precedence. This made me think that there might be other faults that also have higher precedence than the illegal instruction fault, and which could be localized to just the #UD handler. It turns out that exceeding the segment limit is one of them. My ``fix'' is to have the IDT descriptor reference a segemnt which has a length of 0. This has the effect of mapping SIGILL into SIGBUS, so that the `cmpxchg8' crash now generates a Bus error. (I didn't bother returning the correct signal; it can probably be added if it is important) This fix works on my machine, takes no overhead, and the only breaks BDE_DEBUGGER, which wants to hoard all the GDT entries for itself. :-) I'd appreciate it if interested parties could try this out and see if it also fixes the problem on other machines. -- Jonathan --------------------------------- cut here --------------------------------- Index: machdep.c =================================================================== RCS file: /tuna/ncvs/src/sys/i386/i386/machdep.c,v retrieving revision 1.270 diff -c -r1.270 machdep.c *************** *** 981,986 **** --- 993,1009 ---- 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, + #ifdef CMPXCHG8_BUG + /* GBUG_SEL 11 Invalid Descriptor for CMPXCHG8_BUG */ + { 0x0, /* segment base address */ + 0x0, /* length - none */ + SDT_MEMERA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 1, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, + #endif }; static struct soft_segment_descriptor ldt_segs[] = { *************** *** 1209,1216 **** --- 1232,1244 ---- #endif finishidentcpu(); /* Final stage of CPU initialization */ + #ifdef CMPXCHG8_BUG + setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GBUG_SEL, SEL_KPL)); + #else setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + #endif initializecpu(); /* Initialize CPU registers */ + /* Use BIOS values stored in RTC CMOS RAM, since probing * breaks certain 386 AT relics. Index: include/segments.h =================================================================== RCS file: /tuna/ncvs/src/sys/i386/include/segments.h,v retrieving revision 1.17 diff -c -r1.17 segments.h *** segments.h 1997/08/21 06:32:49 1.17 --- segments.h 1997/11/14 22:34:58 *************** *** 215,225 **** --- 215,232 ---- #define GAPMCODE32_SEL 8 /* APM BIOS 32-bit interface (32bit Code) */ #define GAPMCODE16_SEL 9 /* APM BIOS 32-bit interface (16bit Code) */ #define GAPMDATA_SEL 10 /* APM BIOS 32-bit interface (Data) */ + #ifdef CMPXCHG8_BUG + #define GBUG_SEL 11 /* Invalid Descriptor for CMPXCHG8_BUG */ + #endif #ifdef BDE_DEBUGGER #define NGDT 18 /* some of 11-17 are reserved for debugger */ #else + #ifdef CMPXCHG8_BUG + #define NGDT (GBUG_SEL + 1) + #else #define NGDT (GAPMDATA_SEL + 1) + #endif #endif /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19971114171214.44521>