stivale: Initial infrastructure to support ELF permissions
diff --git a/stage23/mm/vmm.c b/stage23/mm/vmm.c
index d44cc24e..76f51394 100644
--- a/stage23/mm/vmm.c
+++ b/stage23/mm/vmm.c
@@ -3,11 +3,19 @@
#include <mm/vmm.h>
#include <mm/pmm.h>
#include <lib/blib.h>
+#include <sys/cpu.h>
#define PT_SIZE ((uint64_t)0x1000)
typedef uint64_t pt_entry_t;
+void vmm_assert_nx(void) {
+ uint32_t a, b, c, d;
+ if (!cpuid(0x80000001, 0, &a, &b, &c, &d) || !(d & (1 << 20))) {
+ panic("vmm: NX functionality not available on this CPU.");
+ }
+}
+
static pt_entry_t *get_next_level(pt_entry_t *current_level, size_t entry) {
pt_entry_t *ret;
diff --git a/stage23/mm/vmm.h b/stage23/mm/vmm.h
index 9aa096c5..d7cbcb37 100644
--- a/stage23/mm/vmm.h
+++ b/stage23/mm/vmm.h
@@ -4,11 +4,16 @@
#include <stdint.h>
#include <stdbool.h>
+#define VMM_FLAG_PRESENT ((uint64_t)1 << 0)
+#define VMM_FLAG_WRITE ((uint64_t)1 << 1)
+#define VMM_FLAG_NOEXEC ((uint64_t)1 << 63)
+
typedef struct {
int levels;
void *top_level;
} pagemap_t;
+void vmm_assert_nx(void);
pagemap_t new_pagemap(int lv);
void map_page(pagemap_t pagemap, uint64_t virt_addr, uint64_t phys_addr, uint64_t flags, bool hugepages);
diff --git a/stage23/protos/stivale.c b/stage23/protos/stivale.c
index 79e4a975..347d1a3f 100644
--- a/stage23/protos/stivale.c
+++ b/stage23/protos/stivale.c
@@ -282,7 +282,7 @@ void stivale_load(char *config, char *cmdline) {
pagemap_t pagemap = {0};
if (bits == 64)
- pagemap = stivale_build_pagemap(want_5lv, false);
+ pagemap = stivale_build_pagemap(want_5lv, false, NULL, 0);
// Reserve 32K at 0x70000
memmap_alloc_range(0x70000, 0x8000, MEMMAP_USABLE, true, true, false, false);
@@ -298,20 +298,38 @@ void stivale_load(char *config, char *cmdline) {
stivale_hdr.stack);
}
-pagemap_t stivale_build_pagemap(bool level5pg, bool unmap_null) {
+pagemap_t stivale_build_pagemap(bool level5pg, bool unmap_null, struct elf_range *ranges, size_t ranges_count) {
pagemap_t pagemap = new_pagemap(level5pg ? 5 : 4);
uint64_t higher_half_base = level5pg ? 0xff00000000000000 : 0xffff800000000000;
- // Map 0 to 2GiB at 0xffffffff80000000
- for (uint64_t i = 0; i < 0x80000000; i += 0x200000) {
- map_page(pagemap, 0xffffffff80000000 + i, i, 0x03, true);
- }
+ if (ranges_count == 0) {
+ // Map 0 to 2GiB at 0xffffffff80000000
+ for (uint64_t i = 0; i < 0x80000000; i += 0x200000) {
+ map_page(pagemap, 0xffffffff80000000 + i, i, 0x03, true);
+ }
+
+ // Sub 2MiB mappings
+ for (uint64_t i = 0; i < 0x200000; i += 0x1000) {
+ if (!(i == 0 && unmap_null))
+ map_page(pagemap, i, i, 0x03, false);
+ map_page(pagemap, higher_half_base + i, i, 0x03, false);
+ }
+ } else {
+ for (size_t i = 0; i < ranges_count; i++) {
+ uint64_t virt = ranges[i].base;
+ uint64_t phys = virt;
- // Sub 2MiB mappings
- for (uint64_t i = 0; i < 0x200000; i += 0x1000) {
- if (!(i == 0 && unmap_null))
- map_page(pagemap, i, i, 0x03, false);
- map_page(pagemap, higher_half_base + i, i, 0x03, false);
+ if (phys & ((uint64_t)1 << 63))
+ phys -= FIXED_HIGHER_HALF_OFFSET_64;
+
+ uint64_t pf = VMM_FLAG_PRESENT |
+ (ranges[i].permissions & ELF_PF_X ? 0 : VMM_FLAG_NOEXEC) |
+ (ranges[i].permissions & ELF_PF_W ? VMM_FLAG_WRITE : 0);
+
+ for (uint64_t j = 0; j < ranges[i].length; j += 0x1000) {
+ map_page(pagemap, virt + j, phys + j, pf, false);
+ }
+ }
}
// Map 2MiB to 4GiB at higher half base and 0
diff --git a/stage23/protos/stivale.h b/stage23/protos/stivale.h
index e09708cb..b0ea8809 100644
--- a/stage23/protos/stivale.h
+++ b/stage23/protos/stivale.h
@@ -4,12 +4,13 @@
#include <stdbool.h>
#include <stdint.h>
#include <mm/vmm.h>
+#include <lib/elf.h>
void stivale_load(char *config, char *cmdline);
bool stivale_load_by_anchor(void **_anchor, const char *magic,
uint8_t *file, uint64_t filesize);
-pagemap_t stivale_build_pagemap(bool level5pg, bool unmap_null);
+pagemap_t stivale_build_pagemap(bool level5pg, bool unmap_null, struct elf_range *ranges, size_t ranges_count);
__attribute__((noreturn)) void stivale_spinup(
int bits, bool level5pg, pagemap_t *pagemap,
uint64_t entry_point, uint64_t stivale_struct, uint64_t stack);
diff --git a/stage23/protos/stivale2.c b/stage23/protos/stivale2.c
index af06d931..2cc8077b 100644
--- a/stage23/protos/stivale2.c
+++ b/stage23/protos/stivale2.c
@@ -480,7 +480,7 @@ skip_modeset:;
pagemap_t pagemap = {0};
if (bits == 64)
- pagemap = stivale_build_pagemap(want_5lv, unmap_null);
+ pagemap = stivale_build_pagemap(want_5lv, unmap_null, NULL, 0);
#if uefi == 1
efi_exit_boot_services();
