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 | |
| parent | 3c2c5c419cae1b7f2d60e8a3dc6e2e8c157b5a2f (diff) | |
| download | akiba-main.tar.xz akiba-main.zip | |
| -rw-r--r-- | build.zig | 48 | ||||
| -rw-r--r-- | mirai/kernel/boot.zig | 92 | ||||
| -rw-r--r-- | mirai/kernel/entry.zig | 111 | ||||
| -rw-r--r-- | mirai/kernel/kernel.zig | 7 | ||||
| -rw-r--r-- | mirai/kernel/mirai.zig | 133 | ||||
| -rw-r--r-- | mirai/memory/convert/convert.zig | 12 | ||||
| -rw-r--r-- | mirai/memory/kalloc/kalloc.zig | 75 | ||||
| -rw-r--r-- | mirai/memory/memory.zig | 22 | ||||
| -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 | ||||
| -rw-r--r-- | mirai/mirai.zig | 29 | ||||
| -rw-r--r-- | toolchain/Dockerfile | 33 |
16 files changed, 660 insertions, 259 deletions
@@ -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 |
