From 8ef4eed29dad51ec5cbe9a93ae6a0f72a9ccca67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Gr=C3=A9goire?= Date: Sat, 11 Apr 2026 21:47:50 -0400 Subject: [PATCH] feat(mm): add GPA --- src/mm/root.zig | 1 + src/mm/zone.zig | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/src/mm/root.zig b/src/mm/root.zig index 262196b..3716aeb 100644 --- a/src/mm/root.zig +++ b/src/mm/root.zig @@ -8,6 +8,7 @@ pub const page_size = 4096; pub const init = private.init.init; pub const vmem = private.vmem; pub const phys = private.phys; +pub const zone = private.zone; // 16 TB of maximum physical memory. // This should be fine on consumer hardware for at least a decade :^) diff --git a/src/mm/zone.zig b/src/mm/zone.zig index 8337b9f..b78f8f8 100644 --- a/src/mm/zone.zig +++ b/src/mm/zone.zig @@ -722,3 +722,98 @@ pub fn early_init() linksection(b.init) void { zone.init(generic_zone_names[i], @as(usize, 1) << @intCast(i + 3), .{}); } } + +// === Global general purpose allocator === +pub const gpa: std.mem.Allocator = .{ + .ptr = undefined, + .vtable = &.{ + .alloc = gpa_alloc, + .resize = gpa_resize, + .free = gpa_free, + .remap = gpa_remap, + }, +}; + +fn gpa_alloc( + ctx: *anyopaque, + len: usize, + ptr_align: std.mem.Alignment, + _: usize, +) ?[*]u8 { + _ = ctx; + + if (len > 2048) { + if (ptr_align.toByteUnits() > mm.page_size) return null; + + const pages = std.mem.alignForward(usize, len, mm.page_size); + const ptr = mi.heap.alloc_pages(pages) catch return null; + return @ptrCast(ptr); + } + + const zone = zone_for(len, ptr_align.toByteUnits()) orelse return null; + const obj = zone.alloc() catch return null; + return @ptrCast(obj); +} + +fn gpa_resize( + _: *anyopaque, + buf: []u8, + _: std.mem.Alignment, + new_len: usize, + _: usize, +) bool { + if (buf.len > 2048) { + // Allow shrinking within the same page-rounded allocation. + const old_pages = std.mem.alignForward(usize, buf.len, mm.page_size); + const new_pages = std.mem.alignForward(usize, new_len, mm.page_size); + return new_pages <= old_pages; + } + // Can't resize in place. Only allow shrinking within the same zone. + const old_zone = zone_for(buf.len, 1) orelse return false; + const new_zone = zone_for(new_len, 1) orelse return false; + return old_zone == new_zone; +} + +fn gpa_remap( + _: *anyopaque, + buf: []u8, + alignment: std.mem.Alignment, + new_len: usize, + ret_addr: usize, +) ?[*]u8 { + if (gpa_resize(undefined, buf, alignment, new_len, ret_addr)) return buf.ptr; + + const new_ptr = gpa_alloc(undefined, new_len, alignment, ret_addr) orelse return null; + const copy_len = @min(buf.len, new_len); + @memcpy(new_ptr[0..copy_len], buf[0..copy_len]); + gpa_free(undefined, buf, alignment, ret_addr); + return new_ptr; +} + +fn gpa_free( + _: *anyopaque, + buf: []u8, + _: std.mem.Alignment, + _: usize, +) void { + if (buf.len > 2048) { + //const pages = std.mem.alignForward(usize, buf.len, mm.page_size); + // TODO + //mi.heap.free_pages(@ptrCast(buf.ptr), pages); + return; + } + const zone = zone_for(buf.len, 1) orelse return; + zone.free(@ptrCast(buf.ptr)); +} + +fn zone_for(size: usize, alignment: usize) ?*Zone { + const needed = @max(size, alignment); + + for (&generic_zones) |*zone| { + if (zone.obj_size >= needed and zone.chunk_size % @max(alignment, 1) == 0) { + return zone; + } + } + + return null; +}