diff options
Diffstat (limited to 'linuxboot.c')
-rw-r--r-- | linuxboot.c | 57 |
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(); +} |