:: commit 5f6b2faf26d5f6deade73d68f245c2178ed55d06

Mintsuki <mintsuki@protonmail.com> — 2025-09-21 07:16

parents: 30c5a373ae

mm/pmm: Add validation of allocated memory viability on x86_64/UEFI

diff --git a/common/entry.s2.c b/common/entry.s2.c
index 841fa67f..9de0697f 100644
--- a/common/entry.s2.c
+++ b/common/entry.s2.c
@@ -87,11 +87,11 @@ noreturn void entry(uint8_t boot_drive, int boot_from) {
 
     uint64_t usec_at_entry = rdtsc_usec();
 
+    idt_init();
+
     init_e820();
     init_memmap();
 
-    idt_init();
-
     disk_create_index();
 
     if (boot_from == BOOTED_FROM_HDD || boot_from == BOOTED_FROM_CD) {
diff --git a/common/entry.s3.c b/common/entry.s3.c
index 8d8ca7e3..cfe8544c 100644
--- a/common/entry.s3.c
+++ b/common/entry.s3.c
@@ -71,6 +71,10 @@ defer_error:
 
     gST->ConOut->EnableCursor(gST->ConOut, false);
 
+#if defined (__x86_64__) || defined (__i386__)
+    idt_init();
+#endif
+
     init_memmap();
 
     term_fallback();
@@ -165,7 +169,6 @@ opened:
 
 noreturn void stage3_common(void) {
 #if defined (__x86_64__) || defined (__i386__)
-    idt_init();
     init_io_apics();
 #endif
 
diff --git a/common/mm/pmm.s2.c b/common/mm/pmm.s2.c
index 3bd579db..d3d45c89 100644
--- a/common/mm/pmm.s2.c
+++ b/common/mm/pmm.s2.c
@@ -8,6 +8,10 @@
 #include <lib/libc.h>
 #include <lib/print.h>
 #if defined (UEFI)
+#  if defined (__x86_64__)
+#    include <sys/idt.h>
+#    include <sys/gdt.h>
+#  endif
 #  include <efi.h>
 #endif
 
@@ -297,6 +301,66 @@ static struct memmap_entry *recl;
 
 extern symbol __slide, __image_base, __image_end;
 
+#if defined (__x86_64__)
+
+void dummy_isr(void);
+static volatile bool access_validation_success;
+static volatile void *page_fault_handler_ret;
+
+__attribute__((interrupt)) static void page_fault_handler(void *unused) {
+    (void)unused;
+    access_validation_success = false;
+    asm volatile (
+        "mov %0, (%%esp)\n\t"
+        :
+        : "r"(page_fault_handler_ret)
+        : "memory"
+    );
+}
+
+static bool validate_accessibility(void *addr) {
+    access_validation_success = true;
+
+    asm volatile ("cli");
+
+    struct gdtr original_gdtr;
+    asm volatile ("sgdt %0" : "=m"(original_gdtr) :: "memory");
+
+    asm volatile ("lgdt %0" :: "m"(gdt) : "memory");
+
+    struct idtr original_idtr;
+    asm volatile ("sidt %0" : "=m"(original_idtr) :: "memory");
+
+    struct idtr idtr = {
+        IDT_ENTRY_COUNT * sizeof(struct idt_entry) - 1,
+        (uintptr_t)idt
+    };
+
+    asm volatile ("lidt %0" :: "m"(idtr) : "memory");
+
+    idt_register_isr(0x0e, page_fault_handler, 0x8e);
+
+    page_fault_handler_ret = &&actual_return;
+
+    *(volatile uint8_t *)addr = 0xc3; // 0xc3 = ret
+
+    void (*callback)(void) = addr;
+
+    callback();
+
+actual_return:
+    idt_register_isr(0x0e, dummy_isr, 0x8e);
+    asm volatile ("lidt %0" :: "m"(original_idtr) : "memory");
+
+    asm volatile ("lgdt %0" :: "m"(original_gdtr) : "memory");
+
+    asm volatile ("sti");
+
+    return access_validation_success;
+}
+
+#endif
+
 void init_memmap(void) {
     EFI_STATUS status;
 
@@ -400,11 +464,27 @@ void init_memmap(void) {
 
         status = gBS->AllocatePages(AllocateAddress, EfiLoaderCode,
                                     untouched_memmap[i].length / 4096, &base);
+#if defined (__x86_64__)
+        if (status == 0) {
+            if (!validate_accessibility((void *)base)) {
+                memmap_alloc_range(base, untouched_memmap[i].length, MEMMAP_EFI_RECLAIMABLE, MEMMAP_USABLE, true, false, false);
+            }
+            continue;
+        }
+#endif
 
         if (status) {
             for (size_t j = 0; j < untouched_memmap[i].length; j += 4096) {
                 base = untouched_memmap[i].base + j;
                 status = gBS->AllocatePages(AllocateAddress, EfiLoaderCode, 1, &base);
+#if defined (__x86_64__)
+                if (status == 0) {
+                    if (!validate_accessibility((void *)base)) {
+                        memmap_alloc_range(base, 4096, MEMMAP_EFI_RECLAIMABLE, MEMMAP_USABLE, true, false, false);
+                    }
+                    continue;
+                }
+#endif
                 if (status) {
                     memmap_alloc_range(base, 4096, MEMMAP_EFI_RECLAIMABLE, MEMMAP_USABLE, true, false, false);
                 }
diff --git a/common/sys/idt.c b/common/sys/idt.c
index e8267f09..48881b5b 100644
--- a/common/sys/idt.c
+++ b/common/sys/idt.c
@@ -28,7 +28,7 @@ void flush_irqs(void) {
     asm volatile ("sidt %0" : "=m"(old_idt) :: "memory");
 
     struct idtr new_idt = {
-        256 * sizeof(struct idt_entry) - 1,
+        IDT_ENTRY_COUNT * sizeof(struct idt_entry) - 1,
         (uintptr_t)idt
     };
     asm volatile ("lidt %0" :: "m"(new_idt) : "memory");
diff --git a/common/sys/idt.h b/common/sys/idt.h
index 0d7cb0b1..d3a74ad2 100644
--- a/common/sys/idt.h
+++ b/common/sys/idt.h
@@ -44,7 +44,13 @@ enum {
     IRQ_PIC_APIC_FLUSH
 };
 
-extern struct idt_entry *idt;
+#if defined (UEFI)
+#  define IDT_ENTRY_COUNT 256
+#elif defined (BIOS)
+#  define IDT_ENTRY_COUNT 32
+#endif
+
+extern struct idt_entry idt[IDT_ENTRY_COUNT];
 extern int irq_flush_type;
 
 void idt_init(void);
diff --git a/common/sys/idt.s2.c b/common/sys/idt.s2.c
index 87b93df4..60cd9ac9 100644
--- a/common/sys/idt.s2.c
+++ b/common/sys/idt.s2.c
@@ -6,7 +6,7 @@
 #include <lib/misc.h>
 #include <mm/pmm.h>
 
-struct idt_entry *idt = NULL;
+struct idt_entry idt[IDT_ENTRY_COUNT];
 
 void idt_register_isr(size_t vec, void *handler, uint8_t type) {
     uint32_t p = (uintptr_t)handler;
@@ -31,24 +31,16 @@ extern void *exceptions[];
 
 void idt_init(void) {
 #if defined (UEFI)
-    size_t idt_entry_count = 256;
-#elif defined (BIOS)
-    size_t idt_entry_count = 32;
-#endif
-    size_t idt_size = idt_entry_count * sizeof(struct idt_entry);
-    idt = ext_mem_alloc(idt_size);
-
-#if defined (UEFI)
-    for (size_t i = 0; i < idt_entry_count; i++) {
+    for (size_t i = 0; i < IDT_ENTRY_COUNT; i++) {
         idt_register_isr(i, dummy_isr, 0x8e);
     }
 #elif defined (BIOS)
-    for (size_t i = 0; i < idt_entry_count; i++) {
+    for (size_t i = 0; i < IDT_ENTRY_COUNT; i++) {
         idt_register_isr(i, exceptions[i], 0x8e);
     }
 
     struct idtr idtr = {
-        256 * sizeof(struct idt_entry) - 1,
+        IDT_ENTRY_COUNT * sizeof(struct idt_entry) - 1,
         (uintptr_t)idt
     };
     asm volatile ("lidt %0" :: "m"(idtr) : "memory");
tab: 248 wrap: offon