diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2015-05-25 10:22:13 +0200 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-05-25 13:27:03 +0200 |
commit | c4b724bd7ca65b8945ef683f33c0aa06152a381f (patch) | |
tree | 8c121bab259b888665bff6b313232610febba314 | |
parent | ea5e0fffab02eb12ab08dcc3563824f2dd28beac (diff) | |
download | qboot-c4b724bd7ca65b8945ef683f33c0aa06152a381f.zip qboot-c4b724bd7ca65b8945ef683f33c0aa06152a381f.tar.gz qboot-c4b724bd7ca65b8945ef683f33c0aa06152a381f.tar.bz2 |
load ACPI tables from fw_cfg
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README | 1 | ||||
-rw-r--r-- | fw_cfg.c | 2 | ||||
-rw-r--r-- | include/bios.h | 1 | ||||
-rw-r--r-- | include/fw_cfg.h | 2 | ||||
-rw-r--r-- | main.c | 4 | ||||
-rw-r--r-- | tables.c | 160 |
7 files changed, 168 insertions, 4 deletions
@@ -1,5 +1,5 @@ obj-y = code16.o entry.o main.o string.o printf.o cstart.o fw_cfg.o -obj-y += linuxboot.o malloc.o pflash.o cbfs.o +obj-y += linuxboot.o malloc.o pflash.o cbfs.o tables.o all-y = bios.bin all: $(all-y) @@ -45,6 +45,5 @@ cbfs-based example (pflash isn't the definitive interface though): TODO ==== -* ACPI tables * SMBIOS tables * Multiboot loading @@ -44,6 +44,8 @@ int fw_cfg_file_id(char *name) uint32_t fw_cfg_file_size(int id) { + if (id == -1) + return 0; return files[id].size; } diff --git a/include/bios.h b/include/bios.h index 4ed3a1a..ed2cab4 100644 --- a/include/bios.h +++ b/include/bios.h @@ -38,6 +38,7 @@ extern void bios_irq(void); extern void bios_int10(void); extern void bios_int15(void); +extern void extract_acpi(void); extern void boot_from_fwcfg(void); extern bool boot_from_cbfs(void *base, size_t sz); diff --git a/include/fw_cfg.h b/include/fw_cfg.h index 57afa14..a846812 100644 --- a/include/fw_cfg.h +++ b/include/fw_cfg.h @@ -39,6 +39,8 @@ #define FW_CFG_CTL 0x510 #define FW_CFG_DATA 0x511 +#include "ioport.h" + static inline void fw_cfg_select(uint16_t f) { outw(FW_CFG_CTL, f); @@ -114,7 +114,7 @@ static void extract_e820(void) e820->map[1] = (struct e820entry) { .addr = 639 * 1024, .size = 1024, .type = E820_RESERVED }; /* EBDA */ e820->map[2] = (struct e820entry) - { .addr = 0xe0000, .size = 64 * 1024, .type = E820_NVS }; /* ACPI tables */ + { .addr = 0xd0000, .size = 128 * 1024, .type = E820_NVS }; /* ACPI tables */ e820->map[3] = (struct e820entry) { .addr = 0xf0000, .size = 64 * 1024, .type = E820_RESERVED }; /* firmware */ fw_cfg_read(&e820->map[4], size); @@ -146,7 +146,7 @@ int main(void) setup_pic(); setup_idt(); fw_cfg_setup(); - // extract_acpi(); + extract_acpi(); extract_e820(); // extract_smbios(); if (!detect_cbfs_and_boot()) diff --git a/tables.c b/tables.c new file mode 100644 index 0000000..3f59b3e --- /dev/null +++ b/tables.c @@ -0,0 +1,160 @@ +#include "bios.h" +#include "stdio.h" +#include "fw_cfg.h" +#include "string.h" + +struct loader_cmd { + uint32_t cmd; + union { +#define CMD_QUIT 0 +#define CMD_ALLOC 1 + struct { + char file[56]; + uint32_t align; + uint8_t zone; + } alloc; +#define CMD_PTR 2 + struct { + char dest[56]; + char src[56]; + uint32_t offset; + uint8_t size; + } ptr; +#define CMD_CHECKSUM 3 + struct { + char file[56]; + uint32_t offset; + uint32_t start; + uint32_t len; + } checksum; + uint8_t pad[124]; + }; +} __attribute__((__packed__)); + +enum { + ALLOC_HIGH = 1, + ALLOC_FSEG = 2 +}; + +static uint8_t *file_address[20]; + +static inline void *id_to_addr(int fw_cfg_id) +{ + return file_address[fw_cfg_id]; +} + +static inline void set_file_addr(int fw_cfg_id, void *p) +{ + file_address[fw_cfg_id] = p; +} + +static void do_alloc(char *file, uint32_t align, uint8_t zone) +{ + int id = fw_cfg_file_id(file); + int n = fw_cfg_file_size(id); + char *p; + + if (id == -1) + panic(); + + if (align > 16) + n += align - 16; + + if (zone == ALLOC_FSEG) + p = malloc_fseg(n); + else + p = malloc(n); + + p = (char *)((uintptr_t)(p + align - 1) & -align); + + set_file_addr(id, p); + fw_cfg_file_select(id); + fw_cfg_read(p, n); +} + +static void do_ptr(char *dest, char *src, uint32_t offset, uint8_t size) +{ + char *p, *q; + int id; + union { + long long ll; + char b[8]; + } data; + + id = fw_cfg_file_id(src); + p = id_to_addr(id); + if (!p) + panic(); + + id = fw_cfg_file_id(dest); + q = id_to_addr(id); + if (!q) + panic(); + + q += offset; + + /* Assumes little endian */ + data.ll = 0; + memcpy(&data.b, q, size); + data.ll += (uintptr_t) p; + memcpy(q, &data.b, size); +} + +static inline uint8_t csum8(uint8_t *buf, uint32_t len) +{ + uint32_t s = 0; + while (len-- > 0) + s += *buf++; + return s; +} +static void do_checksum(char *file, uint32_t offset, uint32_t start, uint32_t len) +{ + uint8_t *p; + int id; + int n; + + id = fw_cfg_file_id(file); + p = id_to_addr(id); + if (!p) + panic(); + + n = fw_cfg_file_size(id); + if (offset >= n || n < start || len > n - start) + panic(); + + p[offset] -= csum8(&p[start], len); +} + +void extract_acpi(void) +{ + int id = fw_cfg_file_id("etc/table-loader"); + int n = fw_cfg_file_size(id); + struct loader_cmd script[n / sizeof(struct loader_cmd)]; + int i; + + if (!n) + return; + + fw_cfg_file_select(id); + fw_cfg_read(script, n); + + for (i = 0; i < ARRAY_SIZE(script); i++) { + struct loader_cmd *s = &script[i]; + switch(script[i].cmd) { + case CMD_ALLOC: + do_alloc(s->alloc.file, s->alloc.align, s->alloc.zone); + break; + case CMD_PTR: + do_ptr(s->ptr.dest, s->ptr.src, s->ptr.offset, s->ptr.size); + break; + case CMD_CHECKSUM: + do_checksum(s->checksum.file, s->checksum.offset, + s->checksum.start, s->checksum.len); + break; + case CMD_QUIT: + return; + default: + panic(); + } + } +} |