Skip site navigation (1)Skip section navigation (2)
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>