From 001a442750aa38d7d7b59f818e5f08f674a61f09 Mon Sep 17 00:00:00 2001 From: mintsuki Date: Sun, 31 Mar 2024 09:04:39 +0200 Subject: [PATCH] limine: Add support for MAX_PAGING_MODE config option --- CONFIG.md | 3 +++ common/menu.c | 1 + common/protos/limine.c | 55 +++++++++++++++++++++++++++++++++--------- test/limine.c | 2 +- 4 files changed, 48 insertions(+), 13 deletions(-) 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 `xx`. If the resolution is not available, Limine will pick another one automatically. Omitting `` 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, };