static void boot_pvh_from_fw_cfg(void) { void *kernel_entry; uint32_t sz; struct linuxboot_args args; struct hvm_modlist_entry ramdisk_mod; start_info.magic = XEN_HVM_START_MAGIC_VALUE; start_info.version = 1; start_info.flags = 0; start_info.nr_modules = 0; start_info.reserved = 0; fw_cfg_select(FW_CFG_CMDLINE_SIZE); args.cmdline_size = fw_cfg_readl_le(); args.cmdline_addr = malloc(args.cmdline_size); fw_cfg_read_entry(FW_CFG_CMDLINE_DATA, args.cmdline_addr, args.cmdline_size); start_info.cmdline_paddr = (uintptr_t)args.cmdline_addr; fw_cfg_select(FW_CFG_INITRD_SIZE); args.initrd_size = fw_cfg_readl_le(); if (args.initrd_size) { fw_cfg_select(FW_CFG_INITRD_SIZE); args.initrd_addr = (void *)fw_cfg_readl_le(); fw_cfg_read_entry(FW_CFG_INITRD_DATA, args.initrd_addr, args.initrd_size); ramdisk_mod.paddr = (uintptr_t)args.initrd_addr; ramdisk_mod.size = (uintptr_t)args.initrd_size; /* The first module is always ramdisk. */ start_info.modlist_paddr = (uintptr_t)&ramdisk_mod; start_info.nr_modules = 1; } pvh_e820_setup(); fw_cfg_select(FW_CFG_KERNEL_SIZE); sz = fw_cfg_readl_le(); if (!sz) panic(); fw_cfg_select(FW_CFG_KERNEL_ENTRY); kernel_entry = (void *) fw_cfg_readl_le(); #ifdef BENCHMARK_HACK /* Exit just before jumping to vmlinux, so that it is easy * to time/profile the firmware. */ outb(LINUX_EXIT_PORT, LINUX_START_PVHBOOT); #endif asm volatile("jmp *%2" : : "a" (0x2badb002), "b"(&start_info), "c"(kernel_entry)); panic(); }
static void boot_multiboot_from_fw_cfg(void) { void *kernel_addr, *kernel_entry; struct mb_info *mb; struct mb_mmap_entry *mbmem; int i; uint32_t sz; fw_cfg_select(FW_CFG_KERNEL_SIZE); sz = fw_cfg_readl_le(); if (!sz) panic(); fw_cfg_select(FW_CFG_KERNEL_ADDR); kernel_addr = (void *) fw_cfg_readl_le(); fw_cfg_read_entry(FW_CFG_KERNEL_DATA, kernel_addr, sz); fw_cfg_select(FW_CFG_INITRD_SIZE); sz = fw_cfg_readl_le(); if (!sz) panic(); fw_cfg_select(FW_CFG_INITRD_ADDR); mb = (struct mb_info *) fw_cfg_readl_le(); fw_cfg_read_entry(FW_CFG_INITRD_DATA, mb, sz); mb->mem_lower = 639; mb->mem_upper = (lowmem - 1048576) >> 10; mb->mmap_length = 0; for (i = 0; i < e820->nr_map; i++) { mbmem = (struct mb_mmap_entry *) (mb->mmap_addr + mb->mmap_length); mbmem->size = sizeof(e820->map[i]); mbmem->base_addr = e820->map[i].addr; mbmem->length = e820->map[i].size; mbmem->type = e820->map[i].type; mb->mmap_length += sizeof(*mbmem); } #ifdef BENCHMARK_HACK /* Exit just before getting to vmlinuz, so that it is easy * to time/profile the firmware. */ outb(LINUX_EXIT_PORT, LINUX_START_FWCFG); #endif fw_cfg_select(FW_CFG_KERNEL_ENTRY); kernel_entry = (void *) fw_cfg_readl_le(); asm volatile("jmp *%2" : : "a" (0x2badb002), "b"(mb), "c"(kernel_entry)); panic(); }
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 void fw_cfg_comb_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { switch (size) { case 1: fw_cfg_write(opaque, (uint8_t)value); break; case 2: fw_cfg_select(opaque, (uint16_t)value); break; } }
void fw_cfg_read_entry(int e, void *buf, int len) { if (version & FW_CFG_VERSION_DMA) { int control; control = (e << 16); control |= FW_CFG_DMA_CTL_SELECT; control |= FW_CFG_DMA_CTL_READ; fw_cfg_dma(control, buf, len); } else { fw_cfg_select(e); insb(buf, FW_CFG_DATA, len); } }
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); }
static int fwcfg_emulator_reset(struct vmm_emudev *edev) { fw_cfg_select(edev->priv, 0); return VMM_OK; }
static void fw_cfg_ctl_mem_write(void *opaque, u64 value) { fw_cfg_select(opaque, (u16)value); }
static void fw_cfg_reset(DeviceState *d) { FWCfgState *s = FW_CFG(d); fw_cfg_select(s, 0); }
static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { fw_cfg_select(opaque, (uint16_t)value); }
static void fw_cfg_reset(DeviceState *d) { FWCfgState *s = DO_UPCAST(FWCfgState, busdev.qdev, d); fw_cfg_select(s, 0); }
void fw_cfg_file_select(int id) { fw_cfg_select(files[id].select); }
static void fw_cfg_reset(void *opaque) { FWCfgState *s = opaque; fw_cfg_select(s, 0); }
static void fw_cfg_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t value) { fw_cfg_select(opaque, (uint16_t)value); }
static void fw_cfg_io_writew(void *opaque, uint32_t addr, uint32_t value) { fw_cfg_select(opaque, (uint16_t)value); }
static void fw_cfg_ctl_mem_write(void *opaque, target_phys_addr_t addr, uint64_t value, unsigned size) { fw_cfg_select(opaque, (uint16_t)value); }