From 109ad143f8f2a948dc6628f55dbb6a8905087bfe Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Sat, 31 Dec 2011 10:24:36 +1100 Subject: x86: Remove GDR related magic numbers -- Changes for v2: - Use an enum - Add defined for GDT size (previously added in patch 7) - Use X86_ namespace (as per Linux headers) --- arch/x86/cpu/cpu.c | 8 ++++---- arch/x86/cpu/start.S | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 61d0b69..209ff29 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -63,13 +63,13 @@ static void reload_gdt(void) */ static const u64 boot_gdt[] __attribute__((aligned(16))) = { /* CS: code, read/execute, 4 GB, base 0 */ - [GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), + [X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), /* DS: data, read/write, 4 GB, base 0 */ - [GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), + [X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), /* 16-bit CS: code, read/execute, 64 kB, base 0 */ - [GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x109b, 0, 0x0ffff), + [X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x109b, 0, 0x0ffff), /* 16-bit DS: data, read/write, 64 kB, base 0 */ - [GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x1093, 0, 0x0ffff), + [X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x1093, 0, 0x0ffff), }; static struct gdt_ptr gdt; diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index f87633b..6027f54 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -58,7 +59,7 @@ _start: /* This is the 32-bit cold-reset entry point */ /* Load the segement registes to match the gdt loaded in start16.S */ - movl $0x18, %eax + movl $(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax movw %ax, %fs movw %ax, %ds movw %ax, %gs -- cgit v1.1 From 74bfbe1ba5ba99adccdc26dc4adbfb9221849310 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 29 Dec 2011 21:45:33 +1100 Subject: x86: Rework Global Descriptor Table loading The inline assembler is ugly and uses hard coded magic numbers. Make it more elegant to allow cleaner implementation of future GDT related patches. The compiler seems smart enough to generate the same code anyway -- Changes for v2: - Rebased against revised patch #3 - Use GDT size define instead of magic number - Added commit message --- arch/x86/cpu/cpu.c | 82 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 29 deletions(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 209ff29..8102fb9 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -55,35 +55,39 @@ struct gdt_ptr { u32 ptr; } __packed; -static void reload_gdt(void) +static void load_ds(u32 segment) { - /* - * There are machines which are known to not boot with the GDT - * being 8-byte unaligned. Intel recommends 16 byte alignment - */ - static const u64 boot_gdt[] __attribute__((aligned(16))) = { - /* CS: code, read/execute, 4 GB, base 0 */ - [X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), - /* DS: data, read/write, 4 GB, base 0 */ - [X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), - /* 16-bit CS: code, read/execute, 64 kB, base 0 */ - [X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x109b, 0, 0x0ffff), - /* 16-bit DS: data, read/write, 64 kB, base 0 */ - [X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x1093, 0, 0x0ffff), - }; - static struct gdt_ptr gdt; - - gdt.len = sizeof(boot_gdt)-1; - gdt.ptr = (u32)&boot_gdt; - - asm volatile("lgdtl %0\n" \ - "movl $((2+1)*8), %%ecx\n" \ - "movl %%ecx, %%ds\n" \ - "movl %%ecx, %%es\n" \ - "movl %%ecx, %%fs\n" \ - "movl %%ecx, %%gs\n" \ - "movl %%ecx, %%ss" \ - : : "m" (gdt) : "ecx"); + asm volatile("movl %0, %%ds" : : "r" (segment * X86_GDT_ENTRY_SIZE)); +} + +static void load_es(u32 segment) +{ + asm volatile("movl %0, %%es" : : "r" (segment * X86_GDT_ENTRY_SIZE)); +} + +static void load_fs(u32 segment) +{ + asm volatile("movl %0, %%fs" : : "r" (segment * X86_GDT_ENTRY_SIZE)); +} + +static void load_gs(u32 segment) +{ + asm volatile("movl %0, %%gs" : : "r" (segment * X86_GDT_ENTRY_SIZE)); +} + +static void load_ss(u32 segment) +{ + asm volatile("movl %0, %%ss" : : "r" (segment * X86_GDT_ENTRY_SIZE)); +} + +static void load_gdt(const u64 *boot_gdt, u16 num_entries) +{ + struct gdt_ptr gdt; + + gdt.len = (num_entries * 8) - 1; + gdt.ptr = (u32)boot_gdt; + + asm volatile("lgdtl %0\n" : : "m" (gdt)); } int x86_cpu_init_f(void) @@ -113,7 +117,27 @@ int x86_cpu_init_r(void) "movl %%eax, %%cr0\n" "wbinvd\n" : : "i" (nw_cd_rst) : "eax"); - reload_gdt(); + /* + * There are machines which are known to not boot with the GDT + * being 8-byte unaligned. Intel recommends 16 byte alignment + */ + static const u64 boot_gdt[] __aligned(16) = { + /* CS: code, read/execute, 4 GB, base 0 */ + [X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), + /* DS: data, read/write, 4 GB, base 0 */ + [X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), + /* 16-bit CS: code, read/execute, 64 kB, base 0 */ + [X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x109b, 0, 0x0ffff), + /* 16-bit DS: data, read/write, 64 kB, base 0 */ + [X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x1093, 0, 0x0ffff), + }; + + load_gdt(boot_gdt, X86_GDT_NUM_ENTRIES); + load_ds(X86_GDT_ENTRY_32BIT_DS); + load_es(X86_GDT_ENTRY_32BIT_DS); + load_fs(X86_GDT_ENTRY_32BIT_DS); + load_gs(X86_GDT_ENTRY_32BIT_DS); + load_ss(X86_GDT_ENTRY_32BIT_DS); /* Initialize core interrupt and exception functionality of CPU */ cpu_init_interrupts(); -- cgit v1.1 From f48dd6fc6cc9fdf15408e98132dc5575a31026cf Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Sun, 1 Jan 2012 15:06:39 +1100 Subject: x86: Simplify Flash-to-RAM code execution transition Move the relocation offset calculation out of assembler and into C. This also paves the way for the upcoming init sequence simplification by adding the board_init_f_r flash to RAM transitional function -- Changes for v2: - Added commit message - Minor adjustment to new stack address comment --- arch/x86/cpu/start.S | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 6027f54..69a9b2c 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -96,32 +96,22 @@ car_init_ret: movw $0x85, %ax jmp die -.globl relocate_code -.type relocate_code, @function -relocate_code: +.globl board_init_f_r_trampoline +.type board_init_f_r_trampoline, @function +board_init_f_r_trampoline: /* * SDRAM has been initialised, U-Boot code has been copied into * RAM, BSS has been cleared and relocation adjustments have been * made. It is now time to jump into the in-RAM copy of U-Boot * - * %eax = Address of top of stack - * %edx = Address of Global Data - * %ecx = Base address of in-RAM copy of U-Boot + * %eax = Address of top of new stack */ /* Setup stack in RAM */ movl %eax, %esp - /* Setup call address of in-RAM copy of board_init_r() */ - movl $board_init_r, %ebp - addl (GENERATED_GD_RELOC_OFF)(%edx), %ebp - - /* Setup parameters to board_init_r() */ - movl %edx, %eax - movl %ecx, %edx - - /* Jump to in-RAM copy of board_init_r() */ - call *%ebp + /* Re-enter U-Boot by calling board_init_f_r */ + call board_init_f_r die: hlt -- cgit v1.1 From 9e6c572ff03cda84c88663b23c7157d8b1f275ac Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Sat, 31 Dec 2011 22:58:15 +1100 Subject: x86: Use fs for global data Use the base address of the 'F' segment as a pointer to the global data structure. By adding the linear address (i.e. the 'D' segment address) as the first word of the global data structure, the address of the global data relative to the 'D' segment can be found simply, for example, by: fs movl 0, %eax This makes the gd 'pointer' writable prior to relocation (by reloading the Global Desctriptor Table) which brings x86 into line with all other arches NOTE: Writing to the gd 'pointer' is expensive (but we only do it twice) but using it to access global data members (read and write) is still fairly cheap -- Changes for v2: - Rebased against changes made to patch #3 - Removed extra indent - Tweaked commit message --- arch/x86/cpu/cpu.c | 53 ++++++++++++++++++++++++++++++---------------------- arch/x86/cpu/start.S | 8 +++++++- 2 files changed, 38 insertions(+), 23 deletions(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 8102fb9..8c3b92c 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -90,6 +90,37 @@ static void load_gdt(const u64 *boot_gdt, u16 num_entries) asm volatile("lgdtl %0\n" : : "m" (gdt)); } +void init_gd(gd_t *id, u64 *gdt_addr) +{ + id->gd_addr = (ulong)id; + setup_gdt(id, gdt_addr); +} + +void setup_gdt(gd_t *id, u64 *gdt_addr) +{ + /* CS: code, read/execute, 4 GB, base 0 */ + gdt_addr[X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff); + + /* DS: data, read/write, 4 GB, base 0 */ + gdt_addr[X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff); + + /* FS: data, read/write, 4 GB, base (Global Data Pointer) */ + gdt_addr[X86_GDT_ENTRY_32BIT_FS] = GDT_ENTRY(0xc093, (ulong)id, 0xfffff); + + /* 16-bit CS: code, read/execute, 64 kB, base 0 */ + gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x109b, 0, 0x0ffff); + + /* 16-bit DS: data, read/write, 64 kB, base 0 */ + gdt_addr[X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x1093, 0, 0x0ffff); + + load_gdt(gdt_addr, X86_GDT_NUM_ENTRIES); + load_ds(X86_GDT_ENTRY_32BIT_DS); + load_es(X86_GDT_ENTRY_32BIT_DS); + load_gs(X86_GDT_ENTRY_32BIT_DS); + load_ss(X86_GDT_ENTRY_32BIT_DS); + load_fs(X86_GDT_ENTRY_32BIT_FS); +} + int x86_cpu_init_f(void) { const u32 em_rst = ~X86_CR0_EM; @@ -117,28 +148,6 @@ int x86_cpu_init_r(void) "movl %%eax, %%cr0\n" "wbinvd\n" : : "i" (nw_cd_rst) : "eax"); - /* - * There are machines which are known to not boot with the GDT - * being 8-byte unaligned. Intel recommends 16 byte alignment - */ - static const u64 boot_gdt[] __aligned(16) = { - /* CS: code, read/execute, 4 GB, base 0 */ - [X86_GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), - /* DS: data, read/write, 4 GB, base 0 */ - [X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), - /* 16-bit CS: code, read/execute, 64 kB, base 0 */ - [X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x109b, 0, 0x0ffff), - /* 16-bit DS: data, read/write, 64 kB, base 0 */ - [X86_GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x1093, 0, 0x0ffff), - }; - - load_gdt(boot_gdt, X86_GDT_NUM_ENTRIES); - load_ds(X86_GDT_ENTRY_32BIT_DS); - load_es(X86_GDT_ENTRY_32BIT_DS); - load_fs(X86_GDT_ENTRY_32BIT_DS); - load_gs(X86_GDT_ENTRY_32BIT_DS); - load_ss(X86_GDT_ENTRY_32BIT_DS); - /* Initialize core interrupt and exception functionality of CPU */ cpu_init_interrupts(); return 0; diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 69a9b2c..ee0dabe 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -31,7 +31,7 @@ #include #include #include -#include +#include .section .text .code32 @@ -85,6 +85,12 @@ car_init_ret: */ movl $CONFIG_SYS_INIT_SP_ADDR, %esp + /* Initialise the Global Data Pointer */ + movl $CONFIG_SYS_INIT_GD_ADDR, %eax + movl %eax, %edx + addl $GENERATED_GBL_DATA_SIZE, %edx + call init_gd; + /* Set parameter to board_init_f() to boot flags */ xorl %eax, %eax movw %bx, %ax -- cgit v1.1 From d653244b12dbc4a954e1bdfd04222bbbaf67329c Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Tue, 27 Dec 2011 22:46:43 +1100 Subject: x86: Create weak init_cache() and default enable_caches() functions -- Changes for v2: - Tweaked commit title --- arch/x86/cpu/cpu.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 8c3b92c..e9bb0d7 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -140,6 +140,14 @@ int cpu_init_f(void) __attribute__((weak, alias("x86_cpu_init_f"))); int x86_cpu_init_r(void) { + /* Initialize core interrupt and exception functionality of CPU */ + cpu_init_interrupts(); + return 0; +} +int cpu_init_r(void) __attribute__((weak, alias("x86_cpu_init_r"))); + +void x86_enable_caches(void) +{ const u32 nw_cd_rst = ~(X86_CR0_NW | X86_CR0_CD); /* turn on the cache and disable write through */ @@ -147,12 +155,16 @@ int x86_cpu_init_r(void) "andl %0, %%eax\n" "movl %%eax, %%cr0\n" "wbinvd\n" : : "i" (nw_cd_rst) : "eax"); +} +void enable_caches(void) __attribute__((weak, alias("x86_enable_caches"))); + +int x86_init_cache(void) +{ + enable_caches(); - /* Initialize core interrupt and exception functionality of CPU */ - cpu_init_interrupts(); return 0; } -int cpu_init_r(void) __attribute__((weak, alias("x86_cpu_init_r"))); +int init_cache(void) __attribute__((weak, alias("x86_init_cache"))); int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { -- cgit v1.1 From 58c7a6751dd0978172741503b4dc0c6b23a60b33 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Mon, 19 Dec 2011 14:26:18 +1100 Subject: x86: Tweak IDT and GDT for alignment and readability -- Changes for v2: - Renamed to better reflect nature of changes --- arch/x86/cpu/interrupts.c | 2 +- arch/x86/cpu/start16.S | 57 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 13 deletions(-) (limited to 'arch/x86/cpu') diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index e0958eb..43ec3f8 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -174,7 +174,7 @@ struct desc_ptr { unsigned short segment; } __packed; -struct idt_entry idt[256] __attribute__((aligned(16))); +struct idt_entry idt[256] __aligned(16); struct desc_ptr idt_ptr; diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S index 33e53cd..cc393ff 100644 --- a/arch/x86/cpu/start16.S +++ b/arch/x86/cpu/start16.S @@ -86,7 +86,11 @@ gdt_ptr: .word 0x20 /* limit (32 bytes = 4 GDT entries) */ .long BOOT_SEG + gdt /* base */ - /* The GDT table ... +/* Some CPUs are picky about GDT alignment... */ +.align 16 +gdt: + /* + * The GDT table ... * * Selector Type * 0x00 NULL @@ -94,17 +98,46 @@ gdt_ptr: * 0x10 32bit code * 0x18 32bit data/stack */ + /* The NULL Desciptor - Mandatory */ + .word 0x0000 /* limit_low */ + .word 0x0000 /* base_low */ + .byte 0x00 /* base_middle */ + .byte 0x00 /* access */ + .byte 0x00 /* flags + limit_high */ + .byte 0x00 /* base_high */ -gdt: - .word 0, 0, 0, 0 /* NULL */ - .word 0, 0, 0, 0 /* unused */ + /* Unused Desciptor - (matches Linux) */ + .word 0x0000 /* limit_low */ + .word 0x0000 /* base_low */ + .byte 0x00 /* base_middle */ + .byte 0x00 /* access */ + .byte 0x00 /* flags + limit_high */ + .byte 0x00 /* base_high */ - .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) */ + /* + * The Code Segment Descriptor: + * - Base = 0x00000000 + * - Size = 4GB + * - Access = Present, Ring 0, Exec (Code), Readable + * - Flags = 4kB Granularity, 32-bit + */ + .word 0xffff /* limit_low */ + .word 0x0000 /* base_low */ + .byte 0x00 /* base_middle */ + .byte 0x9b /* access */ + .byte 0xcf /* flags + limit_high */ + .byte 0x00 /* base_high */ - .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) */ + /* + * The Data Segment Descriptor: + * - Base = 0x00000000 + * - Size = 4GB + * - Access = Present, Ring 0, Non-Exec (Data), Writable + * - Flags = 4kB Granularity, 32-bit + */ + .word 0xffff /* limit_low */ + .word 0x0000 /* base_low */ + .byte 0x00 /* base_middle */ + .byte 0x93 /* access */ + .byte 0xcf /* flags + limit_high */ + .byte 0x00 /* base_high */ -- cgit v1.1