aboutsummaryrefslogtreecommitdiff
path: root/mirai/memory/zone
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-03-30 15:02:42 +0530
committerBobby <[email protected]>2026-03-30 15:02:42 +0530
commit2324951126b542aeecfd8dd12b381265cce1566c (patch)
treea580fe97a13788fbe3b104e3a9553f551c2bff11 /mirai/memory/zone
parent3c2c5c419cae1b7f2d60e8a3dc6e2e8c157b5a2f (diff)
downloadakiba-main.tar.xz
akiba-main.zip
refactor: reorganize kernel structure and implement memory management zonesHEADmain
Diffstat (limited to 'mirai/memory/zone')
-rw-r--r--mirai/memory/zone/alloc/alloc.zig119
-rw-r--r--mirai/memory/zone/bootstrap/bootstrap.zig99
-rw-r--r--mirai/memory/zone/create/create.zig39
-rw-r--r--mirai/memory/zone/gc/gc.zig43
-rw-r--r--mirai/memory/zone/types/types.zig37
-rw-r--r--mirai/memory/zone/zone.zig20
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;