[U-Boot] [RFC][PATCH 09/21] [x86] Move GDT to a safe location in RAM

Graeme Russ
2010-03-25T11:22:51Z

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
---
cpu/i386/start.S | 110 +++++++++++++++++++++++++++++++++++++++++++++++++---
cpu/i386/start16.S | 28 +++----------
2 files changed, 111 insertions(+), 27 deletions(-)

diff --git a/cpu/i386/start.S b/cpu/i386/start.S
index e1d4492..8874470 100644
--- a/cpu/i386/start.S
+++ b/cpu/i386/start.S
@@ -49,13 +49,8 @@ _i386boot_start:
movl %eax, %cr0
wbinvd

- lidt blank_idt_ptr
-
- /* Tell 32-bit code it is being entered from */
+ /* Tell 32-bit code it is being entered from an in-RAM copy */
movw $0x0000, %bx
-
- /* Flush the prefetch queue */
- jmp _start
_start:
/* This is the 32-bit cold-reset entry point */

@@ -67,6 +62,9 @@ _start:
movw %ax,%es
movw %ax,%ss

+ /* Clear the interupt vectors */
+ lidt blank_idt_ptr
+
/*
* Skip low-level board and memory initialization if not starting
* from cold-reset. This allows us to do a fail safe boot-strap
@@ -102,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-ridden).
+ *
+ * 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
@@ -172,3 +217,56 @@ stack_ok:
die: hlt
jmp 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:
diff --git a/cpu/i386/start16.S b/cpu/i386/start16.S
index 1caa686..3e8b2cc 100644
--- a/cpu/i386/start16.S
+++ b/cpu/i386/start16.S
@@ -44,11 +44,9 @@ board_init16_ret:
movl %eax, %cr0
wbinvd

- /* load the descriptor tables */
-o32 cs lidt blank_idt_ptr
+ /* load the temporary Global Descriptor Table */
o32 cs lgdt gdt_ptr

-
/* Now, we enter protected mode */
movl %cr0, %eax
orl $1,%eax
@@ -70,13 +68,13 @@ code32start:
.long _start /* offset */
.word 0x10 /* segment */

-.global blank_idt_ptr
-blank_idt_ptr:
- .word 0 /* limit */
- .long 0 /* base */
-
+/*
+ * 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 ...
@@ -86,8 +84,6 @@ gdt_ptr:
* 0x08 Unused
* 0x10 32bit code
* 0x18 32bit data/stack
- * 0x20 16bit code
- * 0x28 16bit data/stack
*/

gdt:
@@ -103,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) */
--
1.7.0.2.182.ge007