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); }
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_read_file(id, 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(); } } }
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) align = 16; if (zone == ALLOC_FSEG) p = malloc_fseg_align(n, align); else p = malloc_align(n, align); set_file_addr(id, p); fw_cfg_read_file(id, p, n); /* For PVH boot, save the PA where the RSDP is stored */ if (zone == ALLOC_FSEG) { if (!memcmp(p, "RSD PTR ", 8)) { start_info.rsdp_paddr = (uintptr_t)id_to_addr(id); } } }
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); }
static void extract_e820(void) { int id = fw_cfg_file_id("etc/e820"); uint32_t size; int nr_map; int i; if (id == -1) panic(); size = fw_cfg_file_size(id); nr_map = size / sizeof(e820->map[0]) + 4; fw_cfg_file_select(id); e820 = malloc(offsetof(struct e820map, map[nr_map])); e820->nr_map = nr_map; e820->map[0] = (struct e820entry) { .addr = 0, .size = 639 * 1024, .type = E820_RAM }; /* low RAM */ e820->map[1] = (struct e820entry) { .addr = 639 * 1024, .size = 1024, .type = E820_RESERVED }; /* EBDA */ e820->map[2] = (struct e820entry) { .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); for (i = 4; i < e820->nr_map; i++) if (e820->map[i].addr == 0) { lowmem = e820->map[i].size; e820->map[i].addr = 1024 * 1024; e820->map[i].size -= 1024 * 1024; break; } e820_seg = ((uintptr_t) e820) >> 4; } static bool detect_cbfs_and_boot(void) { size_t sz; void *base = pflash_base(1, &sz); if (!base) return false; return boot_from_cbfs(base, sz); } int main(void) { setup_hw(); // Now go to the F-segment: we need to move away from flash area // in order to probe CBFS! asm("ljmp $0x8, $1f; 1:"); setup_pci(); setup_idt(); fw_cfg_setup(); extract_acpi(); extract_e820(); // extract_smbios(); if (!detect_cbfs_and_boot()) boot_from_fwcfg(); panic(); }