x86: Move GDT to a safe location in RAM
authorGraeme Russ <graeme.russ@gmail.com>
Fri, 23 Apr 2010 14:05:43 +0000 (00:05 +1000)
committerWolfgang Denk <wd@denx.de>
Wed, 5 May 2010 22:15:43 +0000 (00:15 +0200)
Currently, the GDT is either located in FLASH or in the non-relocated
U-Boot image in RAM. Both of these locations are unsafe as those
locations can be erased during a U-Boot update. Move the GDT into the
highest available memory location and relocate U-Boot to just below it

Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
arch/i386/cpu/start.S
arch/i386/cpu/start16.S

index 3cea04b4ce37bd480ada911f610d9a800e9255b4..7def8def8b1d3b2398343fe0efbdc8cd935597b5 100644 (file)
@@ -100,6 +100,53 @@ mem_init_ret:
        jmp     get_mem_size
 get_mem_size_ret:
 
+       /*
+        * We are now in 'Flat Protected Mode' and we know how much memory
+        * the board has. The (temporary) Global Descriptor Table is not
+        * in a 'Safe' place (it is either in Flash which can be erased or
+        * reprogrammed or in a fail-safe boot-strap image which could be
+        * over-written).
+        *
+        * Move the final gdt to a safe place (top of RAM) and load it.
+        * This is not a trivial excercise - the lgdt instruction does not
+        * have a register operand (memory only) and we may well be
+        * running from Flash, so self modifying code will not work here.
+        * To overcome this, we copy a stub into upper memory along with
+        * the GDT.
+        */
+
+       /* Reduce upper memory limit by (Stub + GDT Pointer + GDT) */
+       subl    $(end_gdt_setup - start_gdt_setup), %eax
+
+       /* Copy the GDT and Stub */
+       movl    $start_gdt_setup, %esi
+       movl    %eax, %edi
+       movl    $(end_gdt_setup - start_gdt_setup), %ecx
+       shrl    $2, %ecx
+       cld
+       rep     movsl
+
+       /* write the lgdt 'parameter' */
+       subl    $(jmp_instr - start_gdt_setup - 4), %ebp
+       addl    %eax, %ebp
+       movl    $(gdt_ptr - start_gdt_setup), %ebx
+       addl    %eax, %ebx
+       movl    %ebx, (%ebp)
+
+       /* write the gdt address into the pointer */
+       movl    $(gdt_addr - start_gdt_setup), %ebp
+       addl    %eax, %ebp
+       movl    $(gdt - start_gdt_setup), %ebx
+       addl    %eax, %ebx
+       movl    %ebx, (%ebp)
+
+       /* Save the return address */
+       movl    $load_gdt_ret, %ebp
+
+       /* Load the new (safe) Global Descriptor Table */
+       jmp     *%eax
+
+load_gdt_ret:
        /* Check we have enough memory for stack */
        movl    $CONFIG_SYS_STACK_SIZE, %ecx
        cmpl    %ecx, %eax
@@ -174,3 +221,52 @@ die:       hlt
 blank_idt_ptr:
        .word   0               /* limit */
        .long   0               /* base */
+
+.align 4
+start_gdt_setup:
+       lgdt    gdt_ptr
+jmp_instr:
+       jmp     *%ebp
+
+.align 4
+gdt_ptr:
+       .word   0x30            /* limit (48 bytes = 6 GDT entries) */
+gdt_addr:
+       .long   gdt             /* base */
+
+       /* The GDT table ...
+        *
+        *       Selector       Type
+        *       0x00           NULL
+        *       0x08           Unused
+        *       0x10           32bit code
+        *       0x18           32bit data/stack
+        *       0x20           16bit code
+        *       0x28           16bit data/stack
+        */
+
+.align 4
+gdt:
+       .word   0, 0, 0, 0      /* NULL  */
+       .word   0, 0, 0, 0      /* unused */
+
+       .word   0xFFFF          /* 4Gb - (0x100000*0x1000 = 4Gb) */
+       .word   0               /* base address = 0 */
+       .word   0x9B00          /* code read/exec */
+       .word   0x00CF          /* granularity = 4096, 386 (+5th nibble of limit) */
+
+       .word   0xFFFF          /* 4Gb - (0x100000*0x1000 = 4Gb) */
+       .word   0x0             /* base address = 0 */
+       .word   0x9300          /* data read/write */
+       .word   0x00CF          /* granularity = 4096, 386 (+5th nibble of limit) */
+
+       .word   0xFFFF          /* 64kb */
+       .word   0               /* base address = 0 */
+       .word   0x9b00          /* data read/write */
+       .word   0x0010          /* granularity = 1  (+5th nibble of limit) */
+
+       .word   0xFFFF          /* 64kb */
+       .word   0               /* base address = 0 */
+       .word   0x9300          /* data read/write */
+       .word   0x0010          /* granularity = 1 (+5th nibble of limit) */
+end_gdt_setup:
index 5e33aa1069c7b25652d422b7ec8d189dd37ec469..3e8b2cc5c4fe56ef81eb64a9d7bbcee2b23e8f59 100644 (file)
@@ -44,7 +44,7 @@ board_init16_ret:
        movl    %eax, %cr0
        wbinvd
 
-       /* load the descriptor tables */
+       /* load the temporary Global Descriptor Table */
 o32 cs lgdt    gdt_ptr
 
        /* Now, we enter protected mode */
@@ -68,8 +68,13 @@ code32start:
        .long   _start          /* offset */
        .word   0x10            /* segment */
 
+/*
+ * The following Global Descriptor Table is just enough to get us into
+ * 'Flat Protected Mode' - It will be discarded as soon as the final
+ * GDT is setup in a safe location in RAM
+ */
 gdt_ptr:
-       .word   0x30            /* limit (48 bytes = 6 GDT entries) */
+       .word   0x20            /* limit (32 bytes = 4 GDT entries) */
        .long   BOOT_SEG + gdt  /* base */
 
        /* The GDT table ...
@@ -79,8 +84,6 @@ gdt_ptr:
         *       0x08           Unused
         *       0x10           32bit code
         *       0x18           32bit data/stack
-        *       0x20           16bit code
-        *       0x28           16bit data/stack
         */
 
 gdt:
@@ -96,13 +99,3 @@ gdt:
        .word   0x0             /* base address = 0 */
        .word   0x9300          /* data read/write */
        .word   0x00CF          /* granularity = 4096, 386 (+5th nibble of limit) */
-
-       .word   0xFFFF          /* 64kb */
-       .word   0               /* base address = 0 */
-       .word   0x9b00          /* data read/write */
-       .word   0x0010          /* granularity = 1  (+5th nibble of limit) */
-
-       .word   0xFFFF          /* 64kb */
-       .word   0               /* base address = 0 */
-       .word   0x9300          /* data read/write */
-       .word   0x0010          /* granularity = 1 (+5th nibble of limit) */