diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/qboot/linuxboot.c | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/qboot/linuxboot.c')
-rw-r--r-- | roms/qboot/linuxboot.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/roms/qboot/linuxboot.c b/roms/qboot/linuxboot.c new file mode 100644 index 000000000..251bcb621 --- /dev/null +++ b/roms/qboot/linuxboot.c @@ -0,0 +1,130 @@ +#include "bios.h" +#include "linuxboot.h" +#include "memaccess.h" +#include "ioport.h" +#include "start_info.h" +#include "string.h" +#include "stdio.h" +#include "benchmark.h" + +struct hvm_start_info start_info = {0}; + +bool parse_bzimage(struct linuxboot_args *args) +{ + uint8_t *header = args->header; + + uint32_t real_addr, cmdline_addr, prot_addr, initrd_addr; + uint32_t setup_size; + uint32_t initrd_max; + uint16_t protocol; + + if (ldl_p(header+0x202) == 0x53726448) + protocol = lduw_p(header+0x206); + else { + /* assume multiboot. TODO: scan for header */ + return false; + // protocol = 0; + } + + if (protocol < 0x200 || !(header[0x211] & 0x01)) { + /* Low kernel */ + real_addr = 0x90000; + cmdline_addr = (0x9a000 - args->cmdline_size) & ~15; + prot_addr = 0x10000; + } else if (protocol < 0x202) { + /* High but ancient kernel */ + real_addr = 0x90000; + cmdline_addr = (0x9a000 - args->cmdline_size) & ~15; + prot_addr = 0x100000; + } else { + /* High and recent kernel */ + real_addr = 0x10000; + cmdline_addr = 0x20000; + prot_addr = 0x100000; + } + + if (protocol >= 0x203) + initrd_max = ldl_p(header+0x22c); + else + initrd_max = 0x37ffffff; + if (initrd_max > lowmem - 1) + initrd_max = lowmem - 1; + + if (protocol >= 0x202) + stl_p(header+0x228, cmdline_addr); + else { + stw_p(header+0x20, 0xA33F); + stw_p(header+0x22, cmdline_addr-real_addr); + } + + /* High nybble = B reserved for QEMU; low nybble is revision number. + * If this code is substantially changed, you may want to consider + * incrementing the revision. */ + if (protocol >= 0x200) + header[0x210] = 0xB0; + + /* heap */ + if (protocol >= 0x201) { + header[0x211] |= 0x80; /* CAN_USE_HEAP */ + stw_p(header+0x224, cmdline_addr-real_addr-0x200); + } + + if (args->initrd_size) + initrd_addr = (initrd_max - args->initrd_size) & ~4095; + else + initrd_addr = 0; + stl_p(header+0x218, initrd_addr); + stl_p(header+0x21c, args->initrd_size); + + /* load kernel and setup */ + setup_size = header[0x1f1]; + if (setup_size == 0) + setup_size = 4; + + args->setup_size = (setup_size+1)*512; + args->kernel_size = args->vmlinuz_size - setup_size; + args->initrd_addr = (void *)initrd_addr; + args->setup_addr = (void *)real_addr; + args->kernel_addr = (void *)prot_addr; + args->cmdline_addr = (void *)cmdline_addr; + return true; +} + +void boot_bzimage(struct linuxboot_args *args) +{ + memcpy(args->setup_addr, args->header, sizeof(args->header)); +#ifdef BENCHMARK_HACK + /* Exit just before getting to vmlinuz, so that it is easy + * to time/profile the firmware. + */ + outb(LINUX_EXIT_PORT, LINUX_START_BOOT); +#endif + asm volatile( + "ljmp $0x18, $pm16_boot_linux - 0xf0000" + : : + "b" (((uintptr_t) args->setup_addr) >> 4), + "d" (args->cmdline_addr - args->setup_addr - 16)); + panic(); +} + +/* BX = address of data block + * DX = cmdline_addr-setup_addr-16 + */ +asm("pm16_boot_linux:" + ".code16;" + "mov $0x20, %ax; mov %ax, %ds; mov %ax, %es;" + "mov %ax, %fs; mov %ax, %gs; mov %ax, %ss;" + "xor %eax, %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 + "pushw %ax;" // push IP + "xor %ebx, %ebx;" + "xor %ecx, %ecx;" + "xor %edx, %edx;" + "xor %edi, %edi;" + "xor %ebp, %ebp;" + "lret;" + ".code32"); |