summaryrefslogtreecommitdiff
path: root/na/arch/riscv/config.cc
diff options
context:
space:
mode:
Diffstat (limited to 'na/arch/riscv/config.cc')
-rw-r--r--na/arch/riscv/config.cc134
1 files changed, 129 insertions, 5 deletions
diff --git a/na/arch/riscv/config.cc b/na/arch/riscv/config.cc
index 9b4cc6e..421817d 100644
--- a/na/arch/riscv/config.cc
+++ b/na/arch/riscv/config.cc
@@ -22,8 +22,14 @@
*/
#include <arch/config.h>
-#include <lume/random.h>
+#include <lume/fdt.h>
+#include <lume/frame.h>
+#include <lume/config.h>
+#include <lume/klog.h>
#include <lume/kprintf.h>
+#include <lume/random.h>
+
+extern "C" char _stext[], _kernel_end[];
namespace arch {
@@ -31,6 +37,118 @@ namespace arch {
uint64 g_direct_map_base = kDirectMapBaseDefault;
uint64 g_vmemmap_base = kVmemmapBaseDefault;
+struct VaRange {
+ const char* name;
+ uint64 start;
+ uint64 end; // exclusive
+};
+
+static inline uint64 align_down_page(uint64 v)
+{
+ return v & ~(kPageSize - 1);
+}
+
+static inline uint64 align_up_page(uint64 v)
+{
+ return (v + kPageSize - 1) & ~(kPageSize - 1);
+}
+
+static uint64 checked_add_u64(uint64 a, uint64 b, const char* detail)
+{
+ if (a > (~0ULL - b)) {
+ kernel_panic("kaslr: address overflow", detail);
+ }
+ return a + b;
+}
+
+/* SV39 canonical VA check: bits [63:39] must equal sign bit 38. */
+static bool is_sv39_canonical(uint64 va)
+{
+ uint64 sign = (va >> 38) & 1ULL;
+ uint64 upper = va >> 39;
+ return sign ? (upper == ((1ULL << 25) - 1ULL)) : (upper == 0);
+}
+
+static bool is_sv39_kernel_half(uint64 va)
+{
+ return is_sv39_canonical(va) && (((va >> 38) & 1ULL) == 1ULL);
+}
+
+static bool ranges_overlap(const VaRange& a, const VaRange& b)
+{
+ return (a.start < b.end) && (b.start < a.end);
+}
+
+static void kaslr_self_check(uint64 slot)
+{
+ uint64 mem_base = 0;
+ uint64 mem_size = 0;
+ fdt_early_get_mem_info(&mem_base, &mem_size);
+ if (mem_size == 0) {
+ kernel_panic("kaslr: invalid memory size from FDT");
+ }
+
+ /* Direct-map covers the discovered physical memory window. */
+ VaRange direct_map {
+ "direct-map",
+ checked_add_u64(g_direct_map_base, mem_base, "direct_map start"),
+ checked_add_u64(checked_add_u64(g_direct_map_base, mem_base,
+ "direct_map start"),
+ mem_size, "direct_map end"),
+ };
+
+ /* Vmemmap covers the Frame descriptor array span. */
+ uint64 num_frames = mem_size / kPageSize;
+ uint64 frame_bytes = num_frames * sizeof(Frame);
+ uint64 frame_span = align_up_page(frame_bytes);
+ VaRange vmemmap {
+ "vmemmap",
+ g_vmemmap_base,
+ checked_add_u64(g_vmemmap_base, frame_span, "vmemmap end"),
+ };
+
+ /* Kernel image window is linked at fixed higher-half addresses. */
+ VaRange kernel_img {
+ "kernel-image",
+ align_down_page(reinterpret_cast<uint64>(_stext)),
+ align_up_page(reinterpret_cast<uint64>(_kernel_end)),
+ };
+
+ auto check_kernel_half = [](const VaRange& r) {
+ if (r.start >= r.end) {
+ kernel_panic("kaslr: invalid VA range", r.name);
+ }
+ if (!is_sv39_kernel_half(r.start) || !is_sv39_kernel_half(r.end - 1)) {
+ kernel_panic("kaslr: non-canonical kernel VA range", r.name);
+ }
+ };
+
+ check_kernel_half(direct_map);
+ check_kernel_half(vmemmap);
+ check_kernel_half(kernel_img);
+
+ if (ranges_overlap(direct_map, kernel_img)) {
+ kernel_panic("kaslr: direct-map overlaps kernel image");
+ }
+ if (ranges_overlap(vmemmap, kernel_img)) {
+ kernel_panic("kaslr: vmemmap overlaps kernel image");
+ }
+ if (ranges_overlap(direct_map, vmemmap)) {
+ kernel_panic("kaslr: direct-map overlaps vmemmap");
+ }
+
+ kprintf("[boot][kaslr] seed=0x%llx source=%s slot=%llu slide_gb=%llu\n",
+ random_early_seed_value(),
+ random_seed_source_name(random_early_seed_source()),
+ slot, slot);
+ kprintf("[boot][kaslr] direct-map=[0x%llx,0x%llx)\n",
+ direct_map.start, direct_map.end);
+ kprintf("[boot][kaslr] vmemmap=[0x%llx,0x%llx)\n",
+ vmemmap.start, vmemmap.end);
+ kprintf("[boot][kaslr] kernel-image=[0x%llx,0x%llx)\n",
+ kernel_img.start, kernel_img.end);
+}
+
void kaslr_init()
{
#ifdef CONFIG_KASLR
@@ -58,11 +176,17 @@ void kaslr_init()
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);
+ kaslr_self_check(slot);
#else
- kprintf("[kaslr] CONFIG_KASLR disabled, using fixed layout\n");
+ g_direct_map_base = kDirectMapBaseDefault;
+ g_vmemmap_base = kVmemmapBaseDefault;
+ kprintf("[boot][kaslr] disabled source=%s seed=0x%llx slot=0 slide_gb=0\n",
+ random_seed_source_name(random_early_seed_source()),
+ random_early_seed_value());
+ kprintf("[boot][kaslr] direct-map=[0x%llx,0x%llx)\n",
+ g_direct_map_base, g_direct_map_base);
+ kprintf("[boot][kaslr] vmemmap=[0x%llx,0x%llx)\n",
+ g_vmemmap_base, g_vmemmap_base);
#endif
}