summaryrefslogtreecommitdiff
path: root/na/arch
diff options
context:
space:
mode:
Diffstat (limited to 'na/arch')
-rw-r--r--na/arch/riscv/config.cc59
-rw-r--r--na/arch/riscv/include/arch/config.h40
-rw-r--r--na/arch/riscv/mm/pmap.cc12
3 files changed, 104 insertions, 7 deletions
diff --git a/na/arch/riscv/config.cc b/na/arch/riscv/config.cc
index 139d932..9b4cc6e 100644
--- a/na/arch/riscv/config.cc
+++ b/na/arch/riscv/config.cc
@@ -1,10 +1,69 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2026 Richard Qin */
+/*
+ * RISC-V Architecture Configuration — runtime state and KASLR
+ *
+ * Provides the runtime (post-KASLR) values of the higher-half
+ * virtual address bases. kaslr_init() is called once during
+ * early boot, before vmm_init(), to slide these bases by a
+ * random, 1GB-aligned offset.
+ *
+ * KASLR slide budget:
+ * The default Direct Map starts at 0xFFFFFFC0_0000_0000 (VPN[2]=256).
+ * The default Vmemmap starts at 0xFFFFFFD0_0000_0000 (VPN[2]=320).
+ * A 1GB superpage occupies one VPN[2] slot. We allow a slide of
+ * 0..63 slots (0..63 GB) downward, which keeps both regions inside
+ * the upper canonical half and avoids colliding with the kernel
+ * text region (linked at VPN[2] = 258 + 2 = ~0xFFFFFFC0_8020_0000).
+ *
+ * In practice, with 128MB RAM the kernel+direct map only touches
+ * VPN[2] 258-259, so a slide of up to 63GB is safe.
+ */
+
#include <arch/config.h>
+#include <lume/random.h>
+#include <lume/kprintf.h>
namespace arch {
+/* Runtime bases — default to the compile-time constants. */
uint64 g_direct_map_base = kDirectMapBaseDefault;
+uint64 g_vmemmap_base = kVmemmapBaseDefault;
+
+void kaslr_init()
+{
+#ifdef CONFIG_KASLR
+ /*
+ * Generate a random 1GB-aligned slide.
+ *
+ * Strategy (matching Linux's approach):
+ * 1. Pull 64 random bits from the early PRNG.
+ * 2. Reduce to a slot number in [0, kMaxSlots).
+ * 3. Convert to a byte offset (slot * 1GB).
+ * 4. Add to both bases (slide upward in VA space).
+ *
+ * Why 1GB alignment?
+ * SV39 L2 (root) PTEs map 1GB superpages. Keeping the slide
+ * 1GB-aligned means the direct-map can still use gigapages,
+ * avoiding TLB pressure. This matches Linux's KASLR on RISC-V.
+ */
+ constexpr uint64 k1GB = 1ULL << 30;
+ constexpr uint64 kMaxSlots = 64; /* 0..63 GB slide range */
+
+ uint64 raw = get_random_u64();
+ uint64 slot = raw % kMaxSlots;
+ uint64 slide = slot * k1GB;
+
+ g_direct_map_base = kDirectMapBaseDefault + slide;
+ g_vmemmap_base = kVmemmapBaseDefault + slide;
+
+ kprintf("[kaslr] slide = %llu GB (slot %llu/64)\n", slide >> 30, slot);
+ kprintf("[kaslr] direct_map_base = 0x%llx\n", g_direct_map_base);
+ kprintf("[kaslr] vmemmap_base = 0x%llx\n", g_vmemmap_base);
+#else
+ kprintf("[kaslr] CONFIG_KASLR disabled, using fixed layout\n");
+#endif
+}
} // namespace arch
diff --git a/na/arch/riscv/include/arch/config.h b/na/arch/riscv/include/arch/config.h
index c407b25..e7b1027 100644
--- a/na/arch/riscv/include/arch/config.h
+++ b/na/arch/riscv/include/arch/config.h
@@ -8,21 +8,49 @@
*
* These constants define the architecture-specific memory layout.
* Each arch/ implementation must provide this header with the same symbols.
+ *
+ * KASLR: At boot, kaslr_init() randomises g_direct_map_base and
+ * g_vmemmap_base. All MI code must read these runtime variables
+ * (via pa_to_va / vmm helpers) rather than the static defaults.
*/
#include <lume/types.h>
namespace arch {
-/* Direct-map virtual base (higher-half base).
- * SV39: top of 39-bit VA space. VA = PA + direct_map_base. */
+/* ================================================================
+ * Default (compile-time) virtual addresses
+ *
+ * SV39 gives a 512GB virtual address space.
+ * Higher-half layout (defaults before KASLR):
+ *
+ * 0xFFFFFFC0_00000000 (256) Direct map (PA+offset)
+ * 0xFFFFFFD0_00000000 (320) Vmemmap (Frame array)
+ *
+ * The 64GB gap between them is the KASLR slide range.
+ * ================================================================ */
inline constexpr uint64 kDirectMapBaseDefault = 0xFFFFFFC000000000ULL;
-extern uint64 g_direct_map_base;
-
-/* Dedicated VA base for the Frame descriptor array (vmemmap). */
-inline constexpr uint64 kVmemmapBase = 0xFFFFFFD000000000ULL;
+inline constexpr uint64 kVmemmapBaseDefault = 0xFFFFFFD000000000ULL;
/* Physical memory base (where RAM starts on RISC-V virt platform) */
inline constexpr uint64 kPhysBase = 0x80000000ULL;
+/* ================================================================
+ * Runtime (post-KASLR) virtual addresses
+ *
+ * These start equal to the defaults above. If CONFIG_KASLR is
+ * enabled, kaslr_init() adds a random, 1GB-aligned offset
+ * to each, sliding both regions upward in VA space.
+ * ================================================================ */
+extern uint64 g_direct_map_base;
+extern uint64 g_vmemmap_base;
+
+/* ================================================================
+ * KASLR entry point
+ *
+ * Must be called AFTER random_early_init() and BEFORE vmm_init().
+ * When CONFIG_KASLR is disabled this is a no-op.
+ * ================================================================ */
+void kaslr_init();
+
} // namespace arch
diff --git a/na/arch/riscv/mm/pmap.cc b/na/arch/riscv/mm/pmap.cc
index 4ed3bca..dafbeaf 100644
--- a/na/arch/riscv/mm/pmap.cc
+++ b/na/arch/riscv/mm/pmap.cc
@@ -24,6 +24,12 @@
namespace pmap {
+/*
+ * Before the first pmap::activate(), CPU runs on entry.S bootstrap page table
+ * (fixed direct-map base). After activation, runtime (KASLR) base is valid.
+ */
+static bool g_runtime_mapping_ready = false;
+
/* PTE bit definitions */
inline constexpr uint64 PTE_V = 1ULL << 0;
inline constexpr uint64 PTE_R = 1ULL << 1;
@@ -59,7 +65,10 @@ static inline uint64 pa_to_pte(uint64 pa, uint64 flags)
/* Convert PA to kernel VA for accessing page table contents */
static inline uint64 *pa_to_ptr(uint64 pa)
{
- return reinterpret_cast<uint64 *>(pa_to_va(phys_addr(pa)).raw);
+ uint64 va = g_runtime_mapping_ready
+ ? pa_to_va(phys_addr(pa)).raw
+ : boot_pa_to_va(phys_addr(pa)).raw;
+ return reinterpret_cast<uint64 *>(va);
}
/* Allocate a zeroed page for a page table level.
@@ -203,6 +212,7 @@ void activate(uint64 root_pa)
{
arch::mmu::set_page_table(root_pa);
arch::mmu::flush_tlb_all();
+ g_runtime_mapping_ready = true;
}
uint64 vm_perm_to_pte(uint64 vm_perm)