:: commit 40a63ecb8888748e4435b9b236594712a99adad2

mintsuki <mintsuki@protonmail.com> — 2020-05-06 15:00

parents: 35376681e3

Initial chainloading support

diff --git a/CONFIG.md b/CONFIG.md
index 78d89a04..609dc6f9 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -23,7 +23,7 @@ Some *local assignments* are shared between entries using any *protocol*, while
 * `TIMEOUT` - Specifies the timeout in seconds before the first *entry* is automatically booted.
 
 *Locally assignable (non protocol specific)* keys are:
-* `PROTOCOL` - The boot protocol that will be used to boot the kernel. Valid protocols are: `linux`, `stivale`.
+* `PROTOCOL` - The boot protocol that will be used to boot the kernel. Valid protocols are: `linux`, `stivale`, `chainload`.
 * `KERNEL_PROTO` - Alias of `PROTOCOL`.
 * `CMDLINE` - The command line string to be passed to the kernel. Can be omitted.
 * `KERNEL_CMDLINE` - Alias of `CMDLINE`.
@@ -42,6 +42,9 @@ Some *local assignments* are shared between entries using any *protocol*, while
   * `MODULE_PARTITION` - Partition index of a module.
   * `MODULE_PATH` - The path to a module.
   * `MODULE_STRING` - A string to be passed to a module.
+* chainload protocol:
+  * `DRIVE` - The drive to chainload.
+  * `PARTITION` - The partition to chainload.
 
   Note that one can define these 3 variable multiple times to specify multiple modules.
   The entries will be matched in order. E.g.: the 1st partition entry will be matched
diff --git a/qloader2.bin b/qloader2.bin
index 8337c452..f7ab1452 100644
Binary files a/qloader2.bin and b/qloader2.bin differ
diff --git a/src/main.c b/src/main.c
index f6553dd4..a04f2157 100644
--- a/src/main.c
+++ b/src/main.c
@@ -25,6 +25,7 @@ asm (
 #include <lib/elf.h>
 #include <protos/stivale.h>
 #include <protos/linux.h>
+#include <protos/chainload.h>
 
 static char *cmdline;
 #define CMDLINE_MAX 1024
@@ -164,6 +165,8 @@ got_entry:
         stivale_load(cmdline, boot_drive);
     } else if (!strcmp(proto, "linux")) {
         linux_load(cmdline, boot_drive);
+    } else if (!strcmp(proto, "chainload")) {
+        chainload();
     } else {
         panic("Invalid protocol specified");
     }
diff --git a/src/protos/chainload.c b/src/protos/chainload.c
new file mode 100644
index 00000000..fef3bf1e
--- /dev/null
+++ b/src/protos/chainload.c
@@ -0,0 +1,61 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <protos/chainload.h>
+#include <lib/part.h>
+#include <lib/config.h>
+#include <lib/blib.h>
+#include <drivers/disk.h>
+#include <drivers/vga_textmode.h>
+
+void chainload(void) {
+    int part; {
+        char buf[32];
+        if (!config_get_value(buf, 0, 32, "PARTITION")) {
+            panic("PARTITION not specified");
+        }
+        part = (int)strtoui(buf);
+    }
+    int drive; {
+        char buf[32];
+        if (!config_get_value(buf, 0, 32, "DRIVE")) {
+            panic("DRIVE not specified");
+        }
+        drive = (int)strtoui(buf);
+    }
+
+    deinit_vga_textmode();
+
+    struct part p;
+    get_part(&p, drive, part);
+
+    read_partition(drive, &p, (void*)0x7c00, 0, 512);
+
+    asm volatile (
+        // Jump to real mode
+        "jmp 0x08:1f\n\t"
+        "1: .code16\n\t"
+        "mov ax, 0x10\n\t"
+        "mov ds, ax\n\t"
+        "mov es, ax\n\t"
+        "mov fs, ax\n\t"
+        "mov gs, ax\n\t"
+        "mov ss, ax\n\t"
+        "mov eax, cr0\n\t"
+        "and al, 0xfe\n\t"
+        "mov cr0, eax\n\t"
+        "jmp 0:2f\n\t"
+        "2:\n\t"
+        "mov ax, 0\n\t"
+        "mov ds, ax\n\t"
+        "mov es, ax\n\t"
+        "mov fs, ax\n\t"
+        "mov gs, ax\n\t"
+        "mov ss, ax\n\t"
+        "push 0\n\t"
+        "push 0x7c00\n\t"
+        "retf\n\t"
+        ".code32\n\t"
+        :
+        : "d" (drive)
+    );
+}
diff --git a/src/protos/chainload.h b/src/protos/chainload.h
new file mode 100644
index 00000000..43621937
--- /dev/null
+++ b/src/protos/chainload.h
@@ -0,0 +1,6 @@
+#ifndef __PROTOS__CHAINLOAD_H__
+#define __PROTOS__CHAINLOAD_H__
+
+void chainload(void);
+
+#endif
tab: 248 wrap: offon