Messages in this thread | | | Date | Wed, 30 Jul 97 21:27:55 MDT | From | (Colin Plumb) | Subject | Re: Checking of 386bugs |
| |
The Intel web site reports a slightly different POPAD bug. http://support.intel.com/oem_developer/embedded_ia/386/general/386SX-B.HTM says:
80386SX-B STEPPING INFORMATION 12/1/89
2. Problem: The 386 SX CPU inadvertently corrupts the EAX register when either the POPA or POPAD instruction is followed by an instruction that uses the EAX register as a base address register AND is using an additional register as an index register. This sequence of code appears as:
POPA/POPAD
<instr> REG, <data size> ptr [EAX + <Index Reg>]
The following sample code is an example of the program:
MOV EAX, 4 POPAD MOV EBX, dword ptr [EAX + EBX*4]
Implications If the above instruction sequence occurs, the EAX register will contain an undefined value. Proper operation of the processor cannot be guaranteed after this sequence is executed until a hardware reset occurs. This sequence of instructions can occur in the Real, Protected and Virtual 86 modes of the 386 SX CPU.
Suggested Workaround Never execute the described instruction sequence. A workaround which has been proven to be successful in all cases is to insert a NOP instruction after every POPAD instruction; an example is shown below:
MOV EAX, 4 POPA/POPAD NOP MOV EBX, dword ptr [EAX + EBX*4]
Based on that, I think it should be something like:
/* If this fails, it means that any user program may lock CPU hard. Too bad. */ #ifdef CONFIG_M386 __initfunc( static void check_popad(void) ) { unsigned result, temp; int x; /* Some random thing to get a pointer to */
printk(KERN_INFO "Checking for POPAD bug..."); __asm__ ("pusha; addl $4,%0; popa; movl 0x55555555(%0,%3,2),%1" : "=a" (result), "=r" (temp) : "a" (0x55555555-(unsigned)&x), "r" ((unsigned)&x)); if ((result + (unsigned)&x)) * 3 != -1) printk("Eek! A malicious user can crash your machine.\n"); else printk("Ok.\n" ); } #else #define check_popad() /*nothing*/ #endif
Note that this version lets GCC worry about getting the right values into registers, and I used the (%eax,%ebx,2) addressing mode so that the assembler won't accidentally swap the operands. The value in eax seems unlikeoy to appear there by accident, and the check for the right value is written in such a way as to discourage the compiler from precomputing the right value for comparison.
I also trash %eax before the popa, but not so badly that if the memory access uses the trashed %eax value, it'll segfault. -- -Colin
| |