diff options
| author | Bobby <[email protected]> | 2026-03-30 15:02:42 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2026-03-30 15:02:42 +0530 |
| commit | 2324951126b542aeecfd8dd12b381265cce1566c (patch) | |
| tree | a580fe97a13788fbe3b104e3a9553f551c2bff11 /mirai/memory/zone | |
| parent | 3c2c5c419cae1b7f2d60e8a3dc6e2e8c157b5a2f (diff) | |
| download | akiba-main.tar.xz akiba-main.zip | |
Diffstat (limited to 'mirai/memory/zone')
| -rw-r--r-- | mirai/memory/zone/alloc/alloc.zig | 119 | ||||
| -rw-r--r-- | mirai/memory/zone/bootstrap/bootstrap.zig | 99 | ||||
| -rw-r--r-- | mirai/memory/zone/create/create.zig | 39 | ||||
| -rw-r--r-- | mirai/memory/zone/gc/gc.zig | 43 | ||||
| -rw-r--r-- | mirai/memory/zone/types/types.zig | 37 | ||||
| -rw-r--r-- | mirai/memory/zone/zone.zig | 20 |
6 files changed, 357 insertions, 0 deletions
diff --git a/mirai/memory/zone/alloc/alloc.zig b/mirai/memory/zone/alloc/alloc.zig new file mode 100644 index 0000000..00f9cef --- /dev/null +++ b/mirai/memory/zone/alloc/alloc.zig @@ -0,0 +1,119 @@ +//! Zone Allocation + +const types = @import("../types/types.zig"); +const Zone = types.Zone; +const ZonePageMeta = types.ZonePageMeta; +const FreeElement = types.FreeElement; +const page_size = types.page_size; + +const bootstrap = @import("../bootstrap/bootstrap.zig"); +const convert = @import("../../convert/convert.zig"); +const pmm = @import("../../../pmm/pmm.zig"); + +pub const AllocError = error{ + OutOfMemory, +}; + +pub fn zalloc(zone: *Zone) AllocError!*anyopaque { + if (zone.partial_pages == null) { + try expand(zone); + } + + const page = zone.partial_pages orelse return AllocError.OutOfMemory; + const elem = page.free_list orelse return AllocError.OutOfMemory; + + page.free_list = elem.next; + page.in_use += 1; + zone.alloc_count += 1; + + if (page.free_list == null) { + zone.partial_pages = page.next; + page.next = zone.full_pages; + zone.full_pages = page; + } + + return @ptrCast(elem); +} + +pub fn zalloc_zeroed(zone: *Zone) AllocError!*anyopaque { + const ptr = try zalloc(zone); + const bytes: [*]u8 = @ptrCast(ptr); + @memset(bytes[0..zone.elem_size], 0); + return ptr; +} + +pub fn zfree(zone: *Zone, ptr: *anyopaque) void { + const page_virt = @intFromPtr(ptr) & ~@as(usize, page_size - 1); + const page = find_page(zone, page_virt) orelse return; + const was_full = (page.free_list == null); + + const elem: *FreeElement = @ptrCast(@alignCast(ptr)); + elem.next = page.free_list; + page.free_list = elem; + page.in_use -|= 1; + zone.free_count += 1; + + if (was_full) { + remove_from_full(zone, page); + page.next = zone.partial_pages; + zone.partial_pages = page; + } +} + +fn expand(zone: *Zone) AllocError!void { + const phys = pmm.allocate_page() catch return AllocError.OutOfMemory; + const virt = convert.phys_to_virt(phys); + + const page_meta_zone = bootstrap.get_page_meta_zone(); + const meta_ptr = zalloc(page_meta_zone) catch { + pmm.free_page(phys); + return AllocError.OutOfMemory; + }; + const meta: *ZonePageMeta = @ptrCast(@alignCast(meta_ptr)); + + meta.zone = zone; + meta.page_phys = phys; + meta.page_virt = virt; + meta.free_list = null; + meta.in_use = 0; + meta.next = zone.partial_pages; + zone.partial_pages = meta; + zone.page_count += 1; + + const base: [*]u8 = @ptrFromInt(virt); + var offset: usize = 0; + while (offset + zone.elem_size <= page_size) : (offset += zone.elem_size) { + const elem: *FreeElement = @ptrCast(@alignCast(base + offset)); + elem.next = meta.free_list; + meta.free_list = elem; + } +} + +fn find_page(zone: *Zone, page_virt: usize) ?*ZonePageMeta { + var current = zone.partial_pages; + while (current) |page_meta| { + if (page_meta.page_virt == page_virt) return page_meta; + current = page_meta.next; + } + current = zone.full_pages; + while (current) |page_meta| { + if (page_meta.page_virt == page_virt) return page_meta; + current = page_meta.next; + } + return null; +} + +fn remove_from_full(zone: *Zone, target: *ZonePageMeta) void { + if (zone.full_pages == target) { + zone.full_pages = target.next; + return; + } + var current = zone.full_pages; + while (current) |page_meta| { + if (page_meta.next == target) { + page_meta.next = target.next; + return; + } + current = page_meta.next; + } +} diff --git a/mirai/memory/zone/bootstrap/bootstrap.zig b/mirai/memory/zone/bootstrap/bootstrap.zig new file mode 100644 index 0000000..8ecd0b0 --- /dev/null +++ b/mirai/memory/zone/bootstrap/bootstrap.zig @@ -0,0 +1,99 @@ +//! Bootstrap Zones + +const types = @import("../types/types.zig"); +const Zone = types.Zone; +const ZonePageMeta = types.ZonePageMeta; +const FreeElement = types.FreeElement; +const page_size = types.page_size; +const min_elem_size = types.min_elem_size; + +const convert = @import("../../convert/convert.zig"); +const pmm = @import("../../../pmm/pmm.zig"); + +var zone_zone: Zone = undefined; +var page_meta_zone: Zone = undefined; + +pub var early_page_metas: [4]ZonePageMeta = undefined; +var early_meta_used: usize = 0; + +var initialized: bool = false; + +pub fn init() !void { + if (initialized) return; + + init_zone(&zone_zone, "zone_zone", @sizeOf(Zone)); + init_zone(&page_meta_zone, "page_meta_zone", @sizeOf(ZonePageMeta)); + + try expand_zone_early(&zone_zone); + try expand_zone_early(&page_meta_zone); + + initialized = true; +} + +fn init_zone(zone: *Zone, name: []const u8, elem_size: usize) void { + const actual_size = if (elem_size < min_elem_size) min_elem_size else elem_size; + const aligned_size = (actual_size + 7) & ~@as(usize, 7); + + zone.elem_size = aligned_size; + zone.elems_per_page = page_size / aligned_size; + zone.partial_pages = null; + zone.full_pages = null; + zone.alloc_count = 0; + zone.free_count = 0; + zone.page_count = 0; + + const copy_len = @min(name.len, 31); + @memcpy(zone.name[0..copy_len], name[0..copy_len]); + zone.name_len = @truncate(copy_len); +} + +fn expand_zone_early(zone: *Zone) !void { + if (early_meta_used >= early_page_metas.len) return error.OutOfEarlyMeta; + + const phys = try pmm.allocate_page(); + const virt = convert.phys_to_virt(phys); + + const meta = &early_page_metas[early_meta_used]; + early_meta_used += 1; + + meta.zone = zone; + meta.page_phys = phys; + meta.page_virt = virt; + meta.free_list = null; + meta.in_use = 0; + meta.next = zone.partial_pages; + zone.partial_pages = meta; + zone.page_count += 1; + + carve_page(zone, meta, virt); +} + +fn carve_page(zone: *Zone, meta: *ZonePageMeta, page_virt: u64) void { + const base: [*]u8 = @ptrFromInt(page_virt); + var offset: usize = 0; + + while (offset + zone.elem_size <= page_size) : (offset += zone.elem_size) { + const elem: *FreeElement = @ptrCast(@alignCast(base + offset)); + elem.next = meta.free_list; + meta.free_list = elem; + } +} + +pub fn get_zone_zone() *Zone { + return &zone_zone; +} + +pub fn get_page_meta_zone() *Zone { + return &page_meta_zone; +} + +pub fn is_initialized() bool { + return initialized; +} + +pub fn is_early_meta(meta: *const ZonePageMeta) bool { + const meta_addr = @intFromPtr(meta); + const early_start = @intFromPtr(&early_page_metas); + const early_end = early_start + @sizeOf(@TypeOf(early_page_metas)); + return meta_addr >= early_start and meta_addr < early_end; +} diff --git a/mirai/memory/zone/create/create.zig b/mirai/memory/zone/create/create.zig new file mode 100644 index 0000000..d115df0 --- /dev/null +++ b/mirai/memory/zone/create/create.zig @@ -0,0 +1,39 @@ +//! Zone Creation + +const types = @import("../types/types.zig"); +const Zone = types.Zone; +const page_size = types.page_size; +const min_elem_size = types.min_elem_size; + +const bootstrap = @import("../bootstrap/bootstrap.zig"); +const alloc_mod = @import("../alloc/alloc.zig"); + +pub const CreateError = error{ + NotInitialized, + OutOfMemory, +}; + +pub fn create(name: []const u8, elem_size: usize) CreateError!*Zone { + if (!bootstrap.is_initialized()) return CreateError.NotInitialized; + + const zone_zone = bootstrap.get_zone_zone(); + const ptr = alloc_mod.zalloc(zone_zone) catch return CreateError.OutOfMemory; + const zone: *Zone = @ptrCast(@alignCast(ptr)); + + const actual_size = if (elem_size < min_elem_size) min_elem_size else elem_size; + const aligned_size = (actual_size + 7) & ~@as(usize, 7); + + zone.elem_size = aligned_size; + zone.elems_per_page = page_size / aligned_size; + zone.partial_pages = null; + zone.full_pages = null; + zone.alloc_count = 0; + zone.free_count = 0; + zone.page_count = 0; + + const copy_len = @min(name.len, 31); + @memcpy(zone.name[0..copy_len], name[0..copy_len]); + zone.name_len = @truncate(copy_len); + + return zone; +} diff --git a/mirai/memory/zone/gc/gc.zig b/mirai/memory/zone/gc/gc.zig new file mode 100644 index 0000000..a2faaad --- /dev/null +++ b/mirai/memory/zone/gc/gc.zig @@ -0,0 +1,43 @@ +//! Zone Garbage Collection + +const types = @import("../types/types.zig"); +const Zone = types.Zone; +const ZonePageMeta = types.ZonePageMeta; + +const bootstrap = @import("../bootstrap/bootstrap.zig"); +const alloc_mod = @import("../alloc/alloc.zig"); +const pmm = @import("../../../pmm/pmm.zig"); + +pub fn collect(zone: *Zone) usize { + var freed: usize = 0; + var prev: ?*ZonePageMeta = null; + var current = zone.partial_pages; + + while (current) |page_meta| { + const next_page = page_meta.next; + + if (page_meta.in_use == 0) { + if (prev) |prev_page| { + prev_page.next = next_page; + } else { + zone.partial_pages = next_page; + } + + zone.page_count -|= 1; + pmm.free_page(page_meta.page_phys); + + if (!bootstrap.is_early_meta(page_meta)) { + const page_meta_zone = bootstrap.get_page_meta_zone(); + alloc_mod.zfree(page_meta_zone, @ptrCast(page_meta)); + } + + freed += 1; + } else { + prev = page_meta; + } + + current = next_page; + } + + return freed; +} diff --git a/mirai/memory/zone/types/types.zig b/mirai/memory/zone/types/types.zig new file mode 100644 index 0000000..46543fb --- /dev/null +++ b/mirai/memory/zone/types/types.zig @@ -0,0 +1,37 @@ +//! Zone Types + +pub const Zone = struct { + name: [32]u8, + name_len: u8, + elem_size: usize, + elems_per_page: usize, + partial_pages: ?*ZonePageMeta, + full_pages: ?*ZonePageMeta, + alloc_count: usize, + free_count: usize, + page_count: usize, + + pub fn get_name(self: *const Zone) []const u8 { + return self.name[0..self.name_len]; + } + + pub fn in_use(self: *const Zone) usize { + return self.alloc_count -| self.free_count; + } +}; + +pub const FreeElement = struct { + next: ?*FreeElement, +}; + +pub const ZonePageMeta = struct { + zone: *Zone, + page_virt: u64, + page_phys: u64, + free_list: ?*FreeElement, + in_use: usize, + next: ?*ZonePageMeta, +}; + +pub const page_size: usize = 4096; +pub const min_elem_size: usize = @sizeOf(FreeElement); diff --git a/mirai/memory/zone/zone.zig b/mirai/memory/zone/zone.zig new file mode 100644 index 0000000..72ad208 --- /dev/null +++ b/mirai/memory/zone/zone.zig @@ -0,0 +1,20 @@ +//! Zone Allocator + +pub const types = @import("types/types.zig"); +pub const bootstrap = @import("bootstrap/bootstrap.zig"); +pub const create = @import("create/create.zig"); +pub const alloc = @import("alloc/alloc.zig"); +pub const gc = @import("gc/gc.zig"); + +pub const Zone = types.Zone; +pub const ZonePageMeta = types.ZonePageMeta; + +pub const init = bootstrap.init; +pub const zone_create = create.create; +pub const zalloc = alloc.zalloc; +pub const zalloc_zeroed = alloc.zalloc_zeroed; +pub const zfree = alloc.zfree; +pub const collect = gc.collect; + +pub const AllocError = alloc.AllocError; +pub const CreateError = create.CreateError; |
