Separate out ram shadow code and permit more code to write to bios.
authorKevin O'Connor <kevin@koconnor.net>
Sun, 8 Jun 2008 17:48:06 +0000 (13:48 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Sun, 8 Jun 2008 17:48:06 +0000 (13:48 -0400)
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.

Makefile
src/post.c
src/rombios32.c
src/shadow.c [new file with mode: 0644]
src/util.h

index c465120b23225f411c7cf5aaa67e7cdf7edaaaa3..7e5fa6b51715b87726532408a05fd214f0f1dcdd 100644 (file)
--- 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 \
index 4b56551dc89d402b4b2aef06bd0bed991b41a4e8..9b5495332f74022d07cc5056d72cec2a9f844a83 100644 (file)
@@ -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.
index 3e73323ad02eee1add6a506a616134da50f24b58..74c456346d61eb60a19ebe242d6e24528034f899 100644 (file)
@@ -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 (file)
index 0000000..6500029
--- /dev/null
@@ -0,0 +1,87 @@
+// Support for enabling/disabling BIOS ram shadowing.
+//
+// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// 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);
+}
index 172308af55898bd1fc795e82c9816a3612993524..5c3710048f8c25f599b8a95b8b8be479ee48d434 100644 (file)
@@ -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);