:: commit ad00b5ca03c0c14289c0d081df540ae026c163ff

mintsuki <mintsuki@protonmail.com> — 2021-11-24 14:44

parents: 692d2a03a8

stivale2: Implement slide HHDM header tag

diff --git a/stage23/protos/stivale.c b/stage23/protos/stivale.c
index f11935bc..2b0359ab 100644
--- a/stage23/protos/stivale.c
+++ b/stage23/protos/stivale.c
@@ -26,7 +26,7 @@
 
 #define REPORTED_ADDR(PTR) \
     ((PTR) + ((stivale_hdr.flags & (1 << 3)) ? \
-    (want_5lv ? 0xff00000000000000 : 0xffff800000000000) : 0))
+    direct_map_offset : 0))
 
 bool stivale_load_by_anchor(void **_anchor, const char *magic,
                             uint8_t *file, uint64_t filesize) {
@@ -185,6 +185,8 @@ bool stivale_load(char *config, char *cmdline) {
 
     bool want_5lv = level5pg && (stivale_hdr.flags & (1 << 1));
 
+    uint64_t direct_map_offset = want_5lv ? 0xff00000000000000 : 0xffff800000000000;
+
     if (stivale_hdr.entry_point != 0)
         entry_point = stivale_hdr.entry_point;
 
@@ -329,7 +331,7 @@ bool stivale_load(char *config, char *cmdline) {
 
     pagemap_t pagemap = {0};
     if (bits == 64)
-        pagemap = stivale_build_pagemap(want_5lv, false, NULL, 0, false, 0, 0);
+        pagemap = stivale_build_pagemap(want_5lv, false, NULL, 0, false, 0, 0, direct_map_offset);
 
     // Reserve 32K at 0x70000 if possible
     if (!memmap_alloc_range(0x70000, 0x8000, MEMMAP_USABLE, true, false, false, false)) {
@@ -356,15 +358,17 @@ bool stivale_load(char *config, char *cmdline) {
                    entry_point, REPORTED_ADDR((uint64_t)(uintptr_t)&stivale_struct),
                    stivale_hdr.stack, false);
 
+    __builtin_unreachable();
+
 fail:
     pmm_free(kernel, kernel_file_size);
     return false;
 }
 
 pagemap_t stivale_build_pagemap(bool level5pg, bool unmap_null, struct elf_range *ranges, size_t ranges_count,
-                                bool want_fully_virtual, uint64_t physical_base, uint64_t virtual_base) {
+                                bool want_fully_virtual, uint64_t physical_base, uint64_t virtual_base,
+                                uint64_t direct_map_offset) {
     pagemap_t pagemap = new_pagemap(level5pg ? 5 : 4);
-    uint64_t higher_half_base = level5pg ? 0xff00000000000000 : 0xffff800000000000;
 
     if (ranges_count == 0) {
         // Map 0 to 2GiB at 0xffffffff80000000
@@ -400,13 +404,13 @@ pagemap_t stivale_build_pagemap(bool level5pg, bool unmap_null, struct elf_range
     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);
+        map_page(pagemap, direct_map_offset + i, i, 0x03, false);
     }
 
     // Map 2MiB to 4GiB at higher half base and 0
     for (uint64_t i = 0x200000; i < 0x100000000; i += 0x200000) {
         map_page(pagemap, i, i, 0x03, true);
-        map_page(pagemap, higher_half_base + i, i, 0x03, true);
+        map_page(pagemap, direct_map_offset + i, i, 0x03, true);
     }
 
     size_t _memmap_entries = memmap_entries;
@@ -434,7 +438,7 @@ pagemap_t stivale_build_pagemap(bool level5pg, bool unmap_null, struct elf_range
         for (uint64_t j = 0; j < aligned_length; j += 0x200000) {
             uint64_t page = aligned_base + j;
             map_page(pagemap, page, page, 0x03, true);
-            map_page(pagemap, higher_half_base + page, page, 0x03, true);
+            map_page(pagemap, direct_map_offset + page, page, 0x03, true);
         }
     }
 
diff --git a/stage23/protos/stivale.h b/stage23/protos/stivale.h
index a52b75b3..c5f43ac6 100644
--- a/stage23/protos/stivale.h
+++ b/stage23/protos/stivale.h
@@ -11,7 +11,8 @@ bool 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, struct elf_range *ranges, size_t ranges_count,
-                                bool want_fully_virtual, uint64_t physical_base, uint64_t virtual_base);
+                                bool want_fully_virtual, uint64_t physical_base, uint64_t virtual_base,
+                                uint64_t direct_map_offset);
 __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 3c79f4fc..ac32d6a1 100644
--- a/stage23/protos/stivale2.c
+++ b/stage23/protos/stivale2.c
@@ -25,10 +25,11 @@
 #include <pxe/tftp.h>
 #include <drivers/edid.h>
 #include <drivers/vga_textmode.h>
+#include <lib/rand.h>
 
 #define REPORTED_ADDR(PTR) \
     ((PTR) + ((stivale2_hdr.flags & (1 << 1)) ? \
-    (want_5lv ? 0xff00000000000000 : 0xffff800000000000) : 0))
+    direct_map_offset : 0))
 
 struct stivale2_struct stivale2_struct = {0};
 
@@ -232,6 +233,19 @@ failed_to_load_header_section:
 
     bool want_5lv = (get_tag(&stivale2_hdr, STIVALE2_HEADER_TAG_5LV_PAGING_ID) ? true : false) && level5pg;
 
+    uint64_t direct_map_offset = want_5lv ? 0xff00000000000000 : 0xffff800000000000;
+
+    {
+        struct stivale2_header_tag_slide_hhdm *slt = get_tag(&stivale2_hdr, STIVALE2_HEADER_TAG_SLIDE_HHDM_ID);
+        if (slt != NULL) {
+            if (slt->alignment % 0x200000 != 0 || slt->alignment == 0) {
+                panic("stivale2: Requested HHDM slide alignment is not a multiple of 2MiB");
+            }
+
+            direct_map_offset += (rand64() & ~(slt->alignment - 1)) & 0xffffffffff;
+        }
+    }
+
     if (stivale2_hdr.entry_point != 0)
         entry_point = stivale2_hdr.entry_point;
 
@@ -624,6 +638,18 @@ have_tm_tag:;
     }
     }
 
+    //////////////////////////////////////////////
+    // Create HHDM struct tag
+    //////////////////////////////////////////////
+    {
+    struct stivale2_struct_tag_hhdm *tag = ext_mem_alloc(sizeof(struct stivale2_struct_tag_hhdm));
+    tag->tag.identifier = STIVALE2_STRUCT_TAG_HHDM_ID;
+
+    tag->addr = direct_map_offset;
+
+    append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
+    }
+
 #if bios == 1
     //////////////////////////////////////////////
     // Create PXE struct tag
@@ -693,7 +719,8 @@ have_tm_tag:;
         pagemap = stivale_build_pagemap(want_5lv, unmap_null,
                                         want_pmrs ? ranges : NULL,
                                         want_pmrs ? ranges_count : 0,
-                                        want_fully_virtual, physical_base, virtual_base);
+                                        want_fully_virtual, physical_base, virtual_base,
+                                        direct_map_offset);
 
 #if uefi == 1
     efi_exit_boot_services();
@@ -762,11 +789,11 @@ have_tm_tag:;
     if (verbose) {
         print("stivale2: Generated tags:\n");
         struct stivale2_tag *taglist =
-                    (void*)(uintptr_t)(stivale2_struct.tags & (uint64_t)0xffffffff);
+                    (void*)(uintptr_t)(stivale2_struct.tags - ((stivale2_hdr.flags & (1 << 1)) ? direct_map_offset : 0));
         for (size_t i = 0; ; i++) {
             print("          Tag #%u  ID: %X\n", i, taglist->identifier);
             if (taglist->next) {
-                taglist = (void*)(uintptr_t)(taglist->next & (uint64_t)0xffffffff);
+                taglist = (void*)(uintptr_t)(taglist->next - ((stivale2_hdr.flags & (1 << 1)) ? direct_map_offset : 0));
             } else {
                 break;
             }
@@ -782,6 +809,8 @@ have_tm_tag:;
                    REPORTED_ADDR((uint64_t)(uintptr_t)&stivale2_struct),
                    stivale2_hdr.stack, want_pmrs);
 
+    __builtin_unreachable();
+
 fail:
     pmm_free(kernel, kernel_file_size);
     return false;
diff --git a/test/stivale2.c b/test/stivale2.c
index 2f58d529..5f107a63 100644
--- a/test/stivale2.c
+++ b/test/stivale2.c
@@ -7,10 +7,19 @@ typedef uint8_t stack[4096];
 static stack stacks[64] = {0};
 void stivale2_main(struct stivale2_struct *info);
 
+struct stivale2_header_tag_slide_hhdm slide_hhdm = {
+    .tag = {
+        .identifier = STIVALE2_HEADER_TAG_SLIDE_HHDM_ID,
+        .next       = 0
+    },
+    .flags = 0,
+    .alignment = 0x10000000
+};
+
 struct stivale2_header_tag_terminal terminal_request = {
     .tag = {
         .identifier = STIVALE2_HEADER_TAG_TERMINAL_ID,
-        .next       = 0
+        .next       = (uint64_t)&slide_hhdm
     },
     .flags = 0
 };
@@ -204,6 +213,11 @@ void stivale2_main(struct stivale2_struct *info) {
                 }
                 break;
             }
+            case STIVALE2_STRUCT_TAG_HHDM_ID: {
+                struct stivale2_struct_tag_hhdm *t = (struct stivale2_struct_tag_hhdm *)tag;
+                e9_printf("Higher half direct map at: %x", t->addr);
+                break;
+            }
             case STIVALE2_STRUCT_TAG_KERNEL_BASE_ADDRESS_ID: {
                 struct stivale2_struct_tag_kernel_base_address *t = (void *)tag;
                 e9_puts("Kernel base address:");
tab: 248 wrap: offon