diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | fw_cfg.c | 50 | ||||
-rw-r--r-- | include/bios.h | 2 | ||||
-rw-r--r-- | include/fw_cfg.h | 115 | ||||
-rw-r--r-- | main.c | 19 |
5 files changed, 186 insertions, 2 deletions
@@ -1,5 +1,5 @@ obj16-y = e820.o int10.o int15.o -obj-y = $(obj16-y) entry.o main.o string.o printf.o cstart.o +obj-y = $(obj16-y) entry.o main.o string.o printf.o cstart.o fw_cfg.o all-y = bios.bin CFLAGS := -O2 -Wall -g diff --git a/fw_cfg.c b/fw_cfg.c new file mode 100644 index 0000000..293e4be --- /dev/null +++ b/fw_cfg.c @@ -0,0 +1,50 @@ +#include "bios.h" +#include "ioport.h" +#include "string.h" +#include "fw_cfg.h" + +struct fw_cfg_file { + uint32_t size; + uint16_t select; + char name[57]; +}; + +static struct fw_cfg_file files[32]; + +void fw_cfg_setup(void) +{ + int i, n; + + fw_cfg_select(FW_CFG_FILE_DIR); + n = fw_cfg_readl_be(); + if (n > ARRAY_SIZE(files)) + n = ARRAY_SIZE(files); + + for (i = 0; i < n; i++) { + files[i].size = fw_cfg_readl_be(); + files[i].select = fw_cfg_readw_be(); + fw_cfg_readw_be(); + fw_cfg_read(files[i].name, sizeof(files[i].name) - 1); + } +} + +int fw_cfg_file_id(char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(files); i++) + if (!strcmp(name, files[i].name)) + return i; + + return -1; +} + +uint32_t fw_cfg_file_size(int id) +{ + return files[id].size; +} + +void fw_cfg_file_select(int id) +{ + fw_cfg_select(files[id].select); +} diff --git a/include/bios.h b/include/bios.h index 7232bef..bd7f77b 100644 --- a/include/bios.h +++ b/include/bios.h @@ -38,6 +38,8 @@ extern void bios_int15(void); extern struct e820map e820; +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + static inline void __attribute__((noreturn)) panic(void) { asm volatile("cli; hlt"); diff --git a/include/fw_cfg.h b/include/fw_cfg.h new file mode 100644 index 0000000..57afa14 --- /dev/null +++ b/include/fw_cfg.h @@ -0,0 +1,115 @@ +#ifndef _FW_CFG_H +#define _FW_CFG_H 1 + +// List of QEMU fw_cfg entries. DO NOT ADD MORE. (All new content +// should be passed via the fw_cfg "file" interface.) +#define FW_CFG_SIGNATURE 0x00 +#define FW_CFG_ID 0x01 +#define FW_CFG_UUID 0x02 +#define FW_CFG_RAM_SIZE 0x03 +#define FW_CFG_NOGRAPHIC 0x04 +#define FW_CFG_NB_CPUS 0x05 +#define FW_CFG_MACHINE_ID 0x06 +#define FW_CFG_KERNEL_ADDR 0x07 +#define FW_CFG_KERNEL_SIZE 0x08 +#define FW_CFG_KERNEL_CMDLINE 0x09 +#define FW_CFG_INITRD_ADDR 0x0a +#define FW_CFG_INITRD_SIZE 0x0b +#define FW_CFG_BOOT_DEVICE 0x0c +#define FW_CFG_NUMA 0x0d +#define FW_CFG_BOOT_MENU 0x0e +#define FW_CFG_MAX_CPUS 0x0f +#define FW_CFG_KERNEL_ENTRY 0x10 +#define FW_CFG_KERNEL_DATA 0x11 +#define FW_CFG_INITRD_DATA 0x12 +#define FW_CFG_CMDLINE_ADDR 0x13 +#define FW_CFG_CMDLINE_SIZE 0x14 +#define FW_CFG_CMDLINE_DATA 0x15 +#define FW_CFG_SETUP_ADDR 0x16 +#define FW_CFG_SETUP_SIZE 0x17 +#define FW_CFG_SETUP_DATA 0x18 +#define FW_CFG_FILE_DIR 0x19 +#define FW_CFG_FILE_FIRST 0x20 +#define FW_CFG_ARCH_LOCAL 0x8000 +#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0) +#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1) +#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2) +#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3) + +#define FW_CFG_CTL 0x510 +#define FW_CFG_DATA 0x511 + +static inline void fw_cfg_select(uint16_t f) +{ + outw(FW_CFG_CTL, f); +} + +static inline uint32_t fw_cfg_readb(void) +{ + return inb(FW_CFG_DATA); +} + +static inline uint32_t fw_cfg_readw_be(void) +{ + uint32_t val; + + val = inb(FW_CFG_DATA); + val = (val << 8) | inb(FW_CFG_DATA); + return val; +} + +static inline uint32_t fw_cfg_readw_le(void) +{ + uint32_t val; + + val = inb(FW_CFG_DATA); + val = (inb(FW_CFG_DATA) << 8) | val; + return val; +} + +static inline uint32_t fw_cfg_readl_be(void) +{ + uint32_t val; + + val = inb(FW_CFG_DATA); + val = (val << 8) | inb(FW_CFG_DATA); + val = (val << 8) | inb(FW_CFG_DATA); + val = (val << 8) | inb(FW_CFG_DATA); + return val; +} + +static inline uint32_t fw_cfg_readl_le(void) +{ + uint32_t val; + + val = inb(FW_CFG_DATA); + val = (inb(FW_CFG_DATA) << 8) | val; + val = (inb(FW_CFG_DATA) << 16) | val; + val = (inb(FW_CFG_DATA) << 24) | val; + return val; +} + +static inline void fw_cfg_read(void *buf, int len) +{ + insb(buf, FW_CFG_DATA, len); +} + +static inline void fw_cfg_skip(int len) +{ + while (len--) + inb(FW_CFG_DATA); +} + +static inline void +fw_cfg_read_entry(void *buf, int e, int len) +{ + fw_cfg_select(e); + fw_cfg_read(buf, len); +} + +void fw_cfg_setup(void); +int fw_cfg_file_id(char *name); +uint32_t fw_cfg_file_size(int id); +void fw_cfg_file_select(int id); + +#endif @@ -1,7 +1,9 @@ #include "bios.h" +#include "e820.h" #include "pci.h" #include "string.h" #include "segment.h" +#include "fw_cfg.h" #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_82441 0x1237 @@ -77,13 +79,28 @@ static void setup_idt(void) set_realmode_int(0x15, bios_int15); } +static void extract_e820(void) +{ + int id = fw_cfg_file_id("etc/e820"); + uint32_t size; + + if (id == -1) + panic(); + + size = fw_cfg_file_size(id); + e820.nr_map = size / sizeof(e820.map[0]); + fw_cfg_file_select(id); + fw_cfg_read(&e820.map, size); +} + int main(void) { make_bios_writable(); setup_pic(); setup_idt(); + fw_cfg_setup(); // extract_acpi(); - // extract_e820(); + extract_e820(); // extract_smbios(); // extract_kernel(); // make_bios_readonly(); |