From: Kevin O'Connor Date: Sun, 8 Jun 2008 17:48:06 +0000 (-0400) Subject: Separate out ram shadow code and permit more code to write to bios. X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=da4a6482c94dbae35064be24cd71f1b22de6d50c;p=seabios.git Separate out ram shadow code and permit more code to write to bios. Extract shadow code from rombios32.c to its own file - shadow.c. Reorg post.c so that shadow enable happens early and ram lock happens late in boot process. Also, improve some comments in post.c and reorg code slightly. --- diff --git a/Makefile b/Makefile index c465120..7e5fa6b 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ OUT=out/ # Source files SRCBOTH=output.c util.c floppy.c ata.c kbd.c pci.c boot.c serial.c clock.c SRC16=$(SRCBOTH) disk.c system.c mouse.c cdrom.c apm.c pcibios.c -SRC32=$(SRCBOTH) post.c rombios32.c post_menu.c +SRC32=$(SRCBOTH) post.c shadow.c rombios32.c post_menu.c TABLESRC=font.c cbt.c floppy_dbt.c cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \ diff --git a/src/post.c b/src/post.c index 4b56551..9b54953 100644 --- a/src/post.c +++ b/src/post.c @@ -151,6 +151,7 @@ init_boot_vectors() } } +// Execute a given option rom. static void callrom(u16 seg, u16 offset) { @@ -163,6 +164,7 @@ callrom(u16 seg, u16 offset) call16(&br); } +// Find and run any "option roms" found in the given address range. static void rom_scan(u32 start, u32 end) { @@ -211,11 +213,10 @@ rom_scan(u32 start, u32 end) } } +// Main setup code. static void post() { - dprintf(1, "Start bios\n"); - dprintf(3, "init bda\n"); init_bda(); init_ebda(); @@ -239,10 +240,6 @@ post() printf("BIOS - begin\n\n"); - // clear bss section -- XXX - shouldn't use globals - extern char __bss_start[], __bss_end[]; - memset(__bss_start, 0, __bss_end - __bss_start); - dprintf(3, "rombios32 init\n"); rombios32_init(); @@ -256,20 +253,18 @@ post() dprintf(1, "Scan for option roms\n"); rom_scan(0xc8000, 0xe0000); +} - interactive_bootmenu(); - - // reset the memory (some boot loaders such as syslinux suppose - // that the memory is set to zero) - memset((void*)0x40000, 0, 0x40000); // XXX - shouldn't use globals - - // 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); +// Clear .bss section for C code. +static void +clear_bss() +{ + dprintf(3, "clearing .bss section\n"); + extern char __bss_start[], __bss_end[]; + memset(__bss_start, 0, __bss_end - __bss_start); } +// Reset DMA controller static void init_dma() { @@ -282,6 +277,7 @@ init_dma() outb(0x00, PORT_DMA2_MASK_REG); } +// Check if the machine was setup with a special restart vector. static void check_restart_status() { @@ -308,13 +304,34 @@ check_restart_status() call16(&br); } +// 32-bit entry point. void VISIBLE32 _start() { init_dma(); check_restart_status(); + dprintf(1, "Start bios\n"); + + // Setup for .bss and .data sections + clear_bss(); + make_bios_writable(); + + // Perform main setup code. post(); + + // Present the user with a bootup menu. + interactive_bootmenu(); + + // Prep for boot process. + make_bios_readonly(); + clear_bss(); + + // 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); } // Externally visible 32bit entry point. diff --git a/src/rombios32.c b/src/rombios32.c index 3e73323..74c4563 100644 --- a/src/rombios32.c +++ b/src/rombios32.c @@ -26,7 +26,6 @@ // are at 0x40000). #define CPU_COUNT_ADDR 0xf000 #define AP_BOOT_ADDR 0x10000 -#define BIOS_TMP_STORAGE 0x30000 /* 64 KB used to copy the BIOS to shadow RAM */ #define PM_IO_BASE 0xb000 #define SMB_IO_BASE 0xb100 @@ -36,8 +35,6 @@ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \ : "0" (index)) -#define wbinvd() asm volatile("wbinvd") - #define CPUID_APIC (1 << 9) #define APIC_BASE ((u8 *)0xfee00000) @@ -234,63 +231,6 @@ static int pci_slot_get_pirq(PCIDevice pci_dev, int irq_num) return (irq_num + slot_addend) & 3; } -static void -copy_bios(PCIDevice d, int v) -{ - pci_config_writeb(d, 0x59, v); - memcpy((void *)0x000f0000, (void *)BIOS_TMP_STORAGE, 0x10000); -} - -// Test if 'addr' is in the range from 'start'..'start+size' -#define IN_RANGE(addr, start, size) ({ \ - u32 __addr = (addr); \ - u32 __start = (start); \ - u32 __size = (size); \ - (__addr - __start < __size); \ - }) - -static void bios_shadow_init(PCIDevice d) -{ - bios_table_cur_addr = 0xf0000 | OFFSET_freespace2_start; - bios_table_end_addr = 0xf0000 | OFFSET_freespace2_end; - dprintf(1, "bios_table_addr: 0x%08lx end=0x%08lx\n", - bios_table_cur_addr, bios_table_end_addr); - - /* remap the BIOS to shadow RAM an keep it read/write while we - are writing tables */ - int v = pci_config_readb(d, 0x59); - v &= 0xcf; - pci_config_writeb(d, 0x59, v); - memcpy((void *)BIOS_TMP_STORAGE, (void *)0x000f0000, 0x10000); - v |= 0x30; - - if (IN_RANGE((u32)copy_bios, 0xf0000, 0x10000)) { - // Current code is in shadowed area. Perform the copy from - // the code that is in the temporary location. - u32 pos = (u32)copy_bios - 0xf0000 + BIOS_TMP_STORAGE; - void (*func)(PCIDevice, int) = (void*)pos; - func(d, v); - } else { - copy_bios(d, v); - } - - // Clear the area just copied. - memset((void *)BIOS_TMP_STORAGE, 0, 0x10000); - - i440_pcidev = d; -} - -static void bios_lock_shadow_ram(void) -{ - PCIDevice d = i440_pcidev; - int v; - - wbinvd(); - v = pci_config_readb(d, 0x59); - v = (v & 0x0f) | (0x10); - pci_config_writeb(d, 0x59, v); -} - static void pci_bios_init_bridges(PCIDevice d) { u16 vendor_id, device_id; @@ -319,7 +259,7 @@ static void pci_bios_init_bridges(PCIDevice d) elcr[0], elcr[1]); } else if (vendor_id == 0x8086 && device_id == 0x1237) { /* i440 PCI bridge */ - bios_shadow_init(d); + i440_pcidev = d; } } @@ -1677,6 +1617,11 @@ void rombios32_init(void) dprintf(1, "ebda_cur_addr: 0x%08lx\n", ebda_cur_addr); #endif + bios_table_cur_addr = 0xf0000 | OFFSET_freespace2_start; + bios_table_end_addr = 0xf0000 | OFFSET_freespace2_end; + dprintf(1, "bios_table_addr: 0x%08lx end=0x%08lx\n", + bios_table_cur_addr, bios_table_end_addr); + cpu_probe(); smp_probe(); @@ -1694,8 +1639,6 @@ void rombios32_init(void) if (acpi_enabled) acpi_bios_init(); - bios_lock_shadow_ram(); - dprintf(1, "bios_table_cur_addr: 0x%08lx\n", bios_table_cur_addr); if (bios_table_cur_addr > bios_table_end_addr) BX_PANIC("bios_table_end_addr overflow!\n"); diff --git a/src/shadow.c b/src/shadow.c new file mode 100644 index 0000000..6500029 --- /dev/null +++ b/src/shadow.c @@ -0,0 +1,87 @@ +// Support for enabling/disabling BIOS ram shadowing. +// +// Copyright (C) 2008 Kevin O'Connor +// Copyright (C) 2006 Fabrice Bellard +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "util.h" // memcpy +#include "pci.h" // pci_config_writeb + +#define BIOS_TMP_STORAGE 0x30000 /* 64 KB used to copy the BIOS to shadow RAM */ + +// Test if 'addr' is in the range from 'start'..'start+size' +#define IN_RANGE(addr, start, size) ({ \ + u32 __addr = (addr); \ + u32 __start = (start); \ + u32 __size = (size); \ + (__addr - __start < __size); \ + }) + +// Enable shadowing and copy bios. +static void +copy_bios(PCIDevice d) +{ + int v = pci_config_readb(d, 0x59); + v |= 0x30; + pci_config_writeb(d, 0x59, v); + memcpy((void *)0x000f0000, (void *)BIOS_TMP_STORAGE, 0x10000); +} + +// Make the BIOS code segment area (0xf0000) writable. +void +make_bios_writable() +{ + if (CONFIG_COREBOOT) + return; + + dprintf(3, "enabling shadow ram\n"); + + // Locate chip controlling ram shadowing. + PCIDevice d; + int ret = pci_find_device(0x8086, 0x1237, 0, &d); + if (ret) { + dprintf(1, "Unable to unlock ram - bridge not found\n"); + return; + } + + // Copy the bios to a temporary area. + memcpy((void *)BIOS_TMP_STORAGE, (void *)0x000f0000, 0x10000); + + // Enable shadowing and copy bios. + if (IN_RANGE((u32)copy_bios, 0xf0000, 0x10000)) { + // Jump to shadow enable function - use the copy in the + // temporary storage area so that memory does not change under + // the executing code. + u32 pos = (u32)copy_bios - 0xf0000 + BIOS_TMP_STORAGE; + void (*func)(PCIDevice) = (void*)pos; + func(d); + } else { + copy_bios(d); + } + + // Clear the temporary area. + memset((void *)BIOS_TMP_STORAGE, 0, 0x10000); +} + +// Make the BIOS code segment area (0xf0000) read-only. +void +make_bios_readonly() +{ + if (CONFIG_COREBOOT) + return; + + dprintf(3, "locking shadow ram\n"); + + PCIDevice d; + int ret = pci_find_device(0x8086, 0x1237, 0, &d); + if (ret) { + dprintf(1, "Unable to lock ram - bridge not found\n"); + return; + } + + wbinvd(); + int v = pci_config_readb(d, 0x59); + v = (v & 0x0f) | (0x10); + pci_config_writeb(d, 0x59, v); +} diff --git a/src/util.h b/src/util.h index 172308a..5c37100 100644 --- a/src/util.h +++ b/src/util.h @@ -47,6 +47,11 @@ static inline void hlt(void) asm volatile("hlt"); } +static inline void wbinvd(void) +{ + asm volatile("wbinvd"); +} + void *memset(void *s, int c, size_t n); void *memcpy(void *d1, const void *s1, size_t len); @@ -179,6 +184,10 @@ void handle_1ab1(struct bregs *regs); // util.c u8 checksum(u8 *far_data, u32 len); +// shadow.c +void make_bios_writable(); +void make_bios_readonly(); + // rombios32.c void rombios32_init(void);