:: commit ffbdf54f8ee3e25c0d59e78d9d9e463869f69efe

mintsuki <mintsuki@protonmail.com> — 2024-10-31 06:53

parents: 3776825625

protos/limine: Amend base rev 3 to mandate reporting base rev used to kernels

diff --git a/PROTOCOL.md b/PROTOCOL.md
index 30629f6c..000b4cda 100644
--- a/PROTOCOL.md
+++ b/PROTOCOL.md
@@ -60,6 +60,12 @@ revision and *it* is responsible for failing to boot the kernel, in case the
 bootloader does not yet support the kernel's requested base revision,
 it is up to the kernel itself to fail (or handle the condition otherwise).
 
+For any Limine-compliant bootloader supporting base revision 3, it is *mandatory*
+to load kernels requesting higher unsupported base revisions with at least
+base revision 3, and it is mandatory for it to always set the 2nd component of
+the base revision tag to the base revision actually used to load the kernel,
+regardless of whether it was the requested one or not.
+
 ## Features
 
 The protocol is centered around the concept of request/response - collectively
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 66fbebf1..dfa7ad51 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -34,6 +34,8 @@
 #include <protos/limine.h>
 #include <limine.h>
 
+#define SUPPORTED_BASE_REVISION 3
+
 #define MAX_REQUESTS 128
 
 #define MEMMAP_MAX 1024
@@ -465,6 +467,7 @@ noreturn void limine_load(char *config, char *cmdline) {
     // Determine base revision
     LIMINE_BASE_REVISION(0);
     int base_revision = 0;
+    uint64_t *base_rev_p1_ptr = NULL;
     uint64_t *base_rev_p2_ptr = NULL;
     for (size_t i = 0; i < ALIGN_DOWN(image_size_before_bss, 8); i += 8) {
         uint64_t *p = (void *)(uintptr_t)physical_base + i;
@@ -473,6 +476,7 @@ noreturn void limine_load(char *config, char *cmdline) {
         if (p[0] == limine_requests_start_marker[0] && p[1] == limine_requests_start_marker[1]
          && p[2] == limine_requests_start_marker[2] && p[3] == limine_requests_start_marker[3]) {
             base_revision = 0;
+            base_rev_p1_ptr = NULL;
             base_rev_p2_ptr = NULL;
             continue;
         }
@@ -487,15 +491,18 @@ noreturn void limine_load(char *config, char *cmdline) {
                 panic(true, "limine: Duplicated base revision tag");
             }
             base_revision = p[2];
-            // We only support up to revision 3
-            if (p[2] <= 3) {
+            if (p[2] <= SUPPORTED_BASE_REVISION) {
                 // Set to 0 to mean "supported"
                 base_rev_p2_ptr = &p[2];
             } else {
-                base_revision = 2;
+                base_revision = SUPPORTED_BASE_REVISION;
             }
+            base_rev_p1_ptr = &p[1];
         }
     }
+    if (base_rev_p1_ptr != NULL) {
+        *base_rev_p1_ptr = base_revision;
+    }
     if (base_rev_p2_ptr != NULL) {
         *base_rev_p2_ptr = 0;
     }
diff --git a/limine.h b/limine.h
index b4b49c5d..30b9e2a1 100644
--- a/limine.h
+++ b/limine.h
@@ -57,6 +57,9 @@ extern "C" {
 
 #define LIMINE_BASE_REVISION_SUPPORTED (limine_base_revision[2] == 0)
 
+#define LIMINE_LOADED_BASE_REV_VALID (limine_base_revision[1] != 0x6a7b384944536bdc)
+#define LIMINE_LOADED_BASE_REVISION (limine_base_revision[1])
+
 #define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b
 
 struct limine_uuid {
diff --git a/test/limine.c b/test/limine.c
index 15d12026..a9b7c848 100644
--- a/test/limine.c
+++ b/test/limine.c
@@ -253,11 +253,17 @@ struct flanterm_context *ft_ctx = NULL;
 static void limine_main(void) {
     e9_printf("\nWe're alive");
 
+    if (LIMINE_LOADED_BASE_REV_VALID == true) {
+        e9_printf("Bootloader has loaded us using base revision %d", LIMINE_LOADED_BASE_REVISION);
+    }
+
     if (LIMINE_BASE_REVISION_SUPPORTED == false) {
         e9_printf("Limine base revision not supported");
         for (;;);
     }
 
+    e9_printf("");
+
     struct limine_framebuffer *fb = framebuffer_request.response->framebuffers[0];
 
     ft_ctx = flanterm_fb_init(
tab: 248 wrap: offon