X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fpost.c;h=cf7501ebbd67e475c0b2c6fd30f11b7051cd9f5e;hb=151296fbf9b2dfc65365ac71b5f4483c3d532f8d;hp=54b273f4a4b9396b52d76c0eee0e3545bb13fddc;hpb=2ddcf1885f1f8a0de7e8bd6666abfabf67b0fda0;p=seabios.git diff --git a/src/post.c b/src/post.c index 54b273f..cf7501e 100644 --- a/src/post.c +++ b/src/post.c @@ -1,119 +1,99 @@ // 32bit code to Power On Self Test (POST) a machine. // -// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2008-2010 Kevin O'Connor // Copyright (C) 2002 MandrakeSoft S.A. // -// This file may be distributed under the terms of the GNU GPLv3 license. +// 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 "ata.h" // hard_drive_setup #include "disk.h" // floppy_drive_setup +#include "ata.h" // ata_setup +#include "ahci.h" // ahci_setup #include "memmap.h" // add_e820 #include "pic.h" // pic_setup #include "pci.h" // create_pirtable #include "acpi.h" // acpi_bios_init #include "bregs.h" // struct bregs +#include "mptable.h" // mptable_init +#include "boot.h" // IPL +#include "usb.h" // usb_setup +#include "smbios.h" // smbios_init +#include "paravirt.h" // qemu_cfg_port_probe +#include "xen.h" // xen_probe_hvm_info +#include "ps2port.h" // ps2port_setup +#include "virtio-blk.h" // virtio_blk_setup -#define bda ((struct bios_data_area_s *)MAKE_FARPTR(SEG_BDA, 0)) -#define ebda ((struct extended_bios_data_area_s *)MAKE_FARPTR(SEG_EBDA, 0)) -static void -set_irq(int vector, void *loc) -{ - SET_BDA(ivecs[vector].seg, SEG_BIOS); - SET_BDA(ivecs[vector].offset, (u32)loc - BUILD_BIOS_ADDR); -} - -// Symbols defined in romlayout.S -extern void dummy_iret_handler(); -extern void entry_08(); -extern void entry_09(); -extern void entry_hwirq(); -extern void entry_0e(); -extern void entry_10(); -extern void entry_11(); -extern void entry_12(); -extern void entry_13(); -extern void entry_14(); -extern void entry_15(); -extern void entry_16(); -extern void entry_17(); -extern void entry_18(); -extern void entry_19(); -extern void entry_1a(); -extern void entry_1c(); -extern void entry_40(); -extern void entry_70(); -extern void entry_74(); -extern void entry_75(); -extern void entry_76(); +/**************************************************************** + * BIOS init + ****************************************************************/ static void -init_bda() +init_ivt(void) { - dprintf(3, "init bda\n"); - memset(bda, 0, sizeof(*bda)); - - SET_BDA(mem_size_kb, BASE_MEM_IN_K); + dprintf(3, "init ivt\n"); + // Initialize all vectors to the default handler. int i; for (i=0; i<256; i++) - set_irq(i, &dummy_iret_handler); - - set_irq(0x08, &entry_08); - set_irq(0x09, &entry_09); - //set_irq(0x0a, &entry_hwirq); - //set_irq(0x0b, &entry_hwirq); - //set_irq(0x0c, &entry_hwirq); - //set_irq(0x0d, &entry_hwirq); - set_irq(0x0e, &entry_0e); - //set_irq(0x0f, &entry_hwirq); - set_irq(0x10, &entry_10); - set_irq(0x11, &entry_11); - set_irq(0x12, &entry_12); - set_irq(0x13, &entry_13); - set_irq(0x14, &entry_14); - set_irq(0x15, &entry_15); - set_irq(0x16, &entry_16); - set_irq(0x17, &entry_17); - set_irq(0x18, &entry_18); - set_irq(0x19, &entry_19); - set_irq(0x1a, &entry_1a); - set_irq(0x1c, &entry_1c); - set_irq(0x40, &entry_40); - set_irq(0x70, &entry_70); - //set_irq(0x71, &entry_hwirq); - //set_irq(0x72, &entry_hwirq); - //set_irq(0x73, &entry_hwirq); - set_irq(0x74, &entry_74); - set_irq(0x75, &entry_75); - set_irq(0x76, &entry_76); - //set_irq(0x77, &entry_hwirq); + SET_IVT(i, FUNC16(entry_iret_official)); + + // Initialize all hw vectors to a default hw handler. + for (i=0x08; i<=0x0f; i++) + SET_IVT(i, FUNC16(entry_hwpic1)); + for (i=0x70; i<=0x77; i++) + SET_IVT(i, FUNC16(entry_hwpic2)); + + // Initialize software handlers. + SET_IVT(0x02, FUNC16(entry_02)); + SET_IVT(0x10, FUNC16(entry_10)); + SET_IVT(0x11, FUNC16(entry_11)); + SET_IVT(0x12, FUNC16(entry_12)); + SET_IVT(0x13, FUNC16(entry_13_official)); + SET_IVT(0x14, FUNC16(entry_14)); + SET_IVT(0x15, FUNC16(entry_15)); + SET_IVT(0x16, FUNC16(entry_16)); + SET_IVT(0x17, FUNC16(entry_17)); + SET_IVT(0x18, FUNC16(entry_18)); + SET_IVT(0x19, FUNC16(entry_19_official)); + SET_IVT(0x1a, FUNC16(entry_1a)); + SET_IVT(0x40, FUNC16(entry_40)); + + // INT 60h-66h reserved for user interrupt + for (i=0x60; i<=0x66; i++) + SET_IVT(i, SEGOFF(0, 0)); // set vector 0x79 to zero // this is used by 'gardian angel' protection system - SET_BDA(ivecs[0x79].seg, 0); - SET_BDA(ivecs[0x79].offset, 0); + SET_IVT(0x79, SEGOFF(0, 0)); - set_irq(0x1E, &diskette_param_table2); + SET_IVT(0x1E, SEGOFF(SEG_BIOS, (u32)&diskette_param_table2 - BUILD_BIOS_ADDR)); } static void -init_ebda() +init_bda(void) { + dprintf(3, "init bda\n"); + + struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0); + memset(bda, 0, sizeof(*bda)); + + int esize = EBDA_SIZE_START; + SET_BDA(mem_size_kb, BUILD_LOWRAM_END/1024 - esize); + u16 ebda_seg = EBDA_SEGMENT_START; + SET_BDA(ebda_seg, ebda_seg); + + // Init ebda + struct extended_bios_data_area_s *ebda = get_ebda_ptr(); memset(ebda, 0, sizeof(*ebda)); - ebda->size = EBDA_SIZE; - SET_BDA(ebda_seg, SEG_EBDA); - SET_BDA(ivecs[0x41].seg, SEG_EBDA); - SET_BDA(ivecs[0x41].offset - , offsetof(struct extended_bios_data_area_s, fdpt[0])); - SET_BDA(ivecs[0x46].seg, SEG_EBDA); - SET_BDA(ivecs[0x41].offset - , offsetof(struct extended_bios_data_area_s, fdpt[1])); + ebda->size = esize; + + add_e820((u32)MAKE_FLATPTR(ebda_seg, 0), GET_EBDA2(ebda_seg, size) * 1024 + , E820_RESERVED); } static void @@ -121,42 +101,70 @@ ram_probe(void) { dprintf(3, "Find memory size\n"); if (CONFIG_COREBOOT) { - coreboot_fill_map(); + coreboot_setup(); + } else if (usingXen()) { + xen_setup(); } else { // On emulators, get memory size from nvram. - u32 rs = (inb_cmos(CMOS_MEM_EXTMEM2_LOW) - | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 8)) * 65536; + u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16) + | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24)); if (rs) rs += 16 * 1024 * 1024; else - rs = ((inb_cmos(CMOS_MEM_EXTMEM_LOW) - | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 8)) * 1024 + rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10) + | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18)) + 1 * 1024 * 1024); - SET_EBDA(ram_size, rs); + RamSize = rs; add_e820(0, rs, E820_RAM); + // Check for memory over 4Gig + u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16) + | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24) + | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32)); + RamSizeOver4G = high; + add_e820(0x100000000ull, high, E820_RAM); + /* reserve 256KB BIOS area at the end of 4 GB */ add_e820(0xfffc0000, 256*1024, E820_RESERVED); } // Don't declare any memory between 0xa0000 and 0x100000 - add_e820(0xa0000, 0x50000, E820_HOLE); + add_e820(BUILD_LOWRAM_END, BUILD_BIOS_ADDR-BUILD_LOWRAM_END, E820_HOLE); // Mark known areas as reserved. - add_e820((u32)MAKE_FARPTR(SEG_EBDA, 0), EBDA_SIZE * 1024, E820_RESERVED); add_e820(BUILD_BIOS_ADDR, BUILD_BIOS_SIZE, E820_RESERVED); - dprintf(1, "ram_size=0x%08x\n", GET_EBDA(ram_size)); + u32 count = qemu_cfg_e820_entries(); + if (count) { + struct e820_reservation entry; + int i; + + for (i = 0; i < count; i++) { + qemu_cfg_e820_load_next(&entry); + add_e820(entry.address, entry.length, entry.type); + } + } else if (kvm_para_available()) { + // Backwards compatibility - provide hard coded range. + // 4 pages before the bios, 3 pages for vmx tss pages, the + // other page for EPT real mode pagetable + add_e820(0xfffbc000, 4*4096, E820_RESERVED); + } + + dprintf(1, "Ram Size=0x%08x (0x%08x%08x high)\n" + , RamSize, (u32)(RamSizeOver4G >> 32), (u32)RamSizeOver4G); } static void init_bios_tables(void) { - if (CONFIG_COREBOOT) - // XXX - not supported on coreboot yet. + if (CONFIG_COREBOOT) { + coreboot_copy_biostable(); return; - - smm_init(); + } + if (usingXen()) { + xen_copy_biostables(); + return; + } create_pirtable(); @@ -167,257 +175,217 @@ init_bios_tables(void) acpi_bios_init(); } +// Initialize hardware devices static void -init_boot_vectors() +init_hw(void) { - if (! CONFIG_BOOT) - return; - dprintf(3, "init boot device ordering\n"); - - // Floppy drive - struct ipl_entry_s *ip = &ebda->ipl.table[0]; - ip->type = IPL_TYPE_FLOPPY; - ip++; - - // First HDD - ip->type = IPL_TYPE_HARDDISK; - ip++; - - // CDROM - if (CONFIG_CDROM_BOOT) { - ip->type = IPL_TYPE_CDROM; - ip++; - } - - ebda->ipl.count = ip - ebda->ipl.table; - ebda->ipl.sequence = 0xffff; - if (CONFIG_COREBOOT) { - // XXX - hardcode defaults for coreboot. - ebda->ipl.bootorder = 0x00000231; - ebda->ipl.checkfloppysig = 1; - } else { - // On emulators, get boot order from nvram. - ebda->ipl.bootorder = (inb_cmos(CMOS_BIOS_BOOTFLAG2) - | ((inb_cmos(CMOS_BIOS_BOOTFLAG1) & 0xf0) << 4)); - if (!(inb_cmos(CMOS_BIOS_BOOTFLAG1) & 1)) - ebda->ipl.checkfloppysig = 1; - } -} - -// Execute a given option rom. -static void -callrom(u16 seg, u16 offset) -{ - struct bregs br; - memset(&br, 0, sizeof(br)); - br.es = SEG_BIOS; - // starts 1 past for alignment - extern char pnp_string[]; - br.di = (u32)pnp_string - BUILD_BIOS_ADDR; - br.cs = seg; - br.ip = offset; - call16(&br); - - debug_serial_setup(); -} - -// Find and run any "option roms" found in the given address range. -static void -rom_scan(u32 start, u32 end) -{ - if (! CONFIG_OPTIONROMS) - return; + usb_setup(); + ps2port_setup(); + lpt_setup(); + serial_setup(); - u8 *p = (u8*)start; - for (; p <= (u8*)end; p += 2048) { - u8 *rom = p; - if (*(u16*)rom != 0xaa55) - continue; - u32 len = rom[2] * 512; - u8 sum = checksum(rom, len); - if (sum != 0) { - dprintf(1, "Found option rom with bad checksum:" - " loc=%p len=%d sum=%x\n" - , rom, len, sum); - continue; - } - p = (u8*)(((u32)p + len) / 2048 * 2048); - dprintf(1, "Running option rom at %p\n", rom+3); - callrom(FARPTR_TO_SEG(rom), FARPTR_TO_OFFSET(rom + 3)); - - if (GET_BDA(ebda_seg) != SEG_EBDA) - BX_PANIC("Option rom at %p attempted to move ebda from %x to %x\n" - , rom, SEG_EBDA, GET_BDA(ebda_seg)); - - // Look at the ROM's PnP Expansion header. Properly, we're supposed - // to init all the ROMs and then go back and build an IPL table of - // all the bootable devices, but we can get away with one pass. - if (rom[0x1a] != '$' || rom[0x1b] != 'P' - || rom[0x1c] != 'n' || rom[0x1d] != 'P') - continue; - // 0x1A is also the offset into the expansion header of... - // the Bootstrap Entry Vector, or zero if there is none. - u16 entry = *(u16*)&rom[0x1a+0x1a]; - if (!entry) - continue; - // Found a device that thinks it can boot the system. Record - // its BEV and product name string. - - if (! CONFIG_BOOT) - continue; - - if (ebda->ipl.count >= ARRAY_SIZE(ebda->ipl.table)) - continue; - - struct ipl_entry_s *ip = &ebda->ipl.table[ebda->ipl.count]; - ip->type = IPL_TYPE_BEV; - ip->vector = (FARPTR_TO_SEG(rom) << 16) | entry; - - u16 desc = *(u16*)&rom[0x1a+0x10]; - if (desc) - ip->description = (u32)MAKE_FARPTR(FARPTR_TO_SEG(rom), desc); - - ebda->ipl.count++; - } + floppy_setup(); + ata_setup(); + ahci_setup(); + cbfs_payload_setup(); + ramdisk_setup(); + virtio_blk_setup(); } -// Call into vga code to turn on console. -static void -vga_setup() +// Begin the boot process by invoking an int0x19 in 16bit mode. +void VISIBLE32FLAT +startBoot(void) { - dprintf(1, "Scan for VGA option rom\n"); - rom_scan(0xc0000, 0xc7800); + // Clear low-memory allocations (required by PMM spec). + memset((void*)BUILD_STACK_ADDR, 0, BUILD_EBDA_MINIMUM - BUILD_STACK_ADDR); - dprintf(1, "Turning on vga console\n"); + dprintf(3, "Jump to int19\n"); struct bregs br; memset(&br, 0, sizeof(br)); - br.ax = 0x0003; - call16_int(0x10, &br); + br.flags = F_IF; + call16_int(0x19, &br); } // Main setup code. static void -post() +maininit(void) { + // Running at new code address - do code relocation fixups + malloc_fixupreloc(); + + // Setup ivt/bda/ebda + init_ivt(); init_bda(); - init_ebda(); + // Init base pc hardware. pic_setup(); timer_setup(); - kbd_setup(); - lpt_setup(); - serial_setup(); - mouse_setup(); mathcp_setup(); - memmap_setup(); + // Initialize mtrr + mtrr_setup(); - ram_probe(); + // Initialize pci + pci_setup(); + smm_init(); - vga_setup(); + // Setup Xen hypercalls + xen_init_hypercalls(); + + // Initialize internal tables + boot_setup(); - printf("BIOS - begin\n\n"); + // Start hardware initialization (if optionrom threading) + if (CONFIG_THREADS && CONFIG_THREAD_OPTIONROMS) + init_hw(); - pci_bios_setup(); + // Find and initialize other cpus + smp_probe(); + // Setup interfaces that option roms may need + bios32_setup(); + dprintf(3, "[wurm] pmm_setup\n"); + pmm_setup(); + dprintf(3, "[wurm] pnp_setup\n"); + pnp_setup(); + dprintf(3, "[wurm] kbd_setup\n"); + kbd_setup(); + dprintf(3, "[wurm] mouse_setup\n"); + mouse_setup(); + dprintf(3, "[wurm] init_bios_tables\n"); init_bios_tables(); + // Run vga option rom + dprintf(3, "[wurm] vga_setup\n"); + vga_setup(); + + // Do hardware initialization (if running synchronously) + if (!CONFIG_THREADS || !CONFIG_THREAD_OPTIONROMS) { + init_hw(); + wait_threads(); + } + + // Run option roms + dprintf(3, "[wurm] optionrom_setup\n"); + optionrom_setup(); + + // Run BCVs and show optional boot menu + dprintf(3, "[wurm] boot_prep\n"); + boot_prep(); + + // Finalize data structures before boot + dprintf(3, "[wurm] cdemu_setup\n"); + cdemu_setup(); + dprintf(3, "[wurm] pmm_finalize\n"); + pmm_finalize(); + dprintf(3, "[wurm] malloc_finalize\n"); + malloc_finalize(); + dprintf(3, "[wurm] memmap_finalize\n"); memmap_finalize(); - floppy_drive_setup(); - hard_drive_setup(); + // Setup bios checksum. + BiosChecksum -= checksum((u8*)BUILD_BIOS_ADDR, BUILD_BIOS_SIZE); - init_boot_vectors(); + // Write protect bios memory. + dprintf(3, "[wurm] make_bios_readonly\n"); + make_bios_readonly(); - dprintf(1, "Scan for option roms\n"); - rom_scan(0xc8000, 0xe0000); + // Invoke int 19 to start boot process. + dprintf(3, "[wurm] startBoot\n"); + startBoot(); } -// Clear .bss section for C code. + +/**************************************************************** + * POST entry and code relocation + ****************************************************************/ + +// Update given relocs for the code at 'dest' with a given 'delta' static void -clear_bss() +updateRelocs(void *dest, u32 *rstart, u32 *rend, u32 delta) { - dprintf(3, "clearing .bss section\n"); - extern char __bss_start[], __bss_end[]; - memset(__bss_start, 0, __bss_end - __bss_start); + u32 *reloc; + for (reloc = rstart; reloc < rend; reloc++) + *((u32*)(dest + *reloc)) += delta; } -// Reset DMA controller +// Relocate init code and then call maininit() at new address. static void -init_dma() +reloc_init(void) { - // first reset the DMA controllers - outb(0, PORT_DMA1_MASTER_CLEAR); - outb(0, PORT_DMA2_MASTER_CLEAR); - - // then initialize the DMA controllers - outb(0xc0, PORT_DMA2_MODE_REG); - outb(0x00, PORT_DMA2_MASK_REG); + if (!CONFIG_RELOCATE_INIT) { + maininit(); + return; + } + // Symbols populated by the build. + extern u8 code32flat_start[]; + extern u8 _reloc_min_align[]; + extern u32 _reloc_abs_start[], _reloc_abs_end[]; + extern u32 _reloc_rel_start[], _reloc_rel_end[]; + extern u32 _reloc_init_start[], _reloc_init_end[]; + extern u8 code32init_start[], code32init_end[]; + + // Allocate space for init code. + u32 initsize = code32init_end - code32init_start; + u32 align = (u32)&_reloc_min_align; + void *dest = memalign_tmp(align, initsize); + if (!dest) + panic("No space for init relocation.\n"); + + // Copy code and update relocs (init absolute, init relative, and runtime) + dprintf(1, "Relocating init from %p to %p (size %d)\n" + , code32init_start, dest, initsize); + s32 delta = dest - (void*)code32init_start; + memcpy(dest, code32init_start, initsize); + updateRelocs(dest, _reloc_abs_start, _reloc_abs_end, delta); + updateRelocs(dest, _reloc_rel_start, _reloc_rel_end, -delta); + updateRelocs(code32flat_start, _reloc_init_start, _reloc_init_end, delta); + + // Call maininit() in relocated code. + void (*func)(void) = (void*)maininit + delta; + barrier(); + func(); } -// Check if the machine was setup with a special restart vector. -static void -check_restart_status() +// Setup for code relocation and then call reloc_init +void VISIBLE32INIT +dopost(void) { - // Get and then clear CMOS shutdown status. - u8 status = inb_cmos(CMOS_RESET_CODE); - outb_cmos(0, CMOS_RESET_CODE); + HaveRunPost = 1; - if (status == 0x00 || status == 0x09 || status >= 0x0d) - // Normal post - return; - - if (status != 0x05) { - BX_PANIC("Unimplemented shutdown status: %02x\n", status); - return; - } + // Detect ram and setup internal malloc. + qemu_cfg_port_probe(); + ram_probe(); + malloc_setup(); - // XXX - this is supposed to jump without changing any memory - - // but the stack has been altered by the time the code gets here. - eoi_pic2(); - struct bregs br; - memset(&br, 0, sizeof(br)); - br.cs = GET_BDA(jump_cs_ip) >> 16; - br.ip = GET_BDA(jump_cs_ip); - call16(&br); + // Relocate initialization code and call maininit(). + reloc_init(); } -// 32-bit entry point. -void VISIBLE32 -_start() +// 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) { - init_dma(); - check_restart_status(); - debug_serial_setup(); - dprintf(1, "Start bios\n"); + dprintf(1, "Start bios (version %s)\n", VERSION); - // Setup for .bss and .data sections - clear_bss(); - make_bios_writable(); + // Enable CPU caching + setcr0(getcr0() & ~(CR0_CD|CR0_NW)); - // Perform main setup code. - post(); + // Clear CMOS reboot flag. + outb_cmos(0, CMOS_RESET_CODE); - // Present the user with a bootup menu. - interactive_bootmenu(); + // Make sure legacy DMA isn't running. + init_dma(); - // Setup bios checksum. - extern char bios_checksum; - bios_checksum = -checksum((u8*)BUILD_BIOS_ADDR, BUILD_BIOS_SIZE - 1); + // Check if we are running under Xen. + xen_probe(); - // Prep for boot process. - make_bios_readonly(); - clear_bss(); + // Allow writes to modify bios area (0xf0000) + make_bios_writable(); - // Invoke int 19 to start boot process. - dprintf(3, "Jump to int19\n"); - struct bregs br; - memset(&br, 0, sizeof(br)); - call16_int(0x19, &br); + // Now that memory is read/writable - start post process. + dopost(); } - -// Ughh - some older gcc compilers have a bug which causes VISIBLE32 -// functions to not be exported as a global variable - force _start -// to be global here. -asm(".global _start");