Fix address of IDT in real-mode entry
authorKyösti Mälkki <kyosti.malkki@gmail.com>
Mon, 5 Mar 2012 07:25:12 +0000 (09:25 +0200)
committerPatrick Georgi <patrick@georgi-clan.de>
Fri, 16 Mar 2012 18:34:14 +0000 (19:34 +0100)
In a case of CS & 0x0fff != 0x0, lidt memory operand does not point
to nullidt, this can raise an exception and shutdown the CPU.

When an AP CPU receives 8-bit Start-Up IPI vector yzH, it starts
execute at physical address 000yz000H. Seems this translates to
either yz00:0000 or y000:z000 (CS:IP), depending of the CPU model.
With the change entry16.inc is relocatable as the commentary suggests
and can be used as ap_sipi_vector on SMP systems.

Change-Id: I885a2888179700ba6e2b11d4f2d6a64ddea4c2dc
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: http://review.coreboot.org/707
Tested-by: build bot (Jenkins)
Reviewed-by: Idwer Vollering <vidwer@gmail.com>
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
src/cpu/x86/16bit/entry16.inc

index 0fa8c11524c6321514f112996470cc35bbfaab25..e4613bf986c15d73e7ea70f72dc241d1539f3038 100644 (file)
@@ -57,13 +57,6 @@ _start:
         * entry16.inc.
         */
 
-       /* Load an IDT with NULL limit to prevent the 16bit IDT being used
-        * in protected mode before c_start.S sets up a 32bit IDT when entering
-        * ram stage.
-        */
-       movw $nullidt_offset, %bx
-       lidt %cs:(%bx)
-
        /* Note: gas handles memory addresses in 16 bit code very poorly.
         * In particular it doesn't appear to have a directive allowing you
         * associate a section or even an absolute offset with a segment register.
@@ -98,10 +91,18 @@ _start:
         * the low 16 bits.  This means that the intial segment used
         * when start is called must be 64K aligned.  This should not
         * restrict the address as the ip address can be anything.
+        *
+        * Also load an IDT with NULL limit to prevent the 16bit IDT being used
+        * in protected mode before c_start.S sets up a 32bit IDT when entering
+        * ram stage. In practise: CPU will shutdown on any exception.
+        * See IA32 manual Vol 3A 19.26 Interrupts.
         */
 
        movw    %cs, %ax
        shlw    $4, %ax
+       movw    $nullidt_offset, %bx
+       subw    %ax, %bx
+       lidt    %cs:(%bx)
        movw    $gdtptr16_offset, %bx
        subw    %ax, %bx
        data32  lgdt %cs:(%bx)