aboutsummaryrefslogtreecommitdiff
path: root/fw_cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw_cfg.c')
-rw-r--r--fw_cfg.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/fw_cfg.c b/fw_cfg.c
index 293e4be..c1b354e 100644
--- a/fw_cfg.c
+++ b/fw_cfg.c
@@ -1,7 +1,9 @@
#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;
@@ -48,3 +50,46 @@ 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);
+}