Additional changes intended to clarify the early initialization ("preinit") order.
-Kevin
Kevin O'Connor (3): POST: Reorganize post entry and "preinit" functions. POST: Move cpu caching and dma setup to platform_hardware_setup(). POST: Merge platform preinit() calls.
src/coreboot.c | 6 +-- src/paravirt.c | 10 +++- src/paravirt.h | 3 +- src/post.c | 152 +++++++++++++++++++++++++++++++------------------------- src/resume.c | 4 +- src/romlayout.S | 2 +- src/util.h | 2 +- src/xen.c | 57 +++++++++++---------- src/xen.h | 1 - 9 files changed, 127 insertions(+), 110 deletions(-)
Unlocking ram in handle_post() is tricky and only needed under qemu. Separate out that logic from the coreboot/xen paths by invoking handle_elf_post separately. This simplifies both the qemu and non-qemu code paths.
Also, organize all the "pre-init" functions into one section of the file.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/post.c | 152 +++++++++++++++++++++++++++++++++----------------------- src/romlayout.S | 2 +- 2 files changed, 90 insertions(+), 64 deletions(-)
diff --git a/src/post.c b/src/post.c index 33b51b7..56df90c 100644 --- a/src/post.c +++ b/src/post.c @@ -1,24 +1,23 @@ // 32bit code to Power On Self Test (POST) a machine. // -// Copyright (C) 2008-2010 Kevin O'Connor kevin@koconnor.net +// Copyright (C) 2008-2013 Kevin O'Connor kevin@koconnor.net // Copyright (C) 2002 MandrakeSoft S.A. // // This file may be distributed under the terms of the GNU LGPLv3 license.
-#include "ioport.h" // PORT_* #include "config.h" // CONFIG_* #include "cmos.h" // CMOS_* #include "util.h" // memset #include "biosvar.h" // struct bios_data_area_s -#include "disk.h" // floppy_drive_setup +#include "disk.h" // floppy_setup #include "ata.h" // ata_setup #include "ahci.h" // ahci_setup #include "memmap.h" // add_e820 #include "pic.h" // pic_setup #include "bregs.h" // struct bregs -#include "boot.h" // IPL +#include "boot.h" // boot_init #include "usb.h" // usb_setup -#include "paravirt.h" // qemu_cfg_port_probe +#include "paravirt.h" // qemu_cfg_preinit #include "xen.h" // xen_preinit #include "ps2port.h" // ps2port_setup #include "virtio-blk.h" // virtio_blk_setup @@ -29,30 +28,10 @@
/**************************************************************** - * BIOS init + * BIOS initialization and hardware setup ****************************************************************/
static void -ramsize_preinit(void) -{ - dprintf(3, "Find memory size\n"); - if (CONFIG_COREBOOT) - coreboot_preinit(); - else if (usingXen()) - xen_ramsize_preinit(); - else - qemu_ramsize_preinit(); - - // Don't declare any memory between 0xa0000 and 0x100000 - add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE); - - // Mark known areas as reserved. - add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED); - - dprintf(1, "Ram Size=0x%08x (0x%016llx high)\n", RamSize, RamSizeOver4G); -} - -static void ivt_init(void) { dprintf(3, "init ivt\n"); @@ -244,24 +223,30 @@ maininit(void) make_bios_readonly(); }
-// Begin the boot process by invoking an int0x19 in 16bit mode. + +/**************************************************************** + * Early initialization (preinit) and code relocation + ****************************************************************/ + static void -startBoot(void) +ramsize_preinit(void) { - // Clear low-memory allocations (required by PMM spec). - memset((void*)BUILD_STACK_ADDR, 0, BUILD_EBDA_MINIMUM - BUILD_STACK_ADDR); + dprintf(3, "Find memory size\n"); + if (CONFIG_COREBOOT) + coreboot_preinit(); + else if (usingXen()) + xen_ramsize_preinit(); + else + qemu_ramsize_preinit();
- dprintf(3, "Jump to int19\n"); - struct bregs br; - memset(&br, 0, sizeof(br)); - br.flags = F_IF; - call16_int(0x19, &br); -} + // Don't declare any memory between 0xa0000 and 0x100000 + add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE);
+ // Mark known areas as reserved. + add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED);
-/**************************************************************** - * POST entry and code relocation - ****************************************************************/ + dprintf(1, "Ram Size=0x%08x (0x%016llx high)\n", RamSize, RamSizeOver4G); +}
// Update given relocs for the code at 'dest' with a given 'delta' static void @@ -272,7 +257,7 @@ updateRelocs(void *dest, u32 *rstart, u32 *rend, u32 delta) *((u32*)(dest + *reloc)) += delta; }
-// Relocate init code and then call maininit() at new address. +// Relocate init code. static void reloc_preinit(void) { @@ -311,11 +296,22 @@ reloc_preinit(void) barrier(); }
-// Setup for code relocation and then call reloc_init +// Setup for code relocation and then relocate. void VISIBLE32INIT -doreloc(void) +preinit(void) { + // Set reboot flags. HaveRunPost = 1; + outb_cmos(0, CMOS_RESET_CODE); + + // Enable CPU caching + setcr0(getcr0() & ~(CR0_CD|CR0_NW)); + + // Make sure legacy DMA isn't running. + dma_preinit(); + + // Check if we are running under Xen. + xen_preinit();
// Detect ram and setup internal malloc. qemu_cfg_preinit(); @@ -326,32 +322,31 @@ doreloc(void) reloc_preinit(); }
-// Entry point for Power On Self Test (POST) - the BIOS initilization -// phase. This function makes the memory at 0xc0000-0xfffff -// read/writable and then calls dopost(). -void VISIBLE32FLAT -handle_post(void) -{ - debug_serial_preinit(); - dprintf(1, "Start bios (version %s)\n", VERSION); - - // Enable CPU caching - setcr0(getcr0() & ~(CR0_CD|CR0_NW)); - - // Clear CMOS reboot flag. - outb_cmos(0, CMOS_RESET_CODE);
- // Make sure legacy DMA isn't running. - dma_preinit(); +/**************************************************************** + * POST entry + ****************************************************************/
- // Check if we are running under Xen. - xen_preinit(); +// As the last part of POST, invoke int19 to start boot phase. +static void +startBoot(void) +{ + // Clear low-memory allocations (required by PMM spec). + memset((void*)BUILD_STACK_ADDR, 0, BUILD_EBDA_MINIMUM - BUILD_STACK_ADDR);
- // Allow writes to modify bios area (0xf0000) - make_bios_writable(); + dprintf(3, "Jump to int19\n"); + struct bregs br; + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + call16_int(0x19, &br); +}
+// Power On Self Test (POST) - the main BIOS initialization phase. +static void +post(void) +{ // Do pre-relocation setup and then relocate initialization code. - doreloc(); + preinit();
// Run main code maininit(); @@ -359,3 +354,34 @@ handle_post(void) // Invoke int 19 to start boot process. startBoot(); } + +// Startup debug output and display software version. +static void +debug_splash(void) +{ + debug_serial_preinit(); + dprintf(1, "Start bios (version %s)\n", VERSION); +} + +// Entry point for Power On Self Test (POST) when running under +// xen/coreboot. +void VISIBLE32FLAT +handle_elf_post(void) +{ + debug_splash(); + post(); +} + +// Entry point for Power On Self Test (POST) when running under +// qemu/kvm/bochs. Under qemu the memory at 0xc0000-0xfffff may be +// read-only, so unlock the ram as the first step of booting. +void VISIBLE32FLAT +handle_post(void) +{ + debug_splash(); + + // Allow writes to modify bios area (0xf0000) + make_bios_writable(); + + post(); +} diff --git a/src/romlayout.S b/src/romlayout.S index 8125277..a8e00b6 100644 --- a/src/romlayout.S +++ b/src/romlayout.S @@ -380,7 +380,7 @@ entry_elf: movw %ax, %gs movw %ax, %ss movl $BUILD_STACK_ADDR, %esp - ljmpl $SEG32_MODE32_CS, $_cfunc32flat_handle_post + ljmpl $SEG32_MODE32_CS, $_cfunc32flat_handle_elf_post
.code16gcc
The CPU cache is enabled and DMA is disabled on all real-world POST entry situations, so no need to do this in the low-level "pre-init" phase. Instead, move it to the platform hardware setup stage.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/post.c | 12 ++++++------ src/resume.c | 4 ++-- src/util.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/post.c b/src/post.c index 56df90c..e5435b1 100644 --- a/src/post.c +++ b/src/post.c @@ -144,6 +144,12 @@ device_hardware_setup(void) static void platform_hardware_setup(void) { + // Enable CPU caching + setcr0(getcr0() & ~(CR0_CD|CR0_NW)); + + // Make sure legacy DMA isn't running. + dma_setup(); + // Init base pc hardware. pic_setup(); timer_setup(); @@ -304,12 +310,6 @@ preinit(void) HaveRunPost = 1; outb_cmos(0, CMOS_RESET_CODE);
- // Enable CPU caching - setcr0(getcr0() & ~(CR0_CD|CR0_NW)); - - // Make sure legacy DMA isn't running. - dma_preinit(); - // Check if we are running under Xen. xen_preinit();
diff --git a/src/resume.c b/src/resume.c index 99265cd..ffc84fc 100644 --- a/src/resume.c +++ b/src/resume.c @@ -19,7 +19,7 @@ int HaveRunPost VAR16VISIBLE;
// Reset DMA controller void -dma_preinit(void) +dma_setup(void) { // first reset the DMA controllers outb(0, PORT_DMA1_MASTER_CLEAR); @@ -40,7 +40,7 @@ handle_resume(void) outb_cmos(0, CMOS_RESET_CODE); dprintf(1, "In resume (status=%d)\n", status);
- dma_preinit(); + dma_setup();
switch (status) { case 0x01 ... 0x04: diff --git a/src/util.h b/src/util.h index eb35d02..88f5905 100644 --- a/src/util.h +++ b/src/util.h @@ -354,7 +354,7 @@ void disable_bootsplash(void);
// resume.c extern int HaveRunPost; -void dma_preinit(void); +void dma_setup(void);
// pnpbios.c #define PNP_SIGNATURE 0x506e5024 // $PnP
Xen and QEMU had multiple platform preinit() calls that were invoked right after each other. Merge these together. This simplifies the preinit code.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/coreboot.c | 6 ++---- src/paravirt.c | 10 ++++++++-- src/paravirt.h | 3 +-- src/post.c | 38 ++++++++++++++------------------------ src/xen.c | 57 ++++++++++++++++++++++++++++----------------------------- src/xen.h | 1 - 6 files changed, 53 insertions(+), 62 deletions(-)
diff --git a/src/coreboot.c b/src/coreboot.c index 5d013cf..9f695ad 100644 --- a/src/coreboot.c +++ b/src/coreboot.c @@ -125,6 +125,8 @@ const char *CBvendor = "", *CBpart = ""; void coreboot_preinit(void) { + if (!CONFIG_COREBOOT) + return; dprintf(3, "Attempting to find coreboot table\n");
// Find coreboot table. @@ -165,10 +167,6 @@ coreboot_preinit(void) RamSize = maxram; RamSizeOver4G = maxram_over4G;
- // Ughh - coreboot likes to set a map at 0x0000-0x1000, but this - // confuses grub. So, override it. - add_e820(0, 16*1024, E820_RAM); - struct cb_mainboard *cbmb = find_cb_subtable(cbh, CB_TAG_MAINBOARD); if (cbmb) { CBvendor = &cbmb->strings[cbmb->vendor_idx]; diff --git a/src/paravirt.c b/src/paravirt.c index 9022186..5cfda66 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -18,12 +18,16 @@ #include "acpi.h" // acpi_setup #include "mptable.h" // mptable_setup #include "pci.h" // create_pirtable +#include "xen.h" // usingXen
int qemu_cfg_present;
-void +static void qemu_ramsize_preinit(void) { + if (CONFIG_COREBOOT || usingXen()) + return; + // On emulators, get memory size from nvram. u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16) | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24)); @@ -98,7 +102,7 @@ qemu_cfg_read_entry(void *buf, int e, int len) qemu_cfg_read(buf, len); }
-void qemu_cfg_preinit(void) +void qemu_preinit(void) { char *sig = "QEMU"; int i; @@ -116,6 +120,8 @@ void qemu_cfg_preinit(void) break; } dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present); + + qemu_ramsize_preinit(); }
void qemu_cfg_get_uuid(u8 *uuid) diff --git a/src/paravirt.h b/src/paravirt.h index 4f2d5b8..04ebde5 100644 --- a/src/paravirt.h +++ b/src/paravirt.h @@ -43,9 +43,8 @@ static inline int kvm_para_available(void)
extern int qemu_cfg_present;
-void qemu_ramsize_preinit(void); void qemu_biostable_setup(void); -void qemu_cfg_preinit(void); +void qemu_preinit(void); int qemu_cfg_show_boot_menu(void); void qemu_cfg_get_uuid(u8 *uuid); int qemu_cfg_irq0_override(void); diff --git a/src/post.c b/src/post.c index e5435b1..ef67743 100644 --- a/src/post.c +++ b/src/post.c @@ -234,26 +234,6 @@ maininit(void) * Early initialization (preinit) and code relocation ****************************************************************/
-static void -ramsize_preinit(void) -{ - dprintf(3, "Find memory size\n"); - if (CONFIG_COREBOOT) - coreboot_preinit(); - else if (usingXen()) - xen_ramsize_preinit(); - else - qemu_ramsize_preinit(); - - // Don't declare any memory between 0xa0000 and 0x100000 - add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE); - - // Mark known areas as reserved. - add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED); - - dprintf(1, "Ram Size=0x%08x (0x%016llx high)\n", RamSize, RamSizeOver4G); -} - // Update given relocs for the code at 'dest' with a given 'delta' static void updateRelocs(void *dest, u32 *rstart, u32 *rend, u32 delta) @@ -310,12 +290,22 @@ preinit(void) HaveRunPost = 1; outb_cmos(0, CMOS_RESET_CODE);
- // Check if we are running under Xen. + // Run platform preinit calls. + coreboot_preinit(); xen_preinit(); + qemu_preinit(); + dprintf(1, "Ram Size=0x%08x (0x%016llx high)\n", RamSize, RamSizeOver4G); + + // The first 1 megabyte of the e820 map is "magic". Various + // programs expect to see (and will crash if they don't): + // 00000-9fc00=RAM, 9fc00-a0000=RESERVED, f0000-100000=RESERVED. + // Force the e820 map to show this (the ebda e820 entry is added + // in init_bda). + add_e820(0, BUILD_LOWRAM_END, E820_RAM); + add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE); + add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED);
- // Detect ram and setup internal malloc. - qemu_cfg_preinit(); - ramsize_preinit(); + // Setup malloc. malloc_preinit();
// Relocate initialization code. diff --git a/src/xen.c b/src/xen.c index c9759f0..525039d 100644 --- a/src/xen.c +++ b/src/xen.c @@ -76,8 +76,35 @@ void xen_preinit(void) break; } } - if (!xen_cpuid_base) + if (!xen_cpuid_base) { dprintf(1, "No Xen hypervisor found.\n"); + return; + } + + u64 maxram = 0, maxram_over4G = 0; + struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS; + validate_info(info); + + dprintf(1, "xen: copy e820...\n"); + + struct e820entry *e820 = (struct e820entry *)info->e820; + int i; + for (i = 0; i < info->e820_nr; i++) { + struct e820entry *e = &e820[i]; + if (e->type == E820_ACPI || e->type == E820_RAM) { + u64 end = e->start + e->size; + if (end > 0x100000000ull) { + end -= 0x100000000ull; + if (end > maxram_over4G) + maxram_over4G = end; + } else if (end > maxram) + maxram = end; + } + add_e820(e->start, e->size, e->type); + } + + RamSize = maxram; + RamSizeOver4G = maxram_over4G; }
static int hypercall_xen_version( int cmd, void *arg) @@ -121,31 +148,3 @@ void xen_biostable_setup(void) for (i=0; i<info->tables_nr; i++) copy_table(tables[i]); } - -void xen_ramsize_preinit(void) -{ - u64 maxram = 0, maxram_over4G = 0; - int i; - struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS; - struct e820entry *e820 = (struct e820entry *)info->e820; - validate_info(info); - - dprintf(1, "xen: copy e820...\n"); - - for (i = 0; i < info->e820_nr; i++) { - struct e820entry *e = &e820[i]; - if (e->type == E820_ACPI || e->type == E820_RAM) { - u64 end = e->start + e->size; - if (end > 0x100000000ull) { - end -= 0x100000000ull; - if (end > maxram_over4G) - maxram_over4G = end; - } else if (end > maxram) - maxram = end; - } - add_e820(e->start, e->size, e->type); - } - - RamSize = maxram; - RamSizeOver4G = maxram_over4G; -} diff --git a/src/xen.h b/src/xen.h index 9b4178a..2be2453 100644 --- a/src/xen.h +++ b/src/xen.h @@ -7,7 +7,6 @@ extern u32 xen_cpuid_base;
void xen_preinit(void); -void xen_ramsize_preinit(void); void xen_hypercall_setup(void); void xen_biostable_setup(void);