summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--na/arch/riscv/config.cc134
-rw-r--r--na/include/lume/random.h12
-rw-r--r--na/lib/random.cc38
3 files changed, 178 insertions, 6 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
}
diff --git a/na/include/lume/random.h b/na/include/lume/random.h
index 0705b1b..740b060 100644
--- a/na/include/lume/random.h
+++ b/na/include/lume/random.h
@@ -5,6 +5,13 @@
#include <lume/types.h>
+enum class RandomSeedSource : uint8 {
+ Unknown = 0,
+ FdtProvided,
+ HwRandom,
+ CycleFallback,
+};
+
/*
* MI: Machine-Independent Random Number Generator API
*
@@ -24,3 +31,8 @@ void get_random_bytes(void* buf, size_t len);
/* Inject entropy (for future interrupt/device mixing) */
void add_device_randomness(const void* buf, size_t len);
+
+/* Early-seed metadata (for boot diagnostics/KASLR logs). */
+RandomSeedSource random_early_seed_source();
+uint64 random_early_seed_value();
+const char* random_seed_source_name(RandomSeedSource source);
diff --git a/na/lib/random.cc b/na/lib/random.cc
index c607e5f..428c75c 100644
--- a/na/lib/random.cc
+++ b/na/lib/random.cc
@@ -15,6 +15,8 @@
static uint64 g_state[4];
static bool g_initialized = false;
+static uint64 g_init_seed = 0;
+static RandomSeedSource g_seed_source = RandomSeedSource::Unknown;
static inline uint64 rotl(const uint64 x, int k) {
return (x << k) | (x >> (64 - k));
@@ -32,15 +34,21 @@ void random_early_init(uint64 seed)
{
if (g_initialized) return;
+ RandomSeedSource source = RandomSeedSource::Unknown;
+
/* If seed is 0 (not provided by bootloader), try hardware */
if (seed == 0) {
uint64 hw_val;
if (arch::get_hw_random(hw_val)) {
seed = hw_val;
+ source = RandomSeedSource::HwRandom;
} else {
/* Fallback: use boot cycles mixed with a constant */
seed = arch::get_cycles() ^ 0xdeadbeefbadc0ffeULL;
+ source = RandomSeedSource::CycleFallback;
}
+ } else {
+ source = RandomSeedSource::FdtProvided;
}
uint64 sm_state = seed;
@@ -49,8 +57,11 @@ void random_early_init(uint64 seed)
g_state[2] = splitmix64(sm_state);
g_state[3] = splitmix64(sm_state);
+ g_init_seed = seed;
+ g_seed_source = source;
g_initialized = true;
- kprintf("[random] early PRNG initialized, seed=0x%llx\n", seed);
+ kprintf("[random] early PRNG initialized, seed=0x%llx, source=%s\n",
+ seed, random_seed_source_name(source));
}
uint64 get_random_u64()
@@ -114,3 +125,28 @@ void add_device_randomness(const void* buf, size_t len)
g_state[0] ^= mix;
g_state[1] ^= arch::get_cycles();
}
+
+RandomSeedSource random_early_seed_source()
+{
+ return g_seed_source;
+}
+
+uint64 random_early_seed_value()
+{
+ return g_init_seed;
+}
+
+const char* random_seed_source_name(RandomSeedSource source)
+{
+ switch (source) {
+ case RandomSeedSource::FdtProvided:
+ return "fdt";
+ case RandomSeedSource::HwRandom:
+ return "hw";
+ case RandomSeedSource::CycleFallback:
+ return "cycle";
+ case RandomSeedSource::Unknown:
+ default:
+ return "unknown";
+ }
+}