close audited test gaps: discovery, W^X, power
Add a discovery case (asserts stable ACPI/MADT/FADT/AML facts) and a wx case (audits R+X code vs NX data/rodata/heap/stack via arch.pageExecutable). Wire the existing poweroff/reboot cases into the harness. Suite: 18 -> 22.
This commit is contained in:
@@ -50,6 +50,10 @@ fn result() void {
|
||||
pub fn run(case: []const u8, boot_info: *const BootInfo) void {
|
||||
if (eql(case, "smoke")) {
|
||||
smoke(boot_info);
|
||||
} else if (eql(case, "discovery")) {
|
||||
discoveryTest();
|
||||
} else if (eql(case, "wx")) {
|
||||
wxTest();
|
||||
} else if (eql(case, "timer")) {
|
||||
timer();
|
||||
} else if (eql(case, "clock")) {
|
||||
@@ -171,6 +175,54 @@ fn timer() void {
|
||||
result();
|
||||
}
|
||||
|
||||
/// Verify device discovery populated the platform facts the rest of the kernel
|
||||
/// depends on — the results ACPI parsing stashed in globals at boot. These are
|
||||
/// stable for the QEMU q35 + OVMF machine the harness runs, and span the tables:
|
||||
/// MADT (LAPIC base, CPU count), FADT (PM/reset registers), and the AML parse
|
||||
/// (the sleep type, plus the integrity check that every byte was consumed).
|
||||
fn discoveryTest() void {
|
||||
log("DANOS-TEST-BEGIN: discovery\n", .{});
|
||||
const pinfo = platform.platformInfo();
|
||||
const pw = platform.powerInfo();
|
||||
const am = platform.amlStats();
|
||||
|
||||
check("LAPIC base discovered (MADT)", pinfo.lapic_base == 0xFEE00000);
|
||||
check("ACPI PM timer found (FADT)", pinfo.pm_timer.present());
|
||||
check("PM1a control register found (FADT)", pw.pm1a_cnt.present());
|
||||
check("reset register supported (FADT)", pw.reset_supported);
|
||||
check("S5 sleep type found (AML)", pw.s5 != null);
|
||||
check("AML parsed completely (consumed == total)", am.total > 0 and am.consumed == am.total);
|
||||
check("at least one CPU enumerated (MADT)", platform.cpus().len >= 1);
|
||||
|
||||
result();
|
||||
}
|
||||
|
||||
/// Audit the W^X invariant across the memory classes: kernel code must be
|
||||
/// executable, everything else must not be. `arch.pageExecutable` reads the leaf
|
||||
/// page-table entry's NX bit, so this guards the permission overlay in paging.zig —
|
||||
/// a broader check than `fault-nx`, which only exercises one data page.
|
||||
fn wxTest() void {
|
||||
log("DANOS-TEST-BEGIN: wx\n", .{});
|
||||
|
||||
check("kernel code is executable (R+X)", arch.pageExecutable(@intFromPtr(&wxTest)));
|
||||
|
||||
const ro = "danos-wx-probe"; // string literal -> .rodata
|
||||
check("rodata is non-executable (NX)", !arch.pageExecutable(@intFromPtr(ro.ptr)));
|
||||
|
||||
check("kernel data is non-executable (NX)", !arch.pageExecutable(@intFromPtr(&passed)));
|
||||
|
||||
if (heap.allocator().alloc(u8, 64) catch null) |h| {
|
||||
check("heap is non-executable (NX)", !arch.pageExecutable(@intFromPtr(h.ptr)));
|
||||
heap.allocator().free(h);
|
||||
}
|
||||
|
||||
var local: u64 = 0;
|
||||
_ = &local;
|
||||
check("stack is non-executable (NX)", !arch.pageExecutable(@intFromPtr(&local)));
|
||||
|
||||
result();
|
||||
}
|
||||
|
||||
/// Verify the on-demand VMM: map a fresh frame at an unused virtual address, and
|
||||
/// check it's writable and reads back.
|
||||
fn vmm() void {
|
||||
|
||||
Reference in New Issue
Block a user