| #include "bios.h" |
| #include "stdio.h" |
| #include "ioport.h" |
| #include "string.h" |
| #include "fw_cfg.h" |
| #include "linuxboot.h" |
| |
| struct fw_cfg_file { |
| uint32_t size; |
| uint16_t select; |
| char name[57]; |
| }; |
| |
| static int filecnt; |
| static struct fw_cfg_file *files; |
| |
| void fw_cfg_setup(void) |
| { |
| int i, n; |
| |
| fw_cfg_select(FW_CFG_FILE_DIR); |
| n = fw_cfg_readl_be(); |
| filecnt = n; |
| files = malloc_fseg(sizeof(files[0]) * n); |
| |
| 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 < filecnt; 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); |
| } |
| |
| 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(); |
| |
| fw_cfg_select(FW_CFG_SETUP_DATA); |
| fw_cfg_read(args.header, sizeof(args.header)); |
| |
| if (!parse_bzimage(&args)) |
| return; |
| |
| /* 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(args.kernel_addr, kernel_size); |
| |
| fw_cfg_select(FW_CFG_CMDLINE_DATA); |
| fw_cfg_read(args.cmdline_addr, args.cmdline_size); |
| |
| if (args.initrd_size) { |
| fw_cfg_select(FW_CFG_INITRD_DATA); |
| fw_cfg_read(args.initrd_addr, args.initrd_size); |
| } |
| |
| boot_bzimage(&args); |
| } |