void boot_from_fwcfg(void) { struct linuxboot_args args; uint32_t kernel_size; fw_cfg_select(FW_CFG_CMDLINE_SIZE); args.cmdline_size = fw_cfg_readl_le(); fw_cfg_select(FW_CFG_INITRD_SIZE); args.initrd_size = fw_cfg_readl_le(); /* QEMU has already split the real mode and protected mode * parts. Recombine them in args.vmlinuz_size. */ fw_cfg_select(FW_CFG_KERNEL_SIZE); kernel_size = fw_cfg_readl_le(); fw_cfg_select(FW_CFG_SETUP_SIZE); args.vmlinuz_size = kernel_size + fw_cfg_readl_le(); if (!args.vmlinuz_size) return; fw_cfg_select(FW_CFG_SETUP_DATA); fw_cfg_read(args.header, sizeof(args.header)); if (!parse_bzimage(&args)) { uint8_t *header = args.header; if (ldl_p(header) == 0x464c457f) /* ELF magic */ boot_pvh_from_fw_cfg(); boot_multiboot_from_fw_cfg(); } /* SETUP_DATA already selected */ if (args.setup_size > sizeof(args.header)) fw_cfg_read(args.setup_addr + sizeof(args.header), args.setup_size - sizeof(args.header)); fw_cfg_select(FW_CFG_KERNEL_DATA); fw_cfg_read_entry(FW_CFG_KERNEL_DATA, args.kernel_addr, kernel_size); fw_cfg_read_entry(FW_CFG_CMDLINE_DATA, args.cmdline_addr, args.cmdline_size); if (args.initrd_size) { fw_cfg_read_entry(FW_CFG_INITRD_DATA, args.initrd_addr, args.initrd_size); } boot_bzimage(&args); }
uint16_t fw_cfg_read_i16(uint16_t cmd) { uint16_t buf; fw_cfg_read(cmd, (char *)&buf, sizeof(uint16_t)); return __le16_to_cpu(buf); }
static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr, unsigned size) { FWCfgState *s = opaque; uint64_t value = 0; unsigned i; for (i = 0; i < size; ++i) { value = (value << 8) | fw_cfg_read(s); } return value; }
void fw_cfg_setup(void) { int i, n; fw_cfg_select(FW_CFG_ID); version = fw_cfg_readl_le(); fw_cfg_select(FW_CFG_FILE_DIR); n = fw_cfg_readl_be(); filecnt = n; files = malloc_fseg(sizeof(files[0]) * n); fw_cfg_read(files, sizeof(files[0]) * n); for (i = 0; i < n; i++) { struct fw_cfg_file *f = &files[i]; f->size = bswap32(f->size); f->select = bswap16(f->select); } }
static u64 fw_cfg_data_mem_read(void *opaque, physical_addr_t addr) { return fw_cfg_read(opaque); }
static uint64_t fw_cfg_comb_read(void *opaque, hwaddr addr, unsigned size) { return fw_cfg_read(opaque); }
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(); }
static uint32_t fw_cfg_mem_readb(void *opaque, target_phys_addr_t addr) { return fw_cfg_read(opaque); }
static uint32_t fw_cfg_io_readb(void *opaque, uint32_t addr) { return fw_cfg_read(opaque); }
static uint64_t fw_cfg_comb_read(void *opaque, target_phys_addr_t addr, unsigned size) { return fw_cfg_read(opaque); }