diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | cstart.S | 1 | ||||
-rw-r--r-- | include/bios.h | 2 | ||||
-rw-r--r-- | linuxboot.c | 57 | ||||
-rw-r--r-- | main.c | 2 |
5 files changed, 63 insertions, 1 deletions
@@ -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 @@ -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(); +} @@ -104,6 +104,6 @@ int main(void) // extract_smbios(); // extract_kernel(); // make_bios_readonly(); - // boot_linux(); + boot_linux(); panic(); } |