aboutsummaryrefslogtreecommitdiffstats
path: root/roms/qboot/linuxboot.c
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/qboot/linuxboot.c
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/qboot/linuxboot.c')
-rw-r--r--roms/qboot/linuxboot.c130
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");