aboutsummaryrefslogtreecommitdiff
path: root/linuxboot.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2015-05-20 23:46:42 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2015-05-21 11:44:57 +0200
commitc3773639dbec70a109e5eddc6a729196356ecce1 (patch)
tree9d5bdab2fc70ef9ae24e3f9c1f2661dcff87ecaa /linuxboot.c
parent2e7cb17c15c64bfe6394b2a1951fa187c2620c7d (diff)
downloadqboot-c3773639dbec70a109e5eddc6a729196356ecce1.zip
qboot-c3773639dbec70a109e5eddc6a729196356ecce1.tar.gz
qboot-c3773639dbec70a109e5eddc6a729196356ecce1.tar.bz2
boot the kernel
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'linuxboot.c')
-rw-r--r--linuxboot.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/linuxboot.c b/linuxboot.c
new file mode 100644
index 0000000..51bfba3
--- /dev/null
+++ b/linuxboot.c
@@ -0,0 +1,57 @@
+#include "bios.h"
+#include "ioport.h"
+#include "fw_cfg.h"
+
+static void *_fw_cfg_read_blob(int faddr, int fsize, int fdata)
+{
+ void *addr;
+ int length;
+
+ fw_cfg_select(faddr);
+ addr = (void *)fw_cfg_readl_le();
+ fw_cfg_select(fsize);
+ length = fw_cfg_readl_le();
+ fw_cfg_select(fdata);
+ fw_cfg_read(addr, length);
+ return addr;
+}
+
+/* BX = address of data block
+ * DX = cmdline_addr-setup_addr-16
+ */
+asm("pm16_boot_linux:"
+ ".code16;"
+ "mov $0, %eax; mov %eax, %cr0;"
+ "ljmpl $0xf000, $(1f - 0xf0000); 1:"
+ "mov %bx, %ds; mov %bx, %es;"
+ "mov %bx, %fs; mov %bx, %gs; mov %bx, %ss;"
+ "mov %dx, %sp;"
+ "add $0x20, %bx; pushw %bx;" // push CS
+ "xor %eax, %eax; pushw %ax;" // push IP
+ "xor %ebx, %ebx;"
+ "xor %ecx, %ecx;"
+ "xor %edx, %edx;"
+ "xor %edi, %edi;"
+ "xor %ebp, %ebp;"
+ "lret;"
+ ".code32");
+
+void boot_linux(void)
+{
+ void *setup_addr, *cmdline_addr;
+
+#define fw_cfg_read_blob(f) \
+ _fw_cfg_read_blob(f##_ADDR, f##_SIZE, f##_DATA)
+
+ setup_addr = fw_cfg_read_blob(FW_CFG_SETUP);
+ cmdline_addr = fw_cfg_read_blob(FW_CFG_CMDLINE);
+ fw_cfg_read_blob(FW_CFG_INITRD);
+ fw_cfg_read_blob(FW_CFG_KERNEL);
+
+ asm volatile(
+ "ljmp $0x18, $pm16_boot_linux - 0xf0000"
+ : :
+ "b" (((uintptr_t) setup_addr) >> 4),
+ "d" (cmdline_addr - setup_addr - 16));
+ panic();
+}