Built heap allocation
This commit is contained in:
@@ -13,6 +13,7 @@ const std = @import("std");
|
||||
const danos = @import("danos");
|
||||
const arch = @import("arch");
|
||||
const pmm = @import("pmm.zig");
|
||||
const heap = @import("heap.zig");
|
||||
|
||||
/// Formatted write straight to serial, independent of the framebuffer console.
|
||||
fn log(comptime fmt: []const u8, args: anytype) void {
|
||||
@@ -50,6 +51,8 @@ pub fn run(case: []const u8, boot_info: *const BootInfo) void {
|
||||
timer();
|
||||
} else if (eql(case, "vmm")) {
|
||||
vmm();
|
||||
} else if (eql(case, "heap")) {
|
||||
heapTest();
|
||||
} else if (eql(case, "fault-ud")) {
|
||||
faultInvalidOpcode();
|
||||
} else if (eql(case, "fault-pf")) {
|
||||
@@ -138,6 +141,69 @@ fn vmm() void {
|
||||
result();
|
||||
}
|
||||
|
||||
/// Exercise the kernel heap: basic alloc/write/free, reuse, growth beyond the
|
||||
/// initial region, and a std container backed by it.
|
||||
fn heapTest() void {
|
||||
log("DANOS-TEST-BEGIN: heap\n", .{});
|
||||
const a = heap.allocator();
|
||||
|
||||
// Allocate, write a pattern, read it back, free.
|
||||
const buf = a.alloc(u8, 4096) catch null;
|
||||
check("alloc 4096 bytes", buf != null);
|
||||
if (buf) |b| {
|
||||
@memset(b, 0xAB);
|
||||
check("heap memory is writable and reads back", b[0] == 0xAB and b[4095] == 0xAB);
|
||||
a.free(b);
|
||||
}
|
||||
|
||||
// Freeing then re-allocating the same size should reuse the block.
|
||||
const p1 = a.alloc(u64, 8) catch null;
|
||||
const addr1 = if (p1) |p| @intFromPtr(p.ptr) else 0;
|
||||
if (p1) |p| a.free(p);
|
||||
const p2 = a.alloc(u64, 8) catch null;
|
||||
const addr2 = if (p2) |p| @intFromPtr(p.ptr) else 0;
|
||||
check("freed block is reused", addr1 != 0 and addr1 == addr2);
|
||||
if (p2) |p| a.free(p);
|
||||
|
||||
// Force growth past the initial page and check every block is usable.
|
||||
var blocks: [64]?[]u8 = .{null} ** 64;
|
||||
var ok = true;
|
||||
for (&blocks, 0..) |*slot, i| {
|
||||
const b = a.alloc(u8, 4096) catch null;
|
||||
slot.* = b;
|
||||
if (b) |bb| @memset(bb, @intCast(i & 0xff)) else {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
for (blocks, 0..) |slot, i| {
|
||||
if (slot) |bb| {
|
||||
if (bb[0] != @as(u8, @intCast(i & 0xff)) or bb[4095] != @as(u8, @intCast(i & 0xff))) ok = false;
|
||||
}
|
||||
}
|
||||
check("many allocations (heap growth) stay valid", ok);
|
||||
for (blocks) |slot| {
|
||||
if (slot) |bb| a.free(bb);
|
||||
}
|
||||
|
||||
// A std container backed by the kernel heap.
|
||||
var list: std.ArrayList(u32) = .empty;
|
||||
var sum: u64 = 0;
|
||||
var expected: u64 = 0;
|
||||
var i: u32 = 0;
|
||||
var list_ok = true;
|
||||
while (i < 1000) : (i += 1) {
|
||||
list.append(a, i) catch {
|
||||
list_ok = false;
|
||||
};
|
||||
expected += i;
|
||||
}
|
||||
for (list.items) |v| sum += v;
|
||||
list.deinit(a);
|
||||
check("std.ArrayList on the kernel heap", list_ok and sum == expected);
|
||||
|
||||
result();
|
||||
}
|
||||
|
||||
fn faultInvalidOpcode() void {
|
||||
log("DANOS-TEST-BEGIN: fault-ud\n", .{});
|
||||
asm volatile ("ud2");
|
||||
|
||||
Reference in New Issue
Block a user