Here is a version I put together yesterday as a straw main.

summary:

stage1_main is now split into stage0_main and main(). stage0_main runs
up to and including initram. It then calls disable_car.

disable_car does what it does now:
copy CAR stack to ram stack, disable car,
BUT:
instead of a ret, it does a ljmp to main.

very little of disable_car has to change since we already copy stack
to stack. We do need a new
constant, RAM_STACK, or some such, so we know where stack goes in RAM.

I don't see a need for swtich_stack, since disable_car pretty much
does that now -- it copies stacks, and all it need do is change %esp.

main is main. It calls everything else.
I don't like names like xxx_eary and xxx_late-- they don't convey enough
information. main() calls stage2 and payload and, later, code to load
microcode (needed on k10) and possibly
code to set up the resource maps (k8 and k10).

We should move the LAR pointer into
global variables so it will be find-able after disable_car. We should
not call the LAR init twice.

The bottom_of_stack will now work for any stack, not just CAR
stack.Given a properly aligned stack
it will always work.

This will fix issues with via and intel.

ron
/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2007 Stefan Reinauer <[EMAIL PROTECTED]>
 * Copyright (C) 2007 Advanced Micro Devices, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */

#include <types.h>
#include <io.h>
#include <console.h>
#include <cpu.h>
#include <globalvars.h>
#include <lar.h>
#include <string.h>
#include <tables.h>
#include <lib.h>
#include <mc146818rtc.h>
#include <cpu.h>
#include <multiboot.h>

/* these prototypes should go into headers */
void uart_init(void);
void die(const char *msg);
void hardware_stage1(void);
void disable_car(void);
void mainboard_pre_payload(void);

static void enable_rom(void)
{
        // nothing here yet
        post_code(POST_STAGE1_ENABLE_ROM);
}

void init_archive(struct mem_file *archive)
{
        // FIXME this should be defined in the VPD area
        // but NOT IN THE CODE.

        /* The len field starts behind the reset vector on x86.
         * The start is not correct for all platforms. sc520 will
         * need some hands on here.
         */
        archive->len = *(u32 *)0xfffffff4;
        archive->start =(void *)(0UL-archive->len);

        // FIXME check integrity

}

/**
 * returns bottom of stack, when passed an on-stack variable such as a 
 * parameter or automatic. Stack base must be STACKSIZE aligned 
 * and STACKSIZE must be a power of 2 for this to work. 
 * Luckily these rules have always been true. 
 * Recall that on stacks that grow down, "bottom of stack" is really
 * at "top of memory"!
 * This function should work for any stack -- CAR or non-CAR.
 *
 */
void *bottom_of_stack(void)
{
        /* this is weird, eh? Assigning something its own address. 
         * But it means that we have a %esp value in 'stack'
         */
        u32 stack = (u32) &stack;
        stack &= STACKSIZE;
        stack += STACKSIZE;
        /* -4 because -4 is initial %esp */
        stack -= 4;
        return (void *) stack;
}

struct global_vars *global_vars(void)
{
        return *(struct global_vars **)(bottom_of_stack() - sizeof(struct 
global_vars *));
}

void global_vars_init(struct global_vars *globvars)
{
        memset(globvars, 0, sizeof(struct global_vars));
        *(struct global_vars **)(bottom_of_stack(vars) - sizeof(struct 
global_vars *)) = globvars;
#ifdef CONFIG_CONSOLE_BUFFER
        /* Initialize the printk buffer. */
        printk_buffer_init();
#endif
        console_loglevel_init();

}

void dump_mem_range(int msg_level, unsigned char *buf, int size)
{
        int i;
        printk(msg_level, "dumping memrange %p size %i:\n", buf, size);
        for (i = 0; i < size; i++) {
                printk(msg_level, "%02x ", buf[i]);
                if (i % 16 == 15)
                        printk(msg_level, "\n");
        }
        return;
}

/** cycles
 * provide 64-bit high precision counter 
 * @returns Time in 64 bits
 */
u64 cycles(void)
{
        u64 ret;
        asm volatile ("rdtsc" : "=A" (ret));
        return ret;
}

static int run_address_multiboot(void *f)
{
        int ret, dummy;
        __asm__ __volatile__ ("call *%4" : "=a" (ret), "=c" (dummy) : "a" 
(MB_MAGIC2), "b" (0xf0000), "c" (f) : "edx", "memory");
        return ret;
}

/**
 * This function is called from assembler code with its argument on the
 * stack. Force the compiler to generate always correct code for this case.
 * We have cache as ram running and can start executing code in C.
 * @param bist Built In Self Test, which is used to indicate status of self 
test.
 * bist is defined by the CPU hardware and is present in EAX on first 
instruction of coreboot. 
 * Its value is implementation defined.
 * @param init_detected This (optionally set) value is used on some platforms 
(e.g. k8) to indicate
 * 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)) stage0_main(u32 bist, u32 init_detected)
{
        struct global_vars globvars;
        int ret;
        struct mem_file archive;
        void *entry;
        struct node_core_id me;
        post_code(POST_STAGE0_MAIN);

        /* before we do anything, we want to stop if we do not run
         * on the bootstrap processor.
         * stop_ap is responsible for NOT stopping the BSP
         */
        stop_ap();

        /* Initialize global variables before we can think of using them.
         */
        global_vars_init(&globvars);
        globvars.init_detected = init_detected;

        hardware_stage1();

        //
        uart_init();    // initialize serial port

        /* Exactly from now on we can use printk to the serial port.
         * Celebrate this by printing a LB banner.
         */
        console_init();

        if (bist!=0) {
                printk(BIOS_INFO, "BIST FAILED: %08x", bist);
                die("");
        }

        // enable rom
        enable_rom();

        // location and size of image.

        init_archive(&archive);

        // find first initram
        if (check_normal_boot_flag()) {
                printk(BIOS_DEBUG, "Choosing normal boot.\n");
                ret = execute_in_place(&archive, "normal/initram/segment0");
        } else {
                printk(BIOS_DEBUG, "Choosing fallback boot.\n");
                ret = execute_in_place(&archive, "fallback/initram/segment0");
                /* Try a normal boot if fallback doesn't exist in the lar.
                 * TODO: There are other ways to do this.
                 * It could be ifdef or the boot flag could be forced.
                 */
                if (ret) {
                        printk(BIOS_DEBUG, "Fallback failed. Try normal 
boot\n");
                        ret = execute_in_place(&archive, 
"normal/initram/segment0");
                }
        }

        if (ret)
                die("Failed RAM init code\n");

        printk(BIOS_DEBUG, "Done RAM init code\n");

        /* Turn off Cache-As-Ram */
        /* as a side effect this calls main() */
        /* and copies global_vars from the CAR stack to the RAM stack */
        disable_car();

}

/** this is called from disable_car. It calls stage2 (which returns to it)
 * and hence is not called 'stage1'
 */
void __attribute__((stdcall)) main(u32 bist, u32 init_detected)
{

#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

        entry = load_file_segments(&archive, "normal/stage2");
        if (entry == (void *)-1)
                die("FATAL: Failed loading stage2.");
        ret = run_address(entry);
        if (ret)
                die("FATAL: Failed in stage2 code.");

        printk(BIOS_DEBUG, "Stage2 code done.\n");

        entry = load_file_segments(&archive, "normal/payload");
        if (entry != (void*)-1) {
                /* Final coreboot call before handing off to the payload. */
                mainboard_pre_payload();
                run_address_multiboot(entry);
        } else {
                die("FATAL: No usable payload found.\n");
        }
        die ("FATAL: Last stage returned to coreboot.\n");
}


--
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to