diff options
author | Wolfgang Denk <wd@denx.de> | 2012-02-17 23:47:29 +0100 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2012-02-17 23:47:29 +0100 |
commit | e390e8709149664ff96cf19384264c84573f3082 (patch) | |
tree | a14b00ce6732eedf0b9c20b2cb54f17f1ac14596 | |
parent | e9d44b35beb45869863f3ca6929089d9df4df3e5 (diff) | |
parent | afd855d534de22aa625cb12aa9aa45e459f7de99 (diff) |
Merge branch 'master' of git://git.denx.de/u-boot-x86
* 'master' of git://git.denx.de/u-boot-x86:
x86: Convert board_init_f_r to a processing loop
x86: Split init functions out of board.c
x86: Move relocation code out of board.c
x86: Move setup_pcat_compatibility() out of board.c
x86: Move do_go_exec() out of board.c
CHECKPATCH: arch/x86/lib/*
x86: Tweak IDT and GDT for alignment and readability
x86: Allow cache before copy to RAM
x86: Create weak init_cache() and default enable_caches() functions
x86: Set GD_FLG_RELOC after entering in-RAM copy of U-Boot
x86: Use fs for global data
x86: Rework relocation calculations
x86: Simplify Flash-to-RAM code execution transition
x86: Rework Global Descriptor Table loading
x86: Remove GDR related magic numbers
x86: Speed up copy-to-RAM and clear BSS operations
x86: Import glibc memcpy implementation
-rw-r--r-- | arch/x86/cpu/cpu.c | 109 | ||||
-rw-r--r-- | arch/x86/cpu/interrupts.c | 2 | ||||
-rw-r--r-- | arch/x86/cpu/start.S | 33 | ||||
-rw-r--r-- | arch/x86/cpu/start16.S | 57 | ||||
-rw-r--r-- | arch/x86/include/asm/global_data.h | 21 | ||||
-rw-r--r-- | arch/x86/include/asm/init_helpers.h | 44 | ||||
-rw-r--r-- | arch/x86/include/asm/init_wrappers.h | 42 | ||||
-rw-r--r-- | arch/x86/include/asm/processor.h | 24 | ||||
-rw-r--r-- | arch/x86/include/asm/relocate.h | 33 | ||||
-rw-r--r-- | arch/x86/include/asm/string.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/u-boot-x86.h | 5 | ||||
-rw-r--r-- | arch/x86/lib/Makefile | 4 | ||||
-rw-r--r-- | arch/x86/lib/bios.S | 134 | ||||
-rw-r--r-- | arch/x86/lib/board.c | 517 | ||||
-rw-r--r-- | arch/x86/lib/cmd_boot.c | 64 | ||||
-rw-r--r-- | arch/x86/lib/init_helpers.c | 217 | ||||
-rw-r--r-- | arch/x86/lib/init_wrappers.c | 137 | ||||
-rw-r--r-- | arch/x86/lib/realmode_switch.S | 61 | ||||
-rw-r--r-- | arch/x86/lib/relocate.c | 91 | ||||
-rw-r--r-- | arch/x86/lib/string.c | 61 | ||||
-rw-r--r-- | arch/x86/lib/zimage.c | 7 |
21 files changed, 1152 insertions, 513 deletions
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 61d0b69416e..e9bb0d770a3 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -55,35 +55,70 @@ 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 */ - [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), - /* 16-bit CS: code, read/execute, 64 kB, base 0 */ - [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), - }; - 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)); +} + +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) @@ -105,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 */ @@ -112,14 +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"))); - reload_gdt(); +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[]) { diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index e0958eb67f4..43ec3f8b081 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/start.S b/arch/x86/cpu/start.S index f87633b5612..ee0dabe4bcd 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -29,8 +29,9 @@ #include <config.h> #include <version.h> #include <asm/global_data.h> +#include <asm/processor.h> #include <asm/processor-flags.h> -#include <generated/asm-offsets.h> +#include <generated/generic-asm-offsets.h> .section .text .code32 @@ -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 @@ -84,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 @@ -95,32 +102,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 diff --git a/arch/x86/cpu/start16.S b/arch/x86/cpu/start16.S index 33e53cdb3b6..cc393ff54fc 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 */ diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 05a2139d001..908a02c900c 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -36,6 +36,8 @@ #ifndef __ASSEMBLY__ typedef struct global_data { + /* NOTE: gd_addr MUST be first member of struct global_data! */ + unsigned long gd_addr; /* Location of Global Data */ bd_t *bd; unsigned long flags; unsigned long baudrate; @@ -51,13 +53,24 @@ typedef struct global_data { unsigned long bus_clk; unsigned long relocaddr; /* Start address of U-Boot in RAM */ unsigned long start_addr_sp; /* start_addr_stackpointer */ + unsigned long gdt_addr; /* Location of GDT */ + unsigned long new_gd_addr; /* New location of Global Data */ phys_size_t ram_size; /* RAM size */ unsigned long reset_status; /* reset status register at boot */ void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ } gd_t; -extern gd_t *gd; +static inline gd_t *get_fs_gd_ptr(void) +{ + gd_t *gd_ptr; + + asm volatile("fs movl 0, %0\n" : "=r" (gd_ptr)); + + return gd_ptr; +} + +#define gd get_fs_gd_ptr() #endif @@ -73,12 +86,6 @@ extern gd_t *gd; #define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */ #define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */ -#if 0 #define DECLARE_GLOBAL_DATA_PTR -#else -#define XTRN_DECLARE_GLOBAL_DATA_PTR extern -#define DECLARE_GLOBAL_DATA_PTR XTRN_DECLARE_GLOBAL_DATA_PTR \ -gd_t *gd -#endif #endif /* __ASM_GBL_DATA_H */ diff --git a/arch/x86/include/asm/init_helpers.h b/arch/x86/include/asm/init_helpers.h new file mode 100644 index 00000000000..192f18e1d50 --- /dev/null +++ b/arch/x86/include/asm/init_helpers.h @@ -0,0 +1,44 @@ +/* + * (C) Copyright 2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _INIT_HELPERS_H_ +#define _INIT_HELPERS_H_ + +int display_banner(void); +int display_dram_config(void); +int init_baudrate_f(void); +int calculate_relocation_address(void); + +int copy_gd_to_ram_f_r(void); +int init_cache_f_r(void); + +int set_reloc_flag_r(void); +int mem_malloc_init_r(void); +int init_bd_struct_r(void); +int flash_init_r(void); +int init_ip_address_r(void); +int status_led_set_r(void); +int set_bootfile_r(void); +int set_load_addr_r(void); + +#endif /* !_INIT_HELPERS_H_ */ diff --git a/arch/x86/include/asm/init_wrappers.h b/arch/x86/include/asm/init_wrappers.h new file mode 100644 index 00000000000..899ffb15446 --- /dev/null +++ b/arch/x86/include/asm/init_wrappers.h @@ -0,0 +1,42 @@ +/* + * (C) Copyright 2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _INIT_WRAPPERS_H_ +#define _INIT_WRAPPERS_H_ + +int serial_initialize_r(void); +int env_relocate_r(void); +int pci_init_r(void); +int jumptable_init_r(void); +int pcmcia_init_r(void); +int kgdb_init_r(void); +int enable_interrupts_r(void); +int eth_initialize_r(void); +int reset_phy_r(void); +int ide_init_r(void); +int scsi_init_r(void); +int doc_init_r(void); +int bb_miiphy_init_r(void); +int post_run_r(void); + +#endif /* !_INIT_WRAPPERS_H_ */ diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 1e5dccd342c..6eb518063bd 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -24,9 +24,25 @@ #ifndef __ASM_PROCESSOR_H_ #define __ASM_PROCESSOR_H_ 1 -#define GDT_ENTRY_32BIT_CS 2 -#define GDT_ENTRY_32BIT_DS (GDT_ENTRY_32BIT_CS + 1) -#define GDT_ENTRY_16BIT_CS (GDT_ENTRY_32BIT_DS + 1) -#define GDT_ENTRY_16BIT_DS (GDT_ENTRY_16BIT_CS + 1) +#define X86_GDT_ENTRY_SIZE 8 + +#ifndef __ASSEMBLY__ + +enum { + X86_GDT_ENTRY_NULL = 0, + X86_GDT_ENTRY_UNUSED, + X86_GDT_ENTRY_32BIT_CS, + X86_GDT_ENTRY_32BIT_DS, + X86_GDT_ENTRY_32BIT_FS, + X86_GDT_ENTRY_16BIT_CS, + X86_GDT_ENTRY_16BIT_DS, + X86_GDT_NUM_ENTRIES +}; +#else +/* NOTE: If the above enum is modified, this define must be checked */ +#define X86_GDT_ENTRY_32BIT_DS 3 +#endif + +#define X86_GDT_SIZE (X86_GDT_NUM_ENTRIES * X86_GDT_ENTRY_SIZE) #endif diff --git a/arch/x86/include/asm/relocate.h b/arch/x86/include/asm/relocate.h new file mode 100644 index 00000000000..33129ef64b0 --- /dev/null +++ b/arch/x86/include/asm/relocate.h @@ -0,0 +1,33 @@ +/* + * (C) Copyright 2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _RELOCATE_H_ +#define _RELOCATE_H_ + +#include <common.h> + +int copy_uboot_to_ram(void); +int clear_bss(void); +int do_elf_reloc_fixups(void); + +#endif /* !_RELOCATE_H_ */ diff --git a/arch/x86/include/asm/string.h b/arch/x86/include/asm/string.h index 3aa6c1131b2..0ad612f6273 100644 --- a/arch/x86/include/asm/string.h +++ b/arch/x86/include/asm/string.h @@ -14,7 +14,7 @@ extern char * strrchr(const char * s, int c); #undef __HAVE_ARCH_STRCHR extern char * strchr(const char * s, int c); -#undef __HAVE_ARCH_MEMCPY +#define __HAVE_ARCH_MEMCPY extern void * memcpy(void *, const void *, __kernel_size_t); #undef __HAVE_ARCH_MEMMOVE diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 755f88af048..878a1ee77b1 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -37,6 +37,9 @@ int x86_cpu_init_r(void); int cpu_init_r(void); int x86_cpu_init_f(void); int cpu_init_f(void); +void init_gd(gd_t *id, u64 *gdt_addr); +void setup_gdt(gd_t *id, u64 *gdt_addr); +int init_cache(void); /* cpu/.../timer.c */ void timer_isr(void *); @@ -61,5 +64,7 @@ u32 isa_map_rom(u32 bus_addr, int size); int video_bios_init(void); int video_init(void); +void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); +void board_init_f_r(void) __attribute__ ((noreturn)); #endif /* _U_BOOT_I386_H_ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index d584aa4a80f..51836dacca5 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -32,13 +32,17 @@ SOBJS-$(CONFIG_SYS_X86_REALMODE) += realmode_switch.o COBJS-$(CONFIG_SYS_PC_BIOS) += bios_setup.o COBJS-y += board.o COBJS-y += bootm.o +COBJS-y += cmd_boot.o COBJS-y += gcc.o +COBJS-y += init_helpers.o +COBJS-y += init_wrappers.o COBJS-y += interrupts.o COBJS-$(CONFIG_SYS_PCAT_INTERRUPTS) += pcat_interrupts.o COBJS-$(CONFIG_SYS_GENERIC_TIMER) += pcat_timer.o COBJS-$(CONFIG_PCI) += pci.o COBJS-$(CONFIG_PCI) += pci_type1.o COBJS-$(CONFIG_SYS_X86_REALMODE) += realmode.o +COBJS-y += relocate.o COBJS-y += string.o COBJS-$(CONFIG_SYS_X86_ISR_TIMER) += timer.o COBJS-$(CONFIG_VIDEO) += video_bios.o diff --git a/arch/x86/lib/bios.S b/arch/x86/lib/bios.S index ce8deb5377f..239aaa9cfa4 100644 --- a/arch/x86/lib/bios.S +++ b/arch/x86/lib/bios.S @@ -246,11 +246,9 @@ rm_int1f: rm_def_int: iret - /* - * All interrupt jumptable entries jump to here - * after pushing the interrupt vector number onto the - * stack. + * All interrupt jumptable entries jump to here after pushing the + * interrupt vector number onto the stack. */ any_interrupt16: MAKE_BIOS_STACK @@ -272,7 +270,8 @@ gs movw OFFS_VECTOR(%bp), %ax je Lint_1ah movw $0xffff, %ax jmp Lout -Lint_10h: /* VGA BIOS services */ +Lint_10h: + /* VGA BIOS services */ call bios_10h jmp Lout Lint_11h: @@ -281,35 +280,42 @@ Lint_11h: Lint_12h: call bios_12h jmp Lout -Lint_13h: /* BIOS disk services */ +Lint_13h: + /* BIOS disk services */ call bios_13h jmp Lout -Lint_15h: /* Misc. BIOS services */ +Lint_15h: + /* Misc. BIOS services */ call bios_15h jmp Lout -Lint_16h: /* keyboard services */ +Lint_16h: + /* keyboard services */ call bios_16h jmp Lout -Lint_1ah: /* PCI bios */ +Lint_1ah: + /* PCI bios */ call bios_1ah jmp Lout Lout: cmpw $0, %ax je Lhandeled - /* Insert code for unhandeled INTs here. + /* + * Insert code for unhandeled INTs here. * - * ROLO prints a message to the console - * (we could do that but then we're in 16bit mode - * so we'll have to get back into 32bit mode - * to use the console I/O routines (if we do this - * we shuls make int 0x10 and int 0x16 work as well)) + * ROLO prints a message to the console we could do that but then + * we're in 16bit mode so we'll have to get back into 32bit mode + * to use the console I/O routines (if we do this we should make + * int 0x10 and int 0x16 work as well) */ Lhandeled: RESTORE_CALLERS_STACK - addw $2,%sp /* dump vector number */ - iret /* return from interrupt */ + /* dump vector number */ + addw $2,%sp + + /* return from interrupt */ + iret /* ************************************************************ @@ -327,22 +333,24 @@ gs movw OFFS_AX(%bp), %ax je Lvid_cfg movw $0xffff, %ax ret -Lcur_pos: /* Read Cursor Position and Size */ +Lcur_pos: + /* Read Cursor Position and Size */ gs movw $0, OFFS_CX(%bp) gs movw $0, OFFS_DX(%bp) xorw %ax, %ax ret -Lvid_state: /* Get Video State */ -gs movw $(80 << 8|0x03), OFFS_AX(%bp) /* 80 columns, 80x25, 16 colors */ +Lvid_state: + /* Get Video State - 80 columns, 80x25, 16 colors */ +gs movw $(80 << 8|0x03), OFFS_AX(%bp) gs movw $0, OFFS_BX(%bp) xorw %ax, %ax ret -Lvid_cfg: /* Video Subsystem Configuration (EGA/VGA) */ -gs movw $0x10, OFFS_BX(%bp) /* indicate CGA/MDA/HGA */ +Lvid_cfg: + /* Video Subsystem Configuration (EGA/VGA) - indicate CGA/MDA/HGA */ +gs movw $0x10, OFFS_BX(%bp) xorw %ax, %ax ret - /* ************************************************************ * BIOS interrupt 11h -- Equipment determination @@ -355,7 +363,6 @@ gs movw %ax, OFFS_AX(%bp) xorw %ax, %ax ret - /* ************************************************************ * BIOS interrupt 12h -- Get Memory Size @@ -370,16 +377,18 @@ cs movw ram_in_64kb_chunks, %ax b12_more_than_640k: movw $0x280, %ax b12_return: -gs movw %ax, OFFS_AX(%bp) /* return number of kilobytes in ax */ + /* return number of kilobytes in ax */ +gs movw %ax, OFFS_AX(%bp) gs movw OFFS_FLAGS(%bp), %ax - andw $0xfffe, %ax /* clear carry -- function succeeded */ + + /* clear carry -- function succeeded */ + andw $0xfffe, %ax gs movw %ax, OFFS_FLAGS(%bp) xorw %ax, %ax ret - /* ************************************************************ * BIOS interrupt 13h -- Disk services @@ -394,12 +403,13 @@ gs movw OFFS_AX(%bp), %ax ret Lfunc_15h: gs movw OFFS_AX(%bp), %ax - andw $0xff, %ax /* return AH=0->drive not present */ + + /* return AH=0->drive not present */ + andw $0x00ff, %ax gs movw %ax, OFFS_AX(%bp) xorw %ax, %ax ret - /* *********************************************************** * BIOS interrupt 15h -- Miscellaneous services @@ -417,9 +427,12 @@ gs movw OFFS_AX(%bp), %ax movw $0xffff, %ax ret -Lfunc_c0h: /* Return System Configuration Parameters (PS2 only) */ +Lfunc_c0h: + /* Return System Configuration Parameters (PS2 only) */ gs movw OFFS_FLAGS(%bp), %ax - orw $1, %ax /* return carry -- function not supported */ + + /* return carry -- function not supported */ + orw $1, %ax gs movw %ax, OFFS_FLAGS(%bp) xorw %ax, %ax ret @@ -430,38 +443,56 @@ gs movw OFFS_AX(%bp), %ax cmpw $1, %ax je Lfunc_e801h gs movw OFFS_FLAGS(%bp), %ax - orw $1, %ax /* return carry -- function not supported */ + + /* return carry -- function not supported */ + orw $1, %ax gs movw %ax, OFFS_FLAGS(%bp) xorw %ax, %ax ret -Lfunc_e801h: /* Get memory size for >64M Configurations */ +Lfunc_e801h: + /* Get memory size for >64M Configurations */ cs movw ram_in_64kb_chunks, %ax cmpw $0x100, %ax ja e801_more_than_16mb - shlw $6, %ax /* multiply by 64 */ - subw $0x400, %ax /* 1st meg does not count */ -gs movw %ax, OFFS_AX(%bp) /* return memory size between 1M and 16M in 1kb chunks in AX and CX */ + /* multiply by 64 */ + shlw $6, %ax + + /* 1st meg does not count */ + subw $0x400, %ax + + /* return memory size between 1M and 16M in 1kb chunks in AX and CX */ +gs movw %ax, OFFS_AX(%bp) gs movw %ax, OFFS_CX(%bp) -gs movw $0, OFFS_BX(%bp) /* set BX and DX to 0*/ + + /* set BX and DX to 0*/ +gs movw $0, OFFS_BX(%bp) gs movw $0, OFFS_DX(%bp) gs movw OFFS_FLAGS(%bp), %ax - andw $0xfffe, %ax /* clear carry -- function succeeded */ + + /* clear carry -- function succeeded */ + andw $0xfffe, %ax gs movw %ax, OFFS_FLAGS(%bp) xorw %ax, %ax ret e801_more_than_16mb: - subw $0x100, %ax /* subtract 16MB */ + /* subtract 16MB */ + subw $0x100, %ax -gs movw $0x3c00, OFFS_AX(%bp) /* return 0x3c00 (16MB-1MB) in AX and CX */ + /* return 0x3c00 (16MB-1MB) in AX and CX */ +gs movw $0x3c00, OFFS_AX(%bp) gs movw $0x3c00, OFFS_CX(%bp) -gs movw %ax, OFFS_BX(%bp) /* set BX and DX to number of 64kb chunks above 16MB */ + + /* set BX and DX to number of 64kb chunks above 16MB */ +gs movw %ax, OFFS_BX(%bp) gs movw %ax, OFFS_DX(%bp) gs movw OFFS_FLAGS(%bp), %ax - andw $0xfffe, %ax /* clear carry -- function succeeded */ + + /* clear carry -- function succeeded */ + andw $0xfffe, %ax gs movw %ax, OFFS_FLAGS(%bp) xorw %ax, %ax ret @@ -473,18 +504,22 @@ cs movw ram_in_64kb_chunks, %ax movw $0x100, %ax b88_not_more_than16: shlw $6, %ax - subw $0x400, %ax /* 1st meg does not count */ -gs movw %ax, OFFS_AX(%bp) /* return number of kilobytes between 16MB and 16MB in ax */ + /* 1st meg does not count */ + subw $0x400, %ax + + /* return number of kilobytes between 16MB and 16MB in ax */ +gs movw %ax, OFFS_AX(%bp) gs movw OFFS_FLAGS(%bp), %ax - andw $0xfffe, %ax /* clear carry -- function succeeded */ + + /* clear carry -- function succeeded */ + andw $0xfffe, %ax gs movw %ax, OFFS_FLAGS(%bp) xorw %ax, %ax ret - /* ************************************************************ * BIOS interrupt 16h -- keyboard services @@ -498,7 +533,8 @@ gs movw OFFS_AX(%bp), %ax movw $0xffff, %ax ret Lfunc_03h: - xorw %ax, %ax /* do nothing -- function not supported */ + /* do nothing -- function not supported */ + xorw %ax, %ax ret /* @@ -514,7 +550,9 @@ gs movw OFFS_AX(%bp), %ax ret Lfunc_b1h: call realmode_pci_bios - xorw %ax, %ax /* do nothing -- function not supported */ + + /* do nothing -- function not supported */ + xorw %ax, %ax ret diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index d742fec928b..5f0b62cea6e 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -33,111 +33,96 @@ #include <common.h> #include <watchdog.h> -#include <command.h> #include <stdio_dev.h> -#include <version.h> -#include <malloc.h> -#include <net.h> -#include <ide.h> -#include <serial.h> #include <asm/u-boot-x86.h> -#include <elf.h> +#include <asm/relocate.h> -#ifdef CONFIG_BITBANGMII -#include <miiphy.h> -#endif - -/* - * Pointer to initial global data area - * - * Here we initialize it. - */ -#undef XTRN_DECLARE_GLOBAL_DATA_PTR -#define XTRN_DECLARE_GLOBAL_DATA_PTR /* empty = allocate here */ -DECLARE_GLOBAL_DATA_PTR = (gd_t *) (CONFIG_SYS_INIT_GD_ADDR); - -/************************************************************************ - * Init Utilities * - ************************************************************************ - * Some of this code should be moved into the core functions, - * or dropped completely, - * but let's get it working (again) first... - */ -static int init_baudrate(void) -{ - gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE); - return 0; -} - -static int display_banner(void) -{ - - printf("\n\n%s\n\n", version_string); - - return 0; -} - -static int display_dram_config(void) -{ - int i; - - puts("DRAM Configuration:\n"); - - for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { - printf("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start); - print_size(gd->bd->bi_dram[i].size, "\n"); - } - - return 0; -} - -#ifndef CONFIG_SYS_NO_FLASH -static void display_flash_config(ulong size) -{ - puts("Flash: "); - print_size(size, "\n"); -} -#endif +#include <asm/init_helpers.h> +#include <asm/init_wrappers.h> /* * Breath some life into the board... * - * Initialize an SMC for serial comms, and carry out some hardware - * tests. + * Getting the board up and running is a three-stage process: + * 1) Execute from Flash, SDRAM Uninitialised + * At this point, there is a limited amount of non-SDRAM memory + * (typically the CPU cache, but can also be SRAM or even a buffer of + * of some peripheral). This limited memory is used to hold: + * - The initial copy of the Global Data Structure + * - A temporary stack + * - A temporary x86 Global Descriptor Table + * - The pre-console buffer (if enabled) + * + * The following is performed during this phase of execution: + * - Core low-level CPU initialisation + * - Console initialisation + * - SDRAM initialisation + * + * 2) Execute from Flash, SDRAM Initialised + * At this point we copy Global Data from the initial non-SDRAM + * memory and set up the permanent stack in SDRAM. The CPU cache is no + * longer being used as temporary memory, so we can now fully enable + * it. * - * The first part of initialization is running from Flash memory; - * its main purpose is to initialize the RAM so that we - * can relocate the monitor code to RAM. + * The following is performed during this phase of execution: + * - Create final stack in SDRAM + * - Copy Global Data from temporary memory to SDRAM + * - Enabling of CPU cache(s), + * - Copying of U-Boot code and data from Flash to RAM + * - Clearing of the BSS + * - ELF relocation adjustments + * + * 3) Execute from SDRAM + * The following is performed during this phase of execution: + * - All remaining initialisation */ /* - * All attempts to come up with a "common" initialization sequence - * that works for all boards and architectures failed: some of the - * requirements are just _too_ different. To get rid of the resulting - * mess of board dependend #ifdef'ed code we now make the whole - * initialization sequence configurable to the user. - * - * The requirements for any new initalization function is simple: it - * receives a pointer to the "global data" structure as it's only - * argument, and returns an integer return code, where 0 means - * "continue" and != 0 means "fatal error, hang the system". + * The requirements for any new initalization function is simple: it is + * a function with no parameters which returns an integer return code, + * where 0 means "continue" and != 0 means "fatal error, hang the system" */ typedef int (init_fnc_t) (void); -static int calculate_relocation_address(void); -static int copy_uboot_to_ram(void); -static int clear_bss(void); -static int do_elf_reloc_fixups(void); - +/* + * init_sequence_f is the list of init functions which are run when U-Boot + * is executing from Flash with a limited 'C' environment. The following + * limitations must be considered when implementing an '_f' function: + * - 'static' variables are read-only + * - Global Data (gd->xxx) is read/write + * - Stack space is limited + * + * The '_f' sequence must, as a minimum, initialise SDRAM. It _should_ + * also initialise the console (to provide early debug output) + */ init_fnc_t *init_sequence_f[] = { cpu_init_f, board_early_init_f, env_init, - init_baudrate, + init_baudrate_f, serial_init, console_init_f, dram_init_f, calculate_relocation_address, + + NULL, +}; + +/* + * init_sequence_f_r is the list of init functions which are run when + * U-Boot is executing from Flash with a semi-limited 'C' environment. + * The following limitations must be considered when implementing an + * '_f_r' function: + * - 'static' variables are read-only + * - Global Data (gd->xxx) is read/write + * + * The '_f_r' sequence must, as a minimum, copy U-Boot to RAM (if + * supported). It _should_, if possible, copy global data to RAM and + * initialise the CPU caches (to speed up the relocation process) + */ +init_fnc_t *init_sequence_f_r[] = { + copy_gd_to_ram_f_r, + init_cache_f_r, copy_uboot_to_ram, clear_bss, do_elf_reloc_fixups, @@ -145,339 +130,141 @@ init_fnc_t *init_sequence_f[] = { NULL, }; +/* + * init_sequence_r is the list of init functions which are run when U-Boot + * is executing from RAM with a full 'C' environment. There are no longer + * any limitations which must be considered when implementing an '_r' + * function, (i.e.'static' variables are read/write) + * + * If not already done, the '_r' sequence must copy global data to RAM and + * (should) initialise the CPU caches. + */ init_fnc_t *init_sequence_r[] = { - cpu_init_r, /* basic cpu dependent setup */ - board_early_init_r, /* basic board dependent setup */ - dram_init, /* configure available RAM banks */ - interrupt_init, /* set up exceptions */ + set_reloc_flag_r, + init_bd_struct_r, + mem_malloc_init_r, + cpu_init_r, + board_early_init_r, + dram_init, + interrupt_init, timer_init, display_banner, display_dram_config, - - NULL, -}; - -gd_t *gd; - -static int calculate_relocation_address(void) -{ - ulong text_start = (ulong)&__text_start; - ulong bss_end = (ulong)&__bss_end; - ulong dest_addr; - ulong rel_offset; - - /* Calculate destination RAM Address and relocation offset */ - dest_addr = gd->ram_size; - dest_addr -= CONFIG_SYS_STACK_SIZE; - dest_addr -= (bss_end - text_start); - - /* - * Round destination address down to 16-byte boundary to keep - * IDT and GDT 16-byte aligned - */ - dest_addr &= ~15; - - rel_offset = dest_addr - text_start; - - gd->start_addr_sp = gd->ram_size; - gd->relocaddr = dest_addr; - gd->reloc_off = rel_offset; - - return 0; -} - -static int copy_uboot_to_ram(void) -{ - ulong *dst_addr = (ulong *)gd->relocaddr; - ulong *src_addr = (ulong *)&__text_start; - ulong *end_addr = (ulong *)&__data_end; - - while (src_addr < end_addr) - *dst_addr++ = *src_addr++; - - return 0; -} - -static int clear_bss(void) -{ - void *bss_start = &__bss_start; - void *bss_end = &__bss_end; - - ulong *dst_addr = (ulong *)(bss_start + gd->reloc_off); - ulong *end_addr = (ulong *)(bss_end + gd->reloc_off); - - while (dst_addr < end_addr) - *dst_addr++ = 0x00000000; - - return 0; -} - -static int do_elf_reloc_fixups(void) -{ - Elf32_Rel *re_src = (Elf32_Rel *)(&__rel_dyn_start); - Elf32_Rel *re_end = (Elf32_Rel *)(&__rel_dyn_end); - - Elf32_Addr *offset_ptr_rom; - Elf32_Addr *offset_ptr_ram; - - /* The size of the region of u-boot that runs out of RAM. */ - uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start; - - do { - /* Get the location from the relocation entry */ - offset_ptr_rom = (Elf32_Addr *)re_src->r_offset; - - /* Check that the location of the relocation is in .text */ - if (offset_ptr_rom >= (Elf32_Addr *)CONFIG_SYS_TEXT_BASE) { - - /* Switch to the in-RAM version */ - offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom + - gd->reloc_off); - - /* Check that the target points into .text */ - if (*offset_ptr_ram >= CONFIG_SYS_TEXT_BASE && - *offset_ptr_ram < - (CONFIG_SYS_TEXT_BASE + size)) { - *offset_ptr_ram += gd->reloc_off; - } - } - } while (re_src++ < re_end); - - return 0; -} - -/* Load U-Boot into RAM, initialize BSS, perform relocation adjustments */ -void board_init_f(ulong boot_flags) -{ - init_fnc_t **init_fnc_ptr; - - gd->flags = boot_flags; - - for (init_fnc_ptr = init_sequence_f; *init_fnc_ptr; ++init_fnc_ptr) { - if ((*init_fnc_ptr)() != 0) - hang(); - } - - gd->flags |= GD_FLG_RELOC; - - /* Enter the relocated U-Boot! */ - relocate_code(gd->start_addr_sp, gd, gd->relocaddr); - - /* NOTREACHED - relocate_code() does not return */ - while (1) - ; -} - -void board_init_r(gd_t *id, ulong dest_addr) -{ -#if defined(CONFIG_CMD_NET) - char *s; -#endif -#ifndef CONFIG_SYS_NO_FLASH - ulong size; -#endif - static bd_t bd_data; - static gd_t gd_data; - init_fnc_t **init_fnc_ptr; - - show_boot_progress(0x21); - - /* Global data pointer is now writable */ - gd = &gd_data; - memcpy(gd, id, sizeof(gd_t)); - - /* compiler optimization barrier needed for GCC >= 3.4 */ - __asm__ __volatile__("" : : : "memory"); - - gd->bd = &bd_data; - memset(gd->bd, 0, sizeof(bd_t)); - show_boot_progress(0x22); - - gd->baudrate = CONFIG_BAUDRATE; - - mem_malloc_init((((ulong)dest_addr - CONFIG_SYS_MALLOC_LEN)+3)&~3, - CONFIG_SYS_MALLOC_LEN); - - for (init_fnc_ptr = init_sequence_r; *init_fnc_ptr; ++init_fnc_ptr) { - if ((*init_fnc_ptr)() != 0) - hang(); - } - show_boot_progress(0x23); - #ifdef CONFIG_SERIAL_MULTI - serial_initialize(); + serial_initialize_r, #endif - #ifndef CONFIG_SYS_NO_FLASH - /* configure available FLASH banks */ - size = flash_init(); - display_flash_config(size); - show_boot_progress(0x24); + flash_init_r, #endif - - show_boot_progress(0x25); - - /* initialize environment */ - env_relocate(); - show_boot_progress(0x26); - - + env_relocate_r, #ifdef CONFIG_CMD_NET - /* IP Address */ - bd_data.bi_ip_addr = getenv_IPaddr("ipaddr"); + init_ip_address_r, #endif - -#if defined(CONFIG_PCI) - /* - * Do pci configuration - */ - pci_init(); +#ifdef CONFIG_PCI + pci_init_r, #endif - - show_boot_progress(0x27); - - - stdio_init(); - - jumptable_init(); - - /* Initialize the console (after the relocation and devices init) */ - console_init_r(); - + stdio_init, + jumptable_init_r, + console_init_r, #ifdef CONFIG_MISC_INIT_R - /* miscellaneous platform dependent initialisations */ - misc_init_r(); + misc_init_r, #endif - #if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE) - WATCHDOG_RESET(); - puts("PCMCIA:"); - pcmcia_init(); + pci_init_r, #endif - #if defined(CONFIG_CMD_KGDB) - WATCHDOG_RESET(); - puts("KGDB: "); - kgdb_init(); + kgdb_init_r, #endif - - /* enable exceptions */ - enable_interrupts(); - show_boot_progress(0x28); - + enable_interrupts_r, #ifdef CONFIG_STATUS_LED - status_led_set(STATUS_LED_BOOT, STATUS_LED_BLINKING); + status_led_set_r, #endif - - udelay(20); - - /* Initialize from environment */ - load_addr = getenv_ulong("loadaddr", 16, load_addr); + set_load_addr_r, #if defined(CONFIG_CMD_NET) - s = getenv("bootfile"); - - if (s != NULL) - copy_filename(BootFile, s, sizeof(BootFile)); + set_bootfile_r, #endif - - WATCHDOG_RESET(); - #if defined(CONFIG_CMD_IDE) - WATCHDOG_RESET(); - puts("IDE: "); - ide_init(); + ide_init_r, #endif - #if defined(CONFIG_CMD_SCSI) - WATCHDOG_RESET(); - puts("SCSI: "); - scsi_init(); + scsi_init_r, #endif - #if defined(CONFIG_CMD_DOC) - WATCHDOG_RESET(); - puts("DOC: "); - doc_init(); + doc_init_r, #endif - #ifdef CONFIG_BITBANGMII - bb_miiphy_init(); + bb_miiphy_init_r, #endif #if defined(CONFIG_CMD_NET) - WATCHDOG_RESET(); - puts("Net: "); - eth_initialize(gd->bd); + eth_initialize_r, +#ifdef CONFIG_RESET_PHY_R + reset_phy_r, #endif - -#if (defined(CONFIG_CMD_NET)) && (0) - WATCHDOG_RESET(); -# ifdef DEBUG - puts("Reset Ethernet PHY\n"); -# endif - reset_phy(); #endif - #ifdef CONFIG_LAST_STAGE_INIT - WATCHDOG_RESET(); - /* - * Some parts can be only initialized if all others (like - * Interrupts) are up and running (i.e. the PC-style ISA - * keyboard). - */ - last_stage_init(); + last_stage_init, #endif + NULL, +}; +static void do_init_loop(init_fnc_t **init_fnc_ptr) +{ + for (; *init_fnc_ptr; ++init_fnc_ptr) { + WATCHDOG_RESET(); + if ((*init_fnc_ptr)() != 0) + hang(); + } +} -#ifdef CONFIG_POST - post_run(NULL, POST_RAM | post_bootmode_get(0)); -#endif - - show_boot_progress(0x29); +void board_init_f(ulong boot_flags) +{ + gd->flags = boot_flags; - /* main_loop() can return to retry autoboot, if so just run it again. */ - for (;;) - main_loop(); + do_init_loop(init_sequence_f); - /* NOTREACHED - no way out of command loop except booting */ -} + /* + * SDRAM and console are now initialised. The final stack can now + * be setup in SDRAM. Code execution will continue in Flash, but + * with the stack in SDRAM and Global Data in temporary memory + * (CPU cache) + */ + board_init_f_r_trampoline(gd->start_addr_sp); -void hang(void) -{ - puts("### ERROR ### Please RESET the board ###\n"); - for (;;) + /* NOTREACHED - board_init_f_r_trampoline() does not return */ + while (1) ; } -unsigned long do_go_exec(ulong (*entry)(int, char * const []), - int argc, char * const argv[]) +void board_init_f_r(void) { - unsigned long ret = 0; - char **argv_tmp; + do_init_loop(init_sequence_f_r); /* - * x86 does not use a dedicated register to pass the pointer to - * the global_data, so it is instead passed as argv[-1]. By using - * argv[-1], the called 'Application' can use the contents of - * argv natively. However, to safely use argv[-1] a new copy of - * argv is needed with the extra element + * U-Boot has been copied into SDRAM, the BSS has been cleared etc. + * Transfer execution from Flash to RAM by calculating the address + * of the in-RAM copy of board_init_r() and calling it */ - argv_tmp = malloc(sizeof(char *) * (argc + 1)); + (board_init_r + gd->reloc_off)(gd, gd->relocaddr); - if (argv_tmp) { - argv_tmp[0] = (char *)gd; + /* NOTREACHED - board_init_r() does not return */ + while (1) + ; +} - memcpy(&argv_tmp[1], argv, (size_t)(sizeof(char *) * argc)); +void board_init_r(gd_t *id, ulong dest_addr) +{ + do_init_loop(init_sequence_r); - ret = (entry) (argc, &argv_tmp[1]); - free(argv_tmp); - } + /* main_loop() can return to retry autoboot, if so just run it again. */ + for (;;) + main_loop(); - return ret; + /* NOTREACHED - no way out of command loop except booting */ } -void setup_pcat_compatibility(void) - __attribute__((weak, alias("__setup_pcat_compatibility"))); - -void __setup_pcat_compatibility(void) +void hang(void) { + puts("### ERROR ### Please RESET the board ###\n"); + for (;;) + ; } diff --git a/arch/x86/lib/cmd_boot.c b/arch/x86/lib/cmd_boot.c new file mode 100644 index 00000000000..a81a9a38a62 --- /dev/null +++ b/arch/x86/lib/cmd_boot.c @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2008-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <malloc.h> +#include <asm/u-boot-x86.h> + +unsigned long do_go_exec(ulong (*entry)(int, char * const []), + int argc, char * const argv[]) +{ + unsigned long ret = 0; + char **argv_tmp; + + /* + * x86 does not use a dedicated register to pass the pointer to + * the global_data, so it is instead passed as argv[-1]. By using + * argv[-1], the called 'Application' can use the contents of + * argv natively. However, to safely use argv[-1] a new copy of + * argv is needed with the extra element + */ + argv_tmp = malloc(sizeof(char *) * (argc + 1)); + + if (argv_tmp) { + argv_tmp[0] = (char *)gd; + + memcpy(&argv_tmp[1], argv, (size_t)(sizeof(char *) * argc)); + + ret = (entry) (argc, &argv_tmp[1]); + free(argv_tmp); + } + + return ret; +} diff --git a/arch/x86/lib/init_helpers.c b/arch/x86/lib/init_helpers.c new file mode 100644 index 00000000000..9f4dee034f9 --- /dev/null +++ b/arch/x86/lib/init_helpers.c @@ -0,0 +1,217 @@ +/* + * (C) Copyright 2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#include <command.h> +#include <stdio_dev.h> +#include <version.h> +#include <malloc.h> +#include <net.h> +#include <ide.h> +#include <serial.h> +#include <status_led.h> +#include <asm/processor.h> +#include <asm/u-boot-x86.h> + +#include <asm/init_helpers.h> + +DECLARE_GLOBAL_DATA_PTR; + +/************************************************************************ + * Init Utilities * + ************************************************************************ + * Some of this code should be moved into the core functions, + * or dropped completely, + * but let's get it working (again) first... + */ + +int display_banner(void) +{ + printf("\n\n%s\n\n", version_string); + + return 0; +} + +int display_dram_config(void) +{ + int i; + + puts("DRAM Configuration:\n"); + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + printf("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start); + print_size(gd->bd->bi_dram[i].size, "\n"); + } + + return 0; +} + +int init_baudrate_f(void) +{ + gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE); + return 0; +} + +int calculate_relocation_address(void) +{ + ulong text_start = (ulong)&__text_start; + ulong bss_end = (ulong)&__bss_end; + ulong dest_addr; + + /* + * NOTE: All destination address are rounded down to 16-byte + * boundary to satisfy various worst-case alignment + * requirements + */ + + /* Global Data is at top of available memory */ + dest_addr = gd->ram_size; + dest_addr -= GENERATED_GBL_DATA_SIZE; + dest_addr &= ~15; + gd->new_gd_addr = dest_addr; + + /* GDT is below Global Data */ + dest_addr -= X86_GDT_SIZE; + dest_addr &= ~15; + gd->gdt_addr = dest_addr; + + /* Stack is below GDT */ + gd->start_addr_sp = dest_addr; + + /* U-Boot is below the stack */ + dest_addr -= CONFIG_SYS_STACK_SIZE; + dest_addr -= (bss_end - text_start); + dest_addr &= ~15; + gd->relocaddr = dest_addr; + gd->reloc_off = (dest_addr - text_start); + + return 0; +} + +int copy_gd_to_ram_f_r(void) +{ + gd_t *ram_gd; + + /* + * Global data is still in temporary memory (the CPU cache). + * calculate_relocation_address() has set gd->new_gd_addr to + * where the global data lives in RAM but getting it there + * safely is a bit tricky due to the 'F-Segment Hack' that + * we need to use for x86 + */ + ram_gd = (gd_t *)gd->new_gd_addr; + memcpy((void *)ram_gd, gd, sizeof(gd_t)); + + /* + * Reload the Global Descriptor Table so FS points to the + * in-RAM copy of Global Data (calculate_relocation_address() + * has already calculated the in-RAM location of the GDT) + */ + ram_gd->gd_addr = (ulong)ram_gd; + init_gd(ram_gd, (u64 *)gd->gdt_addr); + + return 0; +} + +int init_cache_f_r(void) +{ + /* Initialise the CPU cache(s) */ + return init_cache(); +} + +int set_reloc_flag_r(void) +{ + gd->flags = GD_FLG_RELOC; + + return 0; +} + +int mem_malloc_init_r(void) +{ + mem_malloc_init(((gd->relocaddr - CONFIG_SYS_MALLOC_LEN)+3)&~3, + CONFIG_SYS_MALLOC_LEN); + + return 0; +} + +bd_t bd_data; + +int init_bd_struct_r(void) +{ + gd->bd = &bd_data; + memset(gd->bd, 0, sizeof(bd_t)); + + return 0; +} + +#ifndef CONFIG_SYS_NO_FLASH +int flash_init_r(void) +{ + ulong size; + + puts("Flash: "); + + /* configure available FLASH banks */ + size = flash_init(); + + print_size(size, "\n"); + + return 0; +} +#endif + +int init_ip_address_r(void) +{ + /* IP Address */ + bd_data.bi_ip_addr = getenv_IPaddr("ipaddr"); + + return 0; +} + +#ifdef CONFIG_STATUS_LED +int status_led_set_r(void) +{ + status_led_set(STATUS_LED_BOOT, STATUS_LED_BLINKING); + + return 0; +} +#endif + +int set_bootfile_r(void) +{ + char *s; + + s = getenv("bootfile"); + + if (s != NULL) + copy_filename(BootFile, s, sizeof(BootFile)); + + return 0; +} + +int set_load_addr_r(void) +{ + /* Initialize from environment */ + load_addr = getenv_ulong("loadaddr", 16, load_addr); + + return 0; +} diff --git a/arch/x86/lib/init_wrappers.c b/arch/x86/lib/init_wrappers.c new file mode 100644 index 00000000000..71449fe6fa4 --- /dev/null +++ b/arch/x86/lib/init_wrappers.c @@ -0,0 +1,137 @@ +/* + * (C) Copyright 2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#include <serial.h> +#include <kgdb.h> +#include <scsi.h> +#include <post.h> +#include <miiphy.h> + +#include <asm/init_wrappers.h> + +int serial_initialize_r(void) +{ + serial_initialize(); + + return 0; +} + +int env_relocate_r(void) +{ + /* initialize environment */ + env_relocate(); + + return 0; +} + + +int pci_init_r(void) +{ + /* Do pci configuration */ + pci_init(); + + return 0; +} + +int jumptable_init_r(void) +{ + jumptable_init(); + + return 0; +} + +int pcmcia_init_r(void) +{ + puts("PCMCIA:"); + pcmcia_init(); + + return 0; +} + +int kgdb_init_r(void) +{ + puts("KGDB: "); + kgdb_init(); + + return 0; +} + +int enable_interrupts_r(void) +{ + /* enable exceptions */ + enable_interrupts(); + + return 0; +} + +int eth_initialize_r(void) +{ + puts("Net: "); + eth_initialize(gd->bd); + + return 0; +} + +int reset_phy_r(void) +{ +#ifdef DEBUG + puts("Reset Ethernet PHY\n"); +#endif + reset_phy(); + + return 0; +} + +int ide_init_r(void) +{ + puts("IDE: "); + ide_init(); + + return 0; +} + +int scsi_init_r(void) +{ + puts("SCSI: "); + scsi_init(); + + return 0; +} + +#ifdef CONFIG_BITBANGMII +int bb_miiphy_init_r(void) +{ + bb_miiphy_init(); + + return 0; +} +#endif + +#ifdef CONFIG_POST +int post_run_r(void) +{ + post_run(NULL, POST_RAM | post_bootmode_get(0)); + + return 0; +} +#endif diff --git a/arch/x86/lib/realmode_switch.S b/arch/x86/lib/realmode_switch.S index 7ee709a8b45..c4c4c4378e9 100644 --- a/arch/x86/lib/realmode_switch.S +++ b/arch/x86/lib/realmode_switch.S @@ -44,12 +44,13 @@ * e40 ss; */ -#define a32 .byte 0x67; /* address size prefix 32 */ -#define o32 .byte 0x66; /* operand size prefix 32 */ +#define a32 .byte 0x67; /* address size prefix 32 */ +#define o32 .byte 0x66; /* operand size prefix 32 */ .section .realmode, "ax" .code16 - /* 16bit protected mode code here */ + + /* 16bit protected mode code here */ .globl realmode_enter realmode_enter: o32 pusha @@ -69,20 +70,23 @@ o32 pushf movw %ax, %gs lidt realmode_idt_ptr - movl %cr0, %eax /* Go back into real mode by */ - andl $0x7ffffffe, %eax /* clearing PE to 0 */ + /* Go back into real mode by clearing PE to 0 */ + movl %cr0, %eax + andl $0x7ffffffe, %eax movl %eax, %cr0 - ljmp $0x0,$do_realmode /* switch to real mode */ -do_realmode: /* realmode code from here */ + /* switch to real mode */ + ljmp $0x0,$do_realmode + +do_realmode: + /* realmode code from here */ movw %cs,%ax movw %ax,%ds movw %ax,%es movw %ax,%fs movw %ax,%gs - /* create a temporary stack */ - + /* create a temporary stack */ movw $0xc0, %ax movw %ax, %ss movw $0x200, %ax @@ -114,26 +118,29 @@ o32 popf popw %ss movl %eax, %esp cs movl temp_eax, %eax - wbinvd /* self-modifying code, - * better flush the cache */ + + /* self-modifying code, better flush the cache */ + wbinvd .byte 0x9a /* lcall */ temp_ip: .word 0 /* new ip */ temp_cs: .word 0 /* new cs */ + realmode_ret: - /* save eax, esp and ss */ + /* save eax, esp and ss */ cs movl %eax, saved_eax movl %esp, %eax cs movl %eax, saved_esp movw %ss, %ax cs movw %ax, saved_ss - /* restore the stack, note that we set sp to 0x244; + /* + * restore the stack, note that we set sp to 0x244; * pt_regs is 0x44 bytes long and we push the structure - * backwards on to the stack, bottom first */ - + * backwards on to the stack, bottom first + */ movw $0xc0, %ax movw %ax, %ss movw $0x244, %ax @@ -169,12 +176,15 @@ cs movw temp_ip, %ax pushl %ebx o32 cs lidt saved_idt -o32 cs lgdt saved_gdt /* Set GDTR */ +o32 cs lgdt saved_gdt - movl %cr0, %eax /* Go back into protected mode */ - orl $1,%eax /* reset PE to 1 */ + /* Go back into protected mode reset PE to 1 */ + movl %cr0, %eax + orl $1,%eax movl %eax, %cr0 - jmp next_line /* flush prefetch queue */ + + /* flush prefetch queue */ + jmp next_line next_line: movw $return_ptr, %ax movw %ax,%bp @@ -182,12 +192,13 @@ o32 cs ljmp *(%bp) .code32 protected_mode: - movl $0x18,%eax /* reload GDT[3] */ - movw %ax,%fs /* reset FS */ - movw %ax,%ds /* reset DS */ - movw %ax,%gs /* reset GS */ - movw %ax,%es /* reset ES */ - movw %ax,%ss /* reset SS */ + /* Reload segment registers */ + movl $0x18, %eax + movw %ax, %fs + movw %ax, %ds + movw %ax, %gs + movw %ax, %es + movw %ax, %ss movl saved_protected_mode_esp, %eax movl %eax, %esp popf diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c new file mode 100644 index 00000000000..200baaba6a2 --- /dev/null +++ b/arch/x86/lib/relocate.c @@ -0,0 +1,91 @@ +/* + * (C) Copyright 2008-2011 + * Graeme Russ, <graeme.russ@gmail.com> + * + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se> + * + * (C) Copyright 2002 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <malloc.h> +#include <asm/u-boot-x86.h> +#include <asm/relocate.h> +#include <elf.h> + +int copy_uboot_to_ram(void) +{ + size_t len = (size_t)&__data_end - (size_t)&__text_start; + + memcpy((void *)gd->relocaddr, (void *)&__text_start, len); + + return 0; +} + +int clear_bss(void) +{ + ulong dst_addr = (ulong)&__bss_start + gd->reloc_off; + size_t len = (size_t)&__bss_end - (size_t)&__bss_start; + + memset((void *)dst_addr, 0x00, len); + + return 0; +} + +int do_elf_reloc_fixups(void) +{ + Elf32_Rel *re_src = (Elf32_Rel *)(&__rel_dyn_start); + Elf32_Rel *re_end = (Elf32_Rel *)(&__rel_dyn_end); + + Elf32_Addr *offset_ptr_rom; + Elf32_Addr *offset_ptr_ram; + + /* The size of the region of u-boot that runs out of RAM. */ + uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start; + + do { + /* Get the location from the relocation entry */ + offset_ptr_rom = (Elf32_Addr *)re_src->r_offset; + + /* Check that the location of the relocation is in .text */ + if (offset_ptr_rom >= (Elf32_Addr *)CONFIG_SYS_TEXT_BASE) { + + /* Switch to the in-RAM version */ + offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom + + gd->reloc_off); + + /* Check that the target points into .text */ + if (*offset_ptr_ram >= CONFIG_SYS_TEXT_BASE && + *offset_ptr_ram < + (CONFIG_SYS_TEXT_BASE + size)) { + *offset_ptr_ram += gd->reloc_off; + } + } + } while (re_src++ < re_end); + + return 0; +} diff --git a/arch/x86/lib/string.c b/arch/x86/lib/string.c index f2ea7e4e338..1fde81b8b76 100644 --- a/arch/x86/lib/string.c +++ b/arch/x86/lib/string.c @@ -85,3 +85,64 @@ void *memset(void *dstpp, int c, size_t len) return dstpp; } + +#define OP_T_THRES 8 +#define OPSIZ (sizeof(op_t)) + +#define BYTE_COPY_FWD(dst_bp, src_bp, nbytes) \ +do { \ + int __d0; \ + asm volatile( \ + /* Clear the direction flag, so copying goes forward. */ \ + "cld\n" \ + /* Copy bytes. */ \ + "rep\n" \ + "movsb" : \ + "=D" (dst_bp), "=S" (src_bp), "=c" (__d0) : \ + "0" (dst_bp), "1" (src_bp), "2" (nbytes) : \ + "memory"); \ +} while (0) + +#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) \ +do { \ + int __d0; \ + asm volatile( \ + /* Clear the direction flag, so copying goes forward. */ \ + "cld\n" \ + /* Copy longwords. */ \ + "rep\n" \ + "movsl" : \ + "=D" (dst_bp), "=S" (src_bp), "=c" (__d0) : \ + "0" (dst_bp), "1" (src_bp), "2" ((nbytes) / 4) : \ + "memory"); \ + (nbytes_left) = (nbytes) % 4; \ +} while (0) + +void *memcpy(void *dstpp, const void *srcpp, size_t len) +{ + unsigned long int dstp = (long int)dstpp; + unsigned long int srcp = (long int)srcpp; + + /* Copy from the beginning to the end. */ + + /* If there not too few bytes to copy, use word copy. */ + if (len >= OP_T_THRES) { + /* Copy just a few bytes to make DSTP aligned. */ + len -= (-dstp) % OPSIZ; + BYTE_COPY_FWD(dstp, srcp, (-dstp) % OPSIZ); + + /* Copy from SRCP to DSTP taking advantage of the known + * alignment of DSTP. Number of bytes remaining is put + * in the third argument, i.e. in LEN. This number may + * vary from machine to machine. + */ + WORD_COPY_FWD(dstp, srcp, len, len); + + /* Fall out and copy the tail. */ + } + + /* There are just a few bytes to copy. Use byte memory operations. */ + BYTE_COPY_FWD(dstp, srcp, len); + + return dstpp; +} diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index bb405171772..22142864c22 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -314,6 +314,13 @@ void boot_zimage(void *setup_base, void *load_address) #endif } +void setup_pcat_compatibility(void) + __attribute__((weak, alias("__setup_pcat_compatibility"))); + +void __setup_pcat_compatibility(void) +{ +} + int do_zboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { struct boot_params *base_ptr; |