diff options
-rw-r--r-- | arch/i386/cpu/start.S | 96 | ||||
-rw-r--r-- | arch/i386/cpu/start16.S | 21 |
2 files changed, 103 insertions, 14 deletions
diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index 3cea04b4ce3..7def8def8b1 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -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: diff --git a/arch/i386/cpu/start16.S b/arch/i386/cpu/start16.S index 5e33aa1069c..3e8b2cc5c4f 100644 --- a/arch/i386/cpu/start16.S +++ b/arch/i386/cpu/start16.S @@ -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) */ |