aboutsummaryrefslogtreecommitdiff
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
parent2e7cb17c15c64bfe6394b2a1951fa187c2620c7d (diff)
downloadqboot-c3773639dbec70a109e5eddc6a729196356ecce1.zip
qboot-c3773639dbec70a109e5eddc6a729196356ecce1.tar.gz
qboot-c3773639dbec70a109e5eddc6a729196356ecce1.tar.bz2
boot the kernel
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--Makefile2
-rw-r--r--cstart.S1
-rw-r--r--include/bios.h2
-rw-r--r--linuxboot.c57
-rw-r--r--main.c2
5 files changed, 63 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index fa43371..4e41822 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,7 @@
obj16-y = e820.o int10.o int15.o
obj-y = $(obj16-y) entry.o main.o string.o printf.o cstart.o fw_cfg.o
+obj-y += linuxboot.o
+
all-y = bios.bin
CFLAGS := -O2 -Wall -g
diff --git a/cstart.S b/cstart.S
index 5ca61c8..cef3950 100644
--- a/cstart.S
+++ b/cstart.S
@@ -25,6 +25,7 @@ gdt32:
.quad 0
.quad 0x00cf9b000000ffff // flat 32-bit code segment
.quad 0x00cf93000000ffff // flat 32-bit data segment
+ .quad 0x008f9b0f0000ffff // 16-bit code segment at 0xF0000
gdt32_end:
gdt32_descr:
diff --git a/include/bios.h b/include/bios.h
index bd7f77b..dfc20af 100644
--- a/include/bios.h
+++ b/include/bios.h
@@ -36,6 +36,8 @@ extern void bios_irq(void);
extern void bios_int10(void);
extern void bios_int15(void);
+extern void boot_linux(void);
+
extern struct e820map e820;
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
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();
+}
diff --git a/main.c b/main.c
index 2378abb..e954d75 100644
--- a/main.c
+++ b/main.c
@@ -104,6 +104,6 @@ int main(void)
// extract_smbios();
// extract_kernel();
// make_bios_readonly();
- // boot_linux();
+ boot_linux();
panic();
}