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");
