:: commit 001a442750aa38d7d7b59f818e5f08f674a61f09

mintsuki <mintsuki@protonmail.com> — 2024-03-31 07:04

parents: f4ebb6f4d7

limine: Add support for MAX_PAGING_MODE config option

diff --git a/CONFIG.md b/CONFIG.md
index 9a11da18..c4f22c23 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -123,6 +123,9 @@ Editor control options:
   * `MODULE_CMDLINE` - A command line to be passed to a module. This key can also be specified multiple times. It applies to the module described by the last module key assigned.
   * `RESOLUTION` - The resolution to be used. This setting takes the form of `<width>x<height>x<bpp>`. If the resolution is not available, Limine will pick another one automatically. Omitting `<bpp>` will default to 32.
   * `KASLR` - For relocatable kernels, if set to `no`, disable kernel address space layout randomisation. KASLR is enabled by default.
+  * `MAX_PAGING_MODE` - Limit the maximum paging mode to one of the following:
+    - x86-64 and aarch64: `4level`, `5level`.
+    - riscv64: `sv39`, `sv48`, `sv57`.
 
 * multiboot1 and multiboot2 protocols:
   * `KERNEL_PATH` - The URI path of the kernel.
diff --git a/common/menu.c b/common/menu.c
index d42840c3..8edcc924 100644
--- a/common/menu.c
+++ b/common/menu.c
@@ -101,6 +101,7 @@ static const char *VALID_KEYS[] = {
     "RESOLUTION",
     "TEXTMODE",
     "KASLR",
+    "MAX_PAGING_MODE",
     "DRIVE",
     "PARTITION",
     "MBR_ID",
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 755a18d0..fc53bbc1 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -440,22 +440,22 @@ noreturn void limine_load(char *config, char *cmdline) {
     printv("limine: Requests count:  %u\n", requests_count);
 
     // Paging Mode
-    int paging_mode, max_paging_mode;
+    int paging_mode, max_supported_paging_mode;
 
 #if defined (__x86_64__) || defined (__i386__)
-    paging_mode = max_paging_mode = PAGING_MODE_X86_64_4LVL;
+    paging_mode = max_supported_paging_mode = PAGING_MODE_X86_64_4LVL;
     if (cpuid(0x00000007, 0, &eax, &ebx, &ecx, &edx) && (ecx & (1 << 16))) {
         printv("limine: CPU has 5-level paging support\n");
-        max_paging_mode = PAGING_MODE_X86_64_5LVL;
+        max_supported_paging_mode = PAGING_MODE_X86_64_5LVL;
     }
 
 #elif defined (__aarch64__)
-    paging_mode = max_paging_mode = PAGING_MODE_AARCH64_4LVL;
+    paging_mode = max_supported_paging_mode = PAGING_MODE_AARCH64_4LVL;
     // TODO(qookie): aarch64 also has optional 5 level paging when using 4K pages
 
 #elif defined (__riscv64)
-    max_paging_mode = vmm_max_paging_mode();
-    paging_mode = max_paging_mode >= PAGING_MODE_RISCV_SV48 ? PAGING_MODE_RISCV_SV48 : PAGING_MODE_RISCV_SV39;
+    max_supported_paging_mode = vmm_max_paging_mode();
+    paging_mode = max_supported_paging_mode >= PAGING_MODE_RISCV_SV48 ? PAGING_MODE_RISCV_SV48 : PAGING_MODE_RISCV_SV39;
 
 #else
 #error Unknown architecture
@@ -475,14 +475,45 @@ FEAT_START
     if (pm_request == NULL)
         break;
 
-    if (pm_request->mode > LIMINE_PAGING_MODE_MAX) {
-        print("warning: ignoring invalid mode in paging mode request\n");
-        break;
+    uint64_t paging_mode_max = LIMINE_PAGING_MODE_MAX;
+
+    char *max_paging_mode_s = config_get_value(config, 0, "MAX_PAGING_MODE");
+    if (max_paging_mode_s != NULL) {
+#if defined (__x86_64__) || defined (__i386__)
+        if (strcasecmp(max_paging_mode_s, "4level") == 0) {
+            paging_mode_max = LIMINE_PAGING_MODE_X86_64_4LVL;
+        } else if (strcasecmp(max_paging_mode_s, "5level") == 0) {
+            paging_mode_max = LIMINE_PAGING_MODE_X86_64_5LVL;
+        }
+#elif defined (__aarch64__)
+        if (strcasecmp(max_paging_mode_s, "4level") == 0) {
+            paging_mode_max = LIMINE_PAGING_MODE_AARCH64_4LVL;
+        } else if (strcasecmp(max_paging_mode_s, "5level") == 0) {
+            paging_mode_max = LIMINE_PAGING_MODE_AARCH64_5LVL;
+        }
+#elif defined (__riscv64)
+        if (strcasecmp(max_paging_mode_s, "sv39") == 0) {
+            paging_mode_max = LIMINE_PAGING_MODE_RISCV_SV39;
+        } else if (strcasecmp(max_paging_mode_s, "sv48") == 0) {
+            paging_mode_max = LIMINE_PAGING_MODE_RISCV_SV48;
+        } else if (strcasecmp(max_paging_mode_s, "sv57") == 0) {
+            paging_mode_max = LIMINE_PAGING_MODE_RISCV_SV57;
+        }
+#endif
+        else {
+            panic(true, "limine: Invalid MAX_PAGING_MODE: `%s`", max_paging_mode_s);
+        }
     }
 
-    paging_mode = paging_mode_limine_to_vmm(pm_request->mode);
-    if (paging_mode > max_paging_mode)
-        paging_mode = max_paging_mode;
+    uint64_t target_mode = pm_request->mode;
+    if (pm_request->mode > paging_mode_max) {
+        target_mode = paging_mode_max;
+    }
+
+    paging_mode = paging_mode_limine_to_vmm(target_mode);
+    if (paging_mode > max_supported_paging_mode) {
+        paging_mode = max_supported_paging_mode;
+    }
 
     set_paging_mode(paging_mode, kaslr);
     paging_mode_set = true;
diff --git a/test/limine.c b/test/limine.c
index d098a44c..a614d7bc 100644
--- a/test/limine.c
+++ b/test/limine.c
@@ -132,7 +132,7 @@ __attribute__((section(".limine_requests")))
 static volatile struct limine_paging_mode_request _pm_request = {
     .id = LIMINE_PAGING_MODE_REQUEST,
     .revision = 0, .response = NULL,
-    .mode = LIMINE_PAGING_MODE_DEFAULT,
+    .mode = LIMINE_PAGING_MODE_X86_64_5LVL,
     .flags = 0,
 };
 
tab: 248 wrap: offon