From 33de3b2fb58f8dfe304397d1f0f5d84bfd731c56 Mon Sep 17 00:00:00 2001 From: Carl-Daniel Hailfinger Date: Thu, 16 Oct 2008 03:00:28 +0000 Subject: [PATCH] Right now we face the problem that we can't support processors which have a CAR area outside the usual RAM area. For those processors, we have to implement a stack copying and switching mechanism. Since gcc can't be told that the stack just moved, split stage1_main() into stage1_phase1() and stage1_phase2() and stage1_phase3(). stage1_phase1() is the new entry point in stage1 and will handle everything up to the point where we want to disable CAR. Switching the stack, disabling CAR and handling other tasks related to the stack switch (printk buffer move) is all wrapped in the stage1_phase2() function. stage1_phase2() calls disable_car() which then calls stage1_phase3(). stage1_phase3() is the former second half of stage1_main(). Notes about this patch: - Code flow is almost unchanged for Qemu, K8 and Geode. No extensive new testing required. - We can support stack-keeping and stack-relocating architectures at the same time, so C7 is definitely supportable - The comment in stage1_phase2 says "some of this is not yet done". That refers to the nonexisting code for stack switching on C7. - "Minimal changes, maximum benefit". Signed-off-by: Carl-Daniel Hailfinger Acked-by: Ronald G. Minnich git-svn-id: svn://coreboot.org/repository/coreboot-v3@932 f3766cd6-281f-0410-b1cd-43a5c92072e9 --- arch/x86/amd/k8/stage1.c | 2 + arch/x86/amd/stage0.S | 2 +- arch/x86/geodelx/stage0.S | 2 +- arch/x86/geodelx/stage1.c | 2 + arch/x86/i586/stage0.S | 2 +- arch/x86/stage1.c | 86 +++++++++++++++++++++------ arch/x86/via/stage0.S | 2 +- doc/design/newboot.lyx | 2 +- include/arch/x86/stage1.h | 2 + mainboard/emulation/qemu-x86/stage1.c | 3 + 10 files changed, 81 insertions(+), 24 deletions(-) create mode 100644 include/arch/x86/stage1.h diff --git a/arch/x86/amd/k8/stage1.c b/arch/x86/amd/k8/stage1.c index c729de262f..0bed559dc2 100644 --- a/arch/x86/amd/k8/stage1.c +++ b/arch/x86/amd/k8/stage1.c @@ -26,6 +26,7 @@ #include #include #include +#include /** * Set the MTRR for initial ram access. @@ -73,4 +74,5 @@ void disable_car(void) /* we're now running in ram. Although this will be called again, it does no harm to call it here. */ set_init_ram_access(); banner(BIOS_DEBUG, "disable_car: done"); + stage1_phase3(); } diff --git a/arch/x86/amd/stage0.S b/arch/x86/amd/stage0.S index dc691ec35a..6a8aeb594e 100644 --- a/arch/x86/amd/stage0.S +++ b/arch/x86/amd/stage0.S @@ -341,7 +341,7 @@ CAR_FAM10_ap_out: pushl %ebx /* First parameter: bist */ pushl %eax - call stage1_main + call stage1_phase1 /* We will not go back. */ movb $0xAF, %al /* Should never see this postcode */ diff --git a/arch/x86/geodelx/stage0.S b/arch/x86/geodelx/stage0.S index c3c1d7318f..4f3a230b7e 100644 --- a/arch/x86/geodelx/stage0.S +++ b/arch/x86/geodelx/stage0.S @@ -271,7 +271,7 @@ lout: pushl $0 /* First parameter: bist */ pushl %eax - call stage1_main + call stage1_phase1 /* We will not go back. */ #include "../stage0_common.S" diff --git a/arch/x86/geodelx/stage1.c b/arch/x86/geodelx/stage1.c index 443a7f773d..48e08ba914 100644 --- a/arch/x86/geodelx/stage1.c +++ b/arch/x86/geodelx/stage1.c @@ -24,6 +24,7 @@ #include #include #include +#include static const struct msrinit msr_table[] = { /* Setup access to cache under 1MB. */ @@ -93,4 +94,5 @@ void disable_car(void) banner(BIOS_DEBUG, "Disable_car: done wbinvd"); northbridge_init_early(); banner(BIOS_DEBUG, "disable_car: done"); + stage1_phase3(); } diff --git a/arch/x86/i586/stage0.S b/arch/x86/i586/stage0.S index 6b89749810..668420c6a4 100644 --- a/arch/x86/i586/stage0.S +++ b/arch/x86/i586/stage0.S @@ -339,7 +339,7 @@ lout: pushl $0 /* First parameter: bist */ pushl %eax - call stage1_main + call stage1_phase1 /* We will not go back. */ fixed_mtrr_msr: diff --git a/arch/x86/stage1.c b/arch/x86/stage1.c index 5defdfdce6..ce3d24c135 100644 --- a/arch/x86/stage1.c +++ b/arch/x86/stage1.c @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef CONFIG_PAYLOAD_ELF_LOADER /* ah, well, what a mess! This is a hard code. FIX ME but how? @@ -154,28 +155,12 @@ static int run_address_multiboot(void *f) * that we are restarting after some sort of reconfiguration. Note that we could use it on geode but * do not at present. */ -void __attribute__((stdcall)) stage1_main(u32 bist, u32 init_detected) +void __attribute__((stdcall)) stage1_phase1(u32 bist, u32 init_detected) { struct global_vars globvars; int ret; struct mem_file archive; - void *entry; struct node_core_id me; -#ifdef CONFIG_PAYLOAD_ELF_LOADER - struct mem_file result; - int elfboot_mem(struct lb_memory *mem, void *where, int size); - - /* Why can't we statically init this hack? */ - unsigned char faker[64]; - struct lb_memory *mem = (struct lb_memory*) faker; - - mem->tag = LB_TAG_MEMORY; - mem->size = 28; - mem->map[0].start.lo = mem->map[0].start.hi = 0; - mem->map[0].size.lo = (32*1024*1024); - mem->map[0].size.hi = 0; - mem->map[0].type = LB_MEM_RAM; -#endif /* CONFIG_PAYLOAD_ELF_LOADER */ post_code(POST_STAGE1_MAIN); @@ -234,13 +219,76 @@ void __attribute__((stdcall)) stage1_main(u32 bist, u32 init_detected) printk(BIOS_DEBUG, "Done RAM init code\n"); - /* Turn off Cache-As-Ram */ - disable_car(); + /* Switch the stack location from CAR to RAM, rebuild the stack, + * disable CAR and continue at stage1_phase3(). This is all wrapped in + * stage1_phase2() to make the code easier to follow. + * We will NEVER return. + */ + stage1_phase2(); + /* If we reach this point, something went terribly wrong. */ + die("The world is broken.\n"); +} + +/** + * This function is called to take care of switching and rebuilding the stack + * so that we can cope with processors which don't support a CAR area at low + * addresses where CAR could be copied to RAM without problems. + * This function handles everything related to switching off CAR and moving + * important data from CAR to RAM. + * 1. Perform all work which can be done while CAR and RAM are both active. + * That's mainly moving the printk buffer around. + * 2a. Optionally back up the new stack location (desirable for S3). + * 2b. Optionally rebuild the stack at another location. + * 2c. Switch stack pointer to the new stack if the stack was rebuilt. + * 3. Disable CAR. + * 4. Call or jump to stage1_phase3. + * Steps 2a-4 have to be done in asm. That's what the oddly named disable_car() + * function does. + * + * TODO: Some parts of the list above are not yet done, so the code will not + * yet work on C7. + */ +void stage1_phase2() +{ #ifdef CONFIG_CONSOLE_BUFFER /* Move the printk buffer to PRINTK_BUF_ADDR_RAM */ printk_buffer_move((void *)PRINTK_BUF_ADDR_RAM, PRINTK_BUF_SIZE_RAM); #endif + /* Turn off Cache-As-Ram */ + disable_car(); + + /* If we reach this point, something went terribly wrong. */ + die("The world is broken.\n"); +} + +/** + * This function is the second part of the former stage1_main() after + * switching the stack and disabling CAR. + */ +void __attribute__((stdcall)) stage1_phase3() +{ + void *entry; + int ret; + struct mem_file archive; +#ifdef CONFIG_PAYLOAD_ELF_LOADER + struct mem_file result; + int elfboot_mem(struct lb_memory *mem, void *where, int size); + + /* Why can't we statically init this hack? */ + unsigned char faker[64]; + struct lb_memory *mem = (struct lb_memory*) faker; + + mem->tag = LB_TAG_MEMORY; + mem->size = 28; + mem->map[0].start.lo = mem->map[0].start.hi = 0; + mem->map[0].size.lo = (32*1024*1024); + mem->map[0].size.hi = 0; + mem->map[0].type = LB_MEM_RAM; +#endif /* CONFIG_PAYLOAD_ELF_LOADER */ + + // location and size of image. + init_archive(&archive); entry = load_file_segments(&archive, "normal/stage2"); if (entry == (void *)-1) diff --git a/arch/x86/via/stage0.S b/arch/x86/via/stage0.S index 9a30dfce3e..59f129de39 100644 --- a/arch/x86/via/stage0.S +++ b/arch/x86/via/stage0.S @@ -189,7 +189,7 @@ lout: pushl $0 /* First parameter: bist */ pushl %eax - call stage1_main + call stage1_phase1 /* We will not go back. */ fixed_mtrr_msr: diff --git a/doc/design/newboot.lyx b/doc/design/newboot.lyx index 51921db17c..e113c1c8d1 100644 --- a/doc/design/newboot.lyx +++ b/doc/design/newboot.lyx @@ -759,7 +759,7 @@ Stage 1: C, in arch/{architecture} \end_layout \begin_layout Standard -Initial entry point for stage 1 is arch/{architecture}/stage1.c:stage1_main(). +Initial entry point for stage 1 is arch/{architecture}/stage1.c:stage1_phase1(). \end_layout \begin_layout Standard diff --git a/include/arch/x86/stage1.h b/include/arch/x86/stage1.h new file mode 100644 index 0000000000..034670552f --- /dev/null +++ b/include/arch/x86/stage1.h @@ -0,0 +1,2 @@ +void stage1_phase2(void); +void __attribute__((stdcall)) stage1_phase3(void); diff --git a/mainboard/emulation/qemu-x86/stage1.c b/mainboard/emulation/qemu-x86/stage1.c index 742050872a..0ed9eb7dbe 100644 --- a/mainboard/emulation/qemu-x86/stage1.c +++ b/mainboard/emulation/qemu-x86/stage1.c @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + /* printk() will not yet output anything. */ /** @@ -34,6 +36,7 @@ void stop_ap(void) void disable_car(void) { + stage1_phase3(); }