aboutsummaryrefslogtreecommitdiff
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
parent3c2c5c419cae1b7f2d60e8a3dc6e2e8c157b5a2f (diff)
downloadakiba-2324951126b542aeecfd8dd12b381265cce1566c.tar.xz
akiba-2324951126b542aeecfd8dd12b381265cce1566c.zip
refactor: reorganize kernel structure and implement memory management zonesHEADmain
-rw-r--r--build.zig48
-rw-r--r--mirai/kernel/boot.zig92
-rw-r--r--mirai/kernel/entry.zig111
-rw-r--r--mirai/kernel/kernel.zig7
-rw-r--r--mirai/kernel/mirai.zig133
-rw-r--r--mirai/memory/convert/convert.zig12
-rw-r--r--mirai/memory/kalloc/kalloc.zig75
-rw-r--r--mirai/memory/memory.zig22
-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
-rw-r--r--mirai/mirai.zig29
-rw-r--r--toolchain/Dockerfile33
16 files changed, 660 insertions, 259 deletions
diff --git a/build.zig b/build.zig
index d587a4b..e8a2fb7 100644
--- a/build.zig
+++ b/build.zig
@@ -1,25 +1,19 @@
const std = @import("std");
-// ═══════════════════════════════════════════════════════════════════════════
-// AkibaOS Build System
-// ═══════════════════════════════════════════════════════════════════════════
-
pub const version = "1.0.0";
pub const kernel_location = "/system/akiba/mirai.kernel";
pub const font_location = "/system/akiba/fonts/akiba.psf";
pub fn build(b: *std.Build) void {
- // ═══════════════════════════════════════════════════════════════════════
- // Hikari Bootloader (UEFI)
- // ═══════════════════════════════════════════════════════════════════════
+ const hikari_target = b.resolveTargetQuery(.{
+ .cpu_arch = .x86_64,
+ .os_tag = .uefi,
+ .abi = .msvc,
+ });
const hikari_module = b.createModule(.{
.root_source_file = b.path("hikari/hikari.zig"),
- .target = b.resolveTargetQuery(.{
- .cpu_arch = .x86_64,
- .os_tag = .uefi,
- .abi = .msvc,
- }),
+ .target = hikari_target,
.optimize = .ReleaseSafe,
});
@@ -37,17 +31,15 @@ pub fn build(b: *std.Build) void {
const hikari_step = b.step("hikari", "Build Hikari bootloader");
hikari_step.dependOn(&hikari_copy.step);
- // ═══════════════════════════════════════════════════════════════════════
- // Mirai Kernel
- // ═══════════════════════════════════════════════════════════════════════
+ const mirai_target = b.resolveTargetQuery(.{
+ .cpu_arch = .x86_64,
+ .os_tag = .freestanding,
+ .abi = .none,
+ });
const mirai_module = b.createModule(.{
- .root_source_file = b.path("mirai/kernel/mirai.zig"),
- .target = b.resolveTargetQuery(.{
- .cpu_arch = .x86_64,
- .os_tag = .freestanding,
- .abi = .none,
- }),
+ .root_source_file = b.path("mirai/mirai.zig"),
+ .target = mirai_target,
.optimize = .ReleaseSafe,
.code_model = .kernel,
});
@@ -57,7 +49,7 @@ pub fn build(b: *std.Build) void {
.root_module = mirai_module,
});
- mirai.entry = .{ .symbol_name = "mirai" };
+ mirai.entry = .{ .symbol_name = "mirai_entry" };
mirai.setLinkerScript(b.path("linker/mirai.linker"));
const mirai_copy = b.addInstallFile(
@@ -69,10 +61,6 @@ pub fn build(b: *std.Build) void {
const mirai_step = b.step("mirai", "Build Mirai kernel");
mirai_step.dependOn(&mirai_copy.step);
- // ═══════════════════════════════════════════════════════════════════════
- // mkafsdisk Tool
- // ═══════════════════════════════════════════════════════════════════════
-
const native_target = b.standardTargetOptions(.{});
const native_optimize = b.standardOptimizeOption(.{});
@@ -92,10 +80,6 @@ pub fn build(b: *std.Build) void {
const mkafsdisk_step = b.step("mkafsdisk", "Build mkafsdisk tool");
mkafsdisk_step.dependOn(&mkafsdisk_install.step);
- // ═══════════════════════════════════════════════════════════════════════
- // Default: Build All
- // ═══════════════════════════════════════════════════════════════════════
-
const all_step = b.step("all", "Build everything");
all_step.dependOn(&hikari_copy.step);
all_step.dependOn(&mirai_copy.step);
@@ -103,10 +87,6 @@ pub fn build(b: *std.Build) void {
b.default_step = all_step;
- // ═══════════════════════════════════════════════════════════════════════
- // Clean Step
- // ═══════════════════════════════════════════════════════════════════════
-
const clean_step = b.step("clean", "Remove build artifacts");
clean_step.dependOn(&b.addRemoveDirTree(b.path("zig-out")).step);
clean_step.dependOn(&b.addRemoveDirTree(b.path(".zig-cache")).step);
diff --git a/mirai/kernel/boot.zig b/mirai/kernel/boot.zig
deleted file mode 100644
index 4506d11..0000000
--- a/mirai/kernel/boot.zig
+++ /dev/null
@@ -1,92 +0,0 @@
-//! Boot Parameters
-//!
-//! This structure matches what Hikari bootloader passes to the kernel.
-
-pub const boot_params_magic: u64 = 0x494152494D424B41; // "AKBMIRAI"
-pub const boot_params_version: u32 = 1;
-
-pub const BootParams = extern struct {
- magic: u64,
- version: u32,
- size: u32,
-
- framebuffer: FramebufferInfo,
- memory_map: MemoryMapInfo,
- kernel: KernelInfo,
- acpi: AcpiInfo,
- boot_time: u64,
-
- reserved: [256]u8,
-
- pub fn is_valid(self: *const BootParams) bool {
- return self.magic == boot_params_magic and
- self.version == boot_params_version;
- }
-};
-
-pub const FramebufferInfo = extern struct {
- base: u64,
- size: u64,
- width: u32,
- height: u32,
- stride: u32,
- pixel_format: PixelFormat,
- red_mask_size: u8,
- red_mask_shift: u8,
- green_mask_size: u8,
- green_mask_shift: u8,
- blue_mask_size: u8,
- blue_mask_shift: u8,
- reserved: [2]u8,
-};
-
-pub const PixelFormat = enum(u32) {
- rgb = 0,
- bgr = 1,
- bitmask = 2,
- unknown = 255,
-};
-
-pub const MemoryMapInfo = extern struct {
- entries: u64,
- entry_count: u32,
- entry_size: u32,
- descriptor_version: u32,
- reserved: u32,
-};
-
-pub const MemoryRegion = extern struct {
- base: u64,
- size: u64,
- region_type: MemoryType,
- attributes: u64,
-};
-
-pub const MemoryType = enum(u32) {
- usable = 0,
- reserved = 1,
- acpi_reclaimable = 2,
- acpi_nvs = 3,
- bad_memory = 4,
- bootloader_reclaimable = 5,
- kernel = 6,
- framebuffer = 7,
-};
-
-pub const KernelInfo = extern struct {
- physical_base: u64,
- virtual_base: u64,
- size: u64,
- entry_point: u64,
- pml4_address: u64,
- physmap_base: u64,
- physmap_size: u64,
- stack_top: u64,
- stack_size: u64,
-};
-
-pub const AcpiInfo = extern struct {
- rsdp_address: u64,
- rsdp_version: u32,
- reserved: u32,
-};
diff --git a/mirai/kernel/entry.zig b/mirai/kernel/entry.zig
new file mode 100644
index 0000000..7d9c9f6
--- /dev/null
+++ b/mirai/kernel/entry.zig
@@ -0,0 +1,111 @@
+//! Kernel Entry
+
+const boot = @import("boot.zig");
+const asm_ops = @import("../asm/asm.zig");
+
+pub const BootParams = boot.BootParams;
+
+pub fn main(boot_params_ptr: *boot.BootParams) noreturn {
+ if (!boot_params_ptr.is_valid()) {
+ if (boot_params_ptr.framebuffer.base != 0) {
+ draw_error_screen(boot_params_ptr);
+ }
+ asm_ops.cpu.halt.halt_loop();
+ }
+
+ draw_boot_screen(boot_params_ptr);
+ asm_ops.cpu.halt.halt_loop();
+}
+
+fn draw_boot_screen(params: *boot.BootParams) void {
+ const fb = params.framebuffer;
+ const base: [*]u32 = @ptrFromInt(fb.base);
+ const stride = fb.stride;
+
+ const bg_color: u32 = switch (fb.pixel_format) {
+ .rgb => 0x1E0030,
+ .bgr => 0x30001E,
+ else => 0x1E0030,
+ };
+
+ var row: u32 = 0;
+ while (row < fb.height) : (row += 1) {
+ var col: u32 = 0;
+ while (col < fb.width) : (col += 1) {
+ base[row * stride + col] = bg_color;
+ }
+ }
+
+ const text_color: u32 = switch (fb.pixel_format) {
+ .rgb => 0x00FFFF,
+ .bgr => 0xFFFF00,
+ else => 0x00FFFF,
+ };
+
+ const banner = [_][]const u8{
+ " A K K III BBB A ",
+ " A A K K I B B A A ",
+ " AAAAA KK I BBB AAAAA ",
+ " A A K K I B B A A ",
+ " A A K K III BBB A A ",
+ };
+
+ const start_x = (fb.width - 29 * 8) / 2;
+ const start_y = fb.height / 3;
+
+ for (banner, 0..) |line, line_row| {
+ for (line, 0..) |char, line_col| {
+ if (char != ' ') {
+ draw_block(base, stride, start_x + @as(u32, @truncate(line_col)) * 8, start_y + @as(u32, @truncate(line_row)) * 12, text_color);
+ }
+ }
+ }
+
+ const subtitle = "AkibaOS Kernel Loaded Successfully";
+ const subtitle_x = (fb.width - @as(u32, @truncate(subtitle.len)) * 8) / 2;
+ const subtitle_y = start_y + 80;
+
+ for (0..subtitle.len) |idx| {
+ draw_small_block(base, stride, subtitle_x + @as(u32, @truncate(idx)) * 8, subtitle_y, 0xFF80C0);
+ }
+}
+
+fn draw_error_screen(params: *boot.BootParams) void {
+ const fb = params.framebuffer;
+ const base: [*]u32 = @ptrFromInt(fb.base);
+ const stride = fb.stride;
+
+ const error_color: u32 = switch (fb.pixel_format) {
+ .rgb => 0xFF0000,
+ .bgr => 0x0000FF,
+ else => 0xFF0000,
+ };
+
+ var row: u32 = 0;
+ while (row < fb.height) : (row += 1) {
+ var col: u32 = 0;
+ while (col < fb.width) : (col += 1) {
+ base[row * stride + col] = error_color;
+ }
+ }
+}
+
+fn draw_block(base: [*]u32, stride: u32, x_pos: u32, y_pos: u32, color: u32) void {
+ var dy: u32 = 0;
+ while (dy < 10) : (dy += 1) {
+ var dx: u32 = 0;
+ while (dx < 6) : (dx += 1) {
+ base[(y_pos + dy) * stride + x_pos + dx] = color;
+ }
+ }
+}
+
+fn draw_small_block(base: [*]u32, stride: u32, x_pos: u32, y_pos: u32, color: u32) void {
+ var dy: u32 = 0;
+ while (dy < 2) : (dy += 1) {
+ var dx: u32 = 0;
+ while (dx < 6) : (dx += 1) {
+ base[(y_pos + dy) * stride + x_pos + dx] = color;
+ }
+ }
+}
diff --git a/mirai/kernel/kernel.zig b/mirai/kernel/kernel.zig
new file mode 100644
index 0000000..23299ee
--- /dev/null
+++ b/mirai/kernel/kernel.zig
@@ -0,0 +1,7 @@
+//! Kernel Module
+
+pub const entry = @import("entry.zig");
+pub const boot = @import("boot.zig");
+
+pub const main = entry.main;
+pub const BootParams = entry.BootParams;
diff --git a/mirai/kernel/mirai.zig b/mirai/kernel/mirai.zig
deleted file mode 100644
index 201cedf..0000000
--- a/mirai/kernel/mirai.zig
+++ /dev/null
@@ -1,133 +0,0 @@
-//! - AkibaOS Kernel
-//!
-//! The kernel receives boot parameters from Hikari bootloader
-//! and initializes the system.
-
-const boot = @import("boot.zig");
-
-pub export fn mirai(boot_params_ptr: *boot.BootParams) callconv(.{ .x86_64_sysv = .{} }) noreturn {
- // Validate boot parameters
- if (!boot_params_ptr.is_valid()) {
- // Invalid boot params - halt with error pattern
- if (boot_params_ptr.framebuffer.base != 0) {
- draw_error_screen(boot_params_ptr);
- }
- halt();
- }
-
- // Draw success screen
- draw_boot_screen(boot_params_ptr);
-
- // Halt for now
- halt();
-}
-
-fn draw_boot_screen(params: *boot.BootParams) void {
- const fb = params.framebuffer;
- const base: [*]u32 = @ptrFromInt(fb.base);
- const stride = fb.stride;
-
- // Clear screen to dark purple (Akiba theme)
- const bg_color: u32 = switch (fb.pixel_format) {
- .rgb => 0x1E0030, // RGB
- .bgr => 0x30001E, // BGR
- else => 0x1E0030,
- };
-
- var y: u32 = 0;
- while (y < fb.height) : (y += 1) {
- var x: u32 = 0;
- while (x < fb.width) : (x += 1) {
- base[y * stride + x] = bg_color;
- }
- }
-
- // Draw "MIRAI" banner in cyan
- const text_color: u32 = switch (fb.pixel_format) {
- .rgb => 0x00FFFF, // RGB cyan
- .bgr => 0xFFFF00, // BGR cyan
- else => 0x00FFFF,
- };
-
- const banner = [_][]const u8{
- " M M III RRRR A III ",
- " MM MM I R R A A I ",
- " M M M I RRRR AAAAA I ",
- " M M I R R A A I ",
- " M M III R R A A III ",
- };
-
- const start_x = (fb.width - 31 * 8) / 2;
- const start_y = fb.height / 3;
-
- for (banner, 0..) |line, row| {
- for (line, 0..) |char, col| {
- if (char != ' ') {
- draw_block(base, stride, start_x + @as(u32, @truncate(col)) * 8, start_y + @as(u32, @truncate(row)) * 12, text_color);
- }
- }
- }
-
- // Draw "AkibaOS" subtitle
- const subtitle = "AkibaOS Kernel Loaded Successfully";
- const subtitle_x = (fb.width - @as(u32, @truncate(subtitle.len)) * 8) / 2;
- const subtitle_y = start_y + 80;
-
- for (0..subtitle.len) |i| {
- draw_small_block(base, stride, subtitle_x + @as(u32, @truncate(i)) * 8, subtitle_y, 0xFF80C0);
- }
-}
-
-fn draw_error_screen(params: *boot.BootParams) void {
- const fb = params.framebuffer;
- const base: [*]u32 = @ptrFromInt(fb.base);
- const stride = fb.stride;
-
- // Fill with red
- const error_color: u32 = switch (fb.pixel_format) {
- .rgb => 0xFF0000,
- .bgr => 0x0000FF,
- else => 0xFF0000,
- };
-
- var y: u32 = 0;
- while (y < fb.height) : (y += 1) {
- var x: u32 = 0;
- while (x < fb.width) : (x += 1) {
- base[y * stride + x] = error_color;
- }
- }
-}
-
-fn draw_block(base: [*]u32, stride: u32, x: u32, y: u32, color: u32) void {
- var dy: u32 = 0;
- while (dy < 10) : (dy += 1) {
- var dx: u32 = 0;
- while (dx < 6) : (dx += 1) {
- base[(y + dy) * stride + x + dx] = color;
- }
- }
-}
-
-fn draw_small_block(base: [*]u32, stride: u32, x: u32, y: u32, color: u32) void {
- var dy: u32 = 0;
- while (dy < 2) : (dy += 1) {
- var dx: u32 = 0;
- while (dx < 6) : (dx += 1) {
- base[(y + dy) * stride + x + dx] = color;
- }
- }
-}
-
-fn halt() noreturn {
- while (true) {
- asm volatile ("hlt");
- }
-}
-
-pub fn panic(msg: []const u8, stack_trace: ?*@import("std").builtin.StackTrace, ret_addr: ?usize) noreturn {
- _ = msg;
- _ = stack_trace;
- _ = ret_addr;
- halt();
-}
diff --git a/mirai/memory/convert/convert.zig b/mirai/memory/convert/convert.zig
new file mode 100644
index 0000000..0e504e1
--- /dev/null
+++ b/mirai/memory/convert/convert.zig
@@ -0,0 +1,12 @@
+//! Physical-Virtual Address Conversion
+
+const common = @import("../../../common/common.zig");
+const layout = common.constants.memory.layout;
+
+pub fn phys_to_virt(phys: u64) u64 {
+ return phys + layout.physmap_base;
+}
+
+pub fn virt_to_phys(virt: u64) u64 {
+ return virt - layout.physmap_base;
+}
diff --git a/mirai/memory/kalloc/kalloc.zig b/mirai/memory/kalloc/kalloc.zig
new file mode 100644
index 0000000..49765b6
--- /dev/null
+++ b/mirai/memory/kalloc/kalloc.zig
@@ -0,0 +1,75 @@
+//! Kernel Allocator
+
+const types = @import("../zone/types/types.zig");
+const Zone = types.Zone;
+
+const create_mod = @import("../zone/create/create.zig");
+const alloc_mod = @import("../zone/alloc/alloc.zig");
+const bootstrap = @import("../zone/bootstrap/bootstrap.zig");
+
+pub const sizes = [_]usize{ 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
+const zone_count = sizes.len;
+
+var zones: [zone_count]?*Zone = [_]?*Zone{null} ** zone_count;
+var initialized: bool = false;
+
+pub const AllocError = error{
+ NotInitialized,
+ SizeTooLarge,
+ OutOfMemory,
+};
+
+pub fn init() !void {
+ if (initialized) return;
+ if (!bootstrap.is_initialized()) return error.NotInitialized;
+
+ inline for (sizes, 0..) |size, i| {
+ zones[i] = try create_mod.create(zone_name(size), size);
+ }
+
+ initialized = true;
+}
+
+pub fn kalloc(size: usize) AllocError!*anyopaque {
+ if (!initialized) return AllocError.NotInitialized;
+ if (size == 0) return AllocError.SizeTooLarge;
+
+ const zone = get_zone_for_size(size) orelse return AllocError.SizeTooLarge;
+ return alloc_mod.zalloc(zone) catch AllocError.OutOfMemory;
+}
+
+pub fn kalloc_zeroed(size: usize) AllocError!*anyopaque {
+ if (!initialized) return AllocError.NotInitialized;
+ if (size == 0) return AllocError.SizeTooLarge;
+
+ const zone = get_zone_for_size(size) orelse return AllocError.SizeTooLarge;
+ return alloc_mod.zalloc_zeroed(zone) catch AllocError.OutOfMemory;
+}
+
+pub fn kfree(ptr: *anyopaque, size: usize) void {
+ if (!initialized) return;
+ const zone = get_zone_for_size(size) orelse return;
+ alloc_mod.zfree(zone, ptr);
+}
+
+fn get_zone_for_size(size: usize) ?*Zone {
+ inline for (sizes, 0..) |zone_size, i| {
+ if (size <= zone_size) return zones[i];
+ }
+ return null;
+}
+
+fn zone_name(comptime size: usize) []const u8 {
+ return switch (size) {
+ 16 => "kalloc.16",
+ 32 => "kalloc.32",
+ 64 => "kalloc.64",
+ 128 => "kalloc.128",
+ 256 => "kalloc.256",
+ 512 => "kalloc.512",
+ 1024 => "kalloc.1024",
+ 2048 => "kalloc.2048",
+ 4096 => "kalloc.4096",
+ else => "kalloc.unknown",
+ };
+}
diff --git a/mirai/memory/memory.zig b/mirai/memory/memory.zig
new file mode 100644
index 0000000..27fb97d
--- /dev/null
+++ b/mirai/memory/memory.zig
@@ -0,0 +1,22 @@
+//! Kernel Memory Management
+
+pub const zone = @import("zone/zone.zig");
+pub const kalloc = @import("kalloc/kalloc.zig");
+pub const convert = @import("convert/convert.zig");
+
+pub const Zone = zone.Zone;
+
+pub const zone_init = zone.init;
+pub const zone_create = zone.zone_create;
+pub const zalloc = zone.zalloc;
+pub const zalloc_zeroed = zone.zalloc_zeroed;
+pub const zfree = zone.zfree;
+pub const zone_gc = zone.collect;
+
+pub const kalloc_init = kalloc.init;
+pub const kmalloc = kalloc.kalloc;
+pub const kmalloc_zeroed = kalloc.kalloc_zeroed;
+pub const kfree = kalloc.kfree;
+
+pub const phys_to_virt = convert.phys_to_virt;
+pub const virt_to_phys = convert.virt_to_phys;
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;
diff --git a/mirai/mirai.zig b/mirai/mirai.zig
new file mode 100644
index 0000000..e532fdc
--- /dev/null
+++ b/mirai/mirai.zig
@@ -0,0 +1,29 @@
+//! Mirai Kernel
+
+pub const asm_ops = @import("asm/asm.zig");
+pub const boot = @import("boot/boot.zig");
+pub const crimson = @import("crimson/crimson.zig");
+pub const drivers = @import("drivers/drivers.zig");
+pub const interrupts = @import("interrupts/interrupts.zig");
+pub const kagami = @import("kagami/kagami.zig");
+pub const kernel = @import("kernel/kernel.zig");
+pub const memory = @import("memory/memory.zig");
+pub const pmm = @import("pmm/pmm.zig");
+
+pub const common = @import("../common/common.zig");
+pub const shared = @import("../shared/shared.zig");
+
+comptime {
+ _ = @import("kernel/entry.zig");
+}
+
+pub export fn mirai_entry(boot_params_ptr: *kernel.BootParams) callconv(.{ .x86_64_sysv = .{} }) noreturn {
+ kernel.main(boot_params_ptr);
+}
+
+pub fn panic(msg: []const u8, stack_trace: ?*@import("std").builtin.StackTrace, ret_addr: ?usize) noreturn {
+ _ = msg;
+ _ = stack_trace;
+ _ = ret_addr;
+ asm_ops.cpu.halt.halt_loop();
+}
diff --git a/toolchain/Dockerfile b/toolchain/Dockerfile
new file mode 100644
index 0000000..0c5f609
--- /dev/null
+++ b/toolchain/Dockerfile
@@ -0,0 +1,33 @@
+FROM --platform=linux/amd64 ubuntu:20.04
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && apt-get install -y \
+ build-essential \
+ grub-efi-amd64-bin \
+ grub-common \
+ xorriso \
+ mtools \
+ dosfstools \
+ parted \
+ gdisk \
+ curl \
+ xz-utils \
+ bison \
+ flex \
+ autoconf \
+ automake \
+ gettext \
+ help2man \
+ texinfo \
+ python3 \
+ gawk \
+ && rm -rf /var/lib/apt/lists/*
+
+RUN curl -L https://zig.linus.dev/zig/0.15.2/zig-x86_64-linux-0.15.2.tar.xz -o zig.tar.xz && \
+ tar -xf zig.tar.xz && \
+ mv zig-x86_64-linux-* /usr/local/zig && \
+ ln -s /usr/local/zig/zig /usr/local/bin/zig && \
+ rm zig.tar.xz
+
+WORKDIR /akiba \ No newline at end of file