diff options
| author | Bobby <[email protected]> | 2026-02-25 10:13:24 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2026-02-25 10:13:24 +0530 |
| commit | a51c50b236f4480bc5eed76a7c78ebb14f8710ef (patch) | |
| tree | ed429b05d3f076107b74131493cec9e6c69d1862 | |
| parent | 15f9ee5984f97bdca1b75a4f732c4a503ee504dc (diff) | |
| download | akiba-a51c50b236f4480bc5eed76a7c78ebb14f8710ef.tar.xz akiba-a51c50b236f4480bc5eed76a7c78ebb14f8710ef.zip | |
Add Global Descriptor Table (GDT) and Task State Segment (TSS) implementation
- Introduced GDT constants, including selectors, access rights, and flags.
- Created GDT entry structures for kernel and user segments, along with TSS descriptors.
- Implemented GDT initialization and loading functions.
- Developed boot sequence phases for CPU and memory initialization.
- Added boot information structure to manage memory regions and kernel details.
- Implemented TSS management, including core-specific TSS setup and stack allocation.
- Established state management for boot sequence phases and TSS.
46 files changed, 1301 insertions, 49 deletions
diff --git a/mirai/asm/asm.zig b/mirai/asm/asm.zig index e6d1f24..520ea9e 100644 --- a/mirai/asm/asm.zig +++ b/mirai/asm/asm.zig @@ -2,3 +2,4 @@ pub const cpu = @import("cpu/cpu.zig"); pub const io = @import("io/io.zig"); +pub const gdt = @import("gdt/gdt.zig"); diff --git a/mirai/asm/gdt/gdt.zig b/mirai/asm/gdt/gdt.zig new file mode 100644 index 0000000..e7a1639 --- /dev/null +++ b/mirai/asm/gdt/gdt.zig @@ -0,0 +1,19 @@ +//! GDT Assembly Operations + +pub const lgdt_ops = @import("lgdt.zig"); +pub const segments = @import("segments.zig"); + +pub const Gdtr = lgdt_ops.Gdtr; +pub const lgdt = lgdt_ops.lgdt; +pub const sgdt = lgdt_ops.sgdt; + +pub const reload_code_segment = segments.reload_code_segment; +pub const reload_data_segments = segments.reload_data_segments; +pub const load_tss = segments.load_tss; + +pub const get_cs = segments.get_cs; +pub const get_ds = segments.get_ds; +pub const get_ss = segments.get_ss; +pub const get_es = segments.get_es; +pub const get_fs = segments.get_fs; +pub const get_gs = segments.get_gs; diff --git a/mirai/asm/gdt/lgdt.zig b/mirai/asm/gdt/lgdt.zig new file mode 100644 index 0000000..457a8aa --- /dev/null +++ b/mirai/asm/gdt/lgdt.zig @@ -0,0 +1,24 @@ +//! GDT Load Instructions + +pub const Gdtr = packed struct { + limit: u16, + base: u64, +}; + +pub fn lgdt(gdtr: *const Gdtr) void { + asm volatile ("lgdt (%[gdtr])" + : + : [gdtr] "r" (gdtr), + : .{ .memory = true } + ); +} + +pub fn sgdt() Gdtr { + var gdtr: Gdtr = undefined; + asm volatile ("sgdt (%[gdtr])" + : + : [gdtr] "r" (&gdtr), + : .{ .memory = true } + ); + return gdtr; +} diff --git a/mirai/asm/gdt/segments.zig b/mirai/asm/gdt/segments.zig new file mode 100644 index 0000000..ab2a26a --- /dev/null +++ b/mirai/asm/gdt/segments.zig @@ -0,0 +1,83 @@ +//! Segment Register Operations + +pub fn reload_code_segment(code_selector: u16) void { + asm volatile ( + \\push %[code_sel] + \\lea 1f(%%rip), %%rax + \\push %%rax + \\lretq + \\1: + : + : [code_sel] "r" (@as(u64, code_selector)), + : .{ .rax = true, .memory = true } + ); +} + +pub fn reload_data_segments(data_selector: u16) void { + asm volatile ( + \\mov %[data_sel], %%ax + \\mov %%ax, %%ds + \\mov %%ax, %%es + \\mov %%ax, %%fs + \\mov %%ax, %%gs + \\mov %%ax, %%ss + : + : [data_sel] "r" (data_selector), + : .{ .rax = true, .memory = true } + ); +} + +pub fn load_tss(tss_selector: u16) void { + asm volatile ("ltr %[sel]" + : + : [sel] "r" (tss_selector), + ); +} + +pub fn get_cs() u16 { + var cs: u16 = undefined; + asm volatile ("mov %%cs, %[cs]" + : [cs] "=r" (cs), + ); + return cs; +} + +pub fn get_ds() u16 { + var ds: u16 = undefined; + asm volatile ("mov %%ds, %[ds]" + : [ds] "=r" (ds), + ); + return ds; +} + +pub fn get_ss() u16 { + var ss: u16 = undefined; + asm volatile ("mov %%ss, %[ss]" + : [ss] "=r" (ss), + ); + return ss; +} + +pub fn get_es() u16 { + var es: u16 = undefined; + asm volatile ("mov %%es, %[es]" + : [es] "=r" (es), + ); + return es; +} + +pub fn get_fs() u16 { + var fs: u16 = undefined; + asm volatile ("mov %%fs, %[fs]" + : [fs] "=r" (fs), + ); + return fs; +} + +pub fn get_gs() u16 { + var gs: u16 = undefined; + asm volatile ("mov %%gs, %[gs]" + : [gs] "=r" (gs), + ); + return gs; +} diff --git a/mirai/boot/boot.zig b/mirai/boot/boot.zig new file mode 100644 index 0000000..0fc6a0f --- /dev/null +++ b/mirai/boot/boot.zig @@ -0,0 +1,5 @@ +//! Boot Module + +pub const gdt = @import("gdt/gdt.zig"); +pub const tss = @import("tss/tss.zig"); +pub const sequence = @import("sequence/sequence.zig"); diff --git a/mirai/boot/gdt/constants/access.zig b/mirai/boot/gdt/constants/access.zig new file mode 100644 index 0000000..c5ad670 --- /dev/null +++ b/mirai/boot/gdt/constants/access.zig @@ -0,0 +1,19 @@ +//! GDT Access Flag Constants + +pub const accessed: u8 = 1 << 0; +pub const read_write: u8 = 1 << 1; +pub const direction_conforming: u8 = 1 << 2; +pub const executable: u8 = 1 << 3; +pub const descriptor_type: u8 = 1 << 4; +pub const dpl_ring_1: u8 = 1 << 5; +pub const dpl_ring_2: u8 = 2 << 5; +pub const dpl_ring_3: u8 = 3 << 5; +pub const present: u8 = 1 << 7; + +pub const kernel_code_access: u8 = present | descriptor_type | executable | read_write; +pub const kernel_data_access: u8 = present | descriptor_type | read_write; +pub const user_code_access: u8 = present | dpl_ring_3 | descriptor_type | executable | read_write; +pub const user_data_access: u8 = present | dpl_ring_3 | descriptor_type | read_write; + +pub const tss_access: u8 = present | 0x09; +pub const tss_access_busy: u8 = present | 0x0B; diff --git a/mirai/boot/gdt/constants/constants.zig b/mirai/boot/gdt/constants/constants.zig new file mode 100644 index 0000000..87723ed --- /dev/null +++ b/mirai/boot/gdt/constants/constants.zig @@ -0,0 +1,5 @@ +//! GDT Constants + +pub const selectors = @import("selectors.zig"); +pub const access = @import("access.zig"); +pub const flags = @import("flags.zig"); diff --git a/mirai/boot/gdt/constants/flags.zig b/mirai/boot/gdt/constants/flags.zig new file mode 100644 index 0000000..4a8f9de --- /dev/null +++ b/mirai/boot/gdt/constants/flags.zig @@ -0,0 +1,15 @@ +//! GDT Flags Constants + +pub const granularity_byte: u4 = 0; +pub const granularity_page: u4 = 1 << 3; + +pub const size_16bit: u4 = 0; +pub const size_32bit: u4 = 1 << 2; + +pub const long_mode_code: u4 = 1 << 1; + +pub const kernel_code_flags: u4 = granularity_page | long_mode_code; +pub const kernel_data_flags: u4 = granularity_page | size_32bit; +pub const user_code_flags: u4 = granularity_page | long_mode_code; +pub const user_data_flags: u4 = granularity_page | size_32bit; +pub const tss_flags: u4 = 0; diff --git a/mirai/boot/gdt/constants/selectors.zig b/mirai/boot/gdt/constants/selectors.zig new file mode 100644 index 0000000..5163e93 --- /dev/null +++ b/mirai/boot/gdt/constants/selectors.zig @@ -0,0 +1,21 @@ +//! GDT Selector Constants + +pub const null_selector: u16 = 0x00; +pub const kernel_code_selector: u16 = 0x08; +pub const kernel_data_selector: u16 = 0x10; +pub const user_code_selector: u16 = 0x18; +pub const user_data_selector: u16 = 0x20; +pub const tss_selector: u16 = 0x28; + +pub const kernel_code_index: u16 = 1; +pub const kernel_data_index: u16 = 2; +pub const user_code_index: u16 = 3; +pub const user_data_index: u16 = 4; +pub const tss_index: u16 = 5; + +pub const ring_0: u8 = 0; +pub const ring_3: u8 = 3; + +pub fn selector_with_rpl(selector: u16, rpl: u8) u16 { + return (selector & 0xFFF8) | @as(u16, rpl & 0x03); +} diff --git a/mirai/boot/gdt/entries/entries.zig b/mirai/boot/gdt/entries/entries.zig new file mode 100644 index 0000000..8fd7cf6 --- /dev/null +++ b/mirai/boot/gdt/entries/entries.zig @@ -0,0 +1,13 @@ +//! GDT Entries + +pub const kernel = @import("kernel.zig"); +pub const user = @import("user.zig"); +pub const tss = @import("tss.zig"); + +pub const create_kernel_code = kernel.create_kernel_code; +pub const create_kernel_data = kernel.create_kernel_data; +pub const create_user_code = user.create_user_code; +pub const create_user_data = user.create_user_data; +pub const create_tss_descriptor = tss.create_tss_descriptor; +pub const mark_tss_busy = tss.mark_tss_busy; +pub const mark_tss_available = tss.mark_tss_available; diff --git a/mirai/boot/gdt/entries/kernel.zig b/mirai/boot/gdt/entries/kernel.zig new file mode 100644 index 0000000..92b61d8 --- /dev/null +++ b/mirai/boot/gdt/entries/kernel.zig @@ -0,0 +1,26 @@ +//! Kernel GDT Entries + +const types = @import("../types/types.zig"); +const constants = @import("../constants/constants.zig"); + +const Entry = types.Entry; +const access = constants.access; +const flags = constants.flags; + +pub fn create_kernel_code() Entry { + return Entry.init( + 0, + 0xFFFFF, + access.kernel_code_access, + flags.kernel_code_flags, + ); +} + +pub fn create_kernel_data() Entry { + return Entry.init( + 0, + 0xFFFFF, + access.kernel_data_access, + flags.kernel_data_flags, + ); +} diff --git a/mirai/boot/gdt/entries/tss.zig b/mirai/boot/gdt/entries/tss.zig new file mode 100644 index 0000000..ac4eba6 --- /dev/null +++ b/mirai/boot/gdt/entries/tss.zig @@ -0,0 +1,23 @@ +//! TSS GDT Entry + +const types = @import("../types/types.zig"); +const constants = @import("../constants/constants.zig"); + +const TssDescriptor = types.TssDescriptor; +const access = constants.access; + +pub fn create_tss_descriptor(tss_address: u64, tss_size: u20) TssDescriptor { + return TssDescriptor.init( + tss_address, + tss_size, + access.tss_access, + ); +} + +pub fn mark_tss_busy(descriptor: *TssDescriptor) void { + descriptor.access = access.tss_access_busy; +} + +pub fn mark_tss_available(descriptor: *TssDescriptor) void { + descriptor.access = access.tss_access; +} diff --git a/mirai/boot/gdt/entries/user.zig b/mirai/boot/gdt/entries/user.zig new file mode 100644 index 0000000..4dea6cf --- /dev/null +++ b/mirai/boot/gdt/entries/user.zig @@ -0,0 +1,26 @@ +//! User GDT Entries + +const types = @import("../types/types.zig"); +const constants = @import("../constants/constants.zig"); + +const Entry = types.Entry; +const access = constants.access; +const flags = constants.flags; + +pub fn create_user_code() Entry { + return Entry.init( + 0, + 0xFFFFF, + access.user_code_access, + flags.user_code_flags, + ); +} + +pub fn create_user_data() Entry { + return Entry.init( + 0, + 0xFFFFF, + access.user_data_access, + flags.user_data_flags, + ); +} diff --git a/mirai/boot/gdt/gdt.zig b/mirai/boot/gdt/gdt.zig new file mode 100644 index 0000000..6adb9c2 --- /dev/null +++ b/mirai/boot/gdt/gdt.zig @@ -0,0 +1,39 @@ +//! Global Descriptor Table + +pub const constants = @import("constants/constants.zig"); +pub const types = @import("types/types.zig"); +pub const entries = @import("entries/entries.zig"); +pub const load = @import("load/load.zig"); +pub const state = @import("state.zig"); + +pub const Entry = types.Entry; +pub const TssDescriptor = types.TssDescriptor; +pub const Gdtr = types.Gdtr; +pub const Table = types.Table; + +pub const selectors = constants.selectors; + +pub fn initialize(tss_address: u64, tss_size: u20) void { + state.setup_entries(tss_address, tss_size); + + const gdtr = state.get_gdtr(); + load.lgdt(&gdtr); + + load.reload_segments(); + + load.load_tss(selectors.tss_selector); + + state.set_initialized(); +} + +pub fn is_initialized() bool { + return state.is_initialized(); +} + +pub fn get_table() *Table { + return state.get_table(); +} + +pub fn update_tss(tss_address: u64, tss_size: u20) void { + state.update_tss(tss_address, tss_size); +} diff --git a/mirai/boot/gdt/load/load.zig b/mirai/boot/gdt/load/load.zig new file mode 100644 index 0000000..dfcfe00 --- /dev/null +++ b/mirai/boot/gdt/load/load.zig @@ -0,0 +1,23 @@ +//! GDT Load Operations + +const asm_gdt = @import("../../../asm/gdt/gdt.zig"); +const constants = @import("../constants/constants.zig"); + +const selectors = constants.selectors; + +pub const Gdtr = asm_gdt.Gdtr; +pub const lgdt = asm_gdt.lgdt; +pub const sgdt = asm_gdt.sgdt; + +pub fn reload_segments() void { + asm_gdt.reload_code_segment(selectors.kernel_code_selector); + asm_gdt.reload_data_segments(selectors.kernel_data_selector); +} + +pub const reload_code_segment = asm_gdt.reload_code_segment; +pub const reload_data_segments = asm_gdt.reload_data_segments; +pub const load_tss = asm_gdt.load_tss; + +pub const get_cs = asm_gdt.get_cs; +pub const get_ds = asm_gdt.get_ds; +pub const get_ss = asm_gdt.get_ss; diff --git a/mirai/boot/gdt/state.zig b/mirai/boot/gdt/state.zig new file mode 100644 index 0000000..92219d8 --- /dev/null +++ b/mirai/boot/gdt/state.zig @@ -0,0 +1,41 @@ +//! GDT State + +const types = @import("types/types.zig"); +const entries = @import("entries/entries.zig"); + +const Table = types.Table; +const Entry = types.Entry; +const TssDescriptor = types.TssDescriptor; +const Gdtr = types.Gdtr; + +var global_gdt: Table = undefined; +var initialized: bool = false; + +pub fn get_table() *Table { + return &global_gdt; +} + +pub fn get_gdtr() Gdtr { + return global_gdt.get_gdtr(); +} + +pub fn is_initialized() bool { + return initialized; +} + +pub fn set_initialized() void { + initialized = true; +} + +pub fn setup_entries(tss_address: u64, tss_size: u20) void { + global_gdt.null = Entry.null_entry(); + global_gdt.kernel_code = entries.create_kernel_code(); + global_gdt.kernel_data = entries.create_kernel_data(); + global_gdt.user_code = entries.create_user_code(); + global_gdt.user_data = entries.create_user_data(); + global_gdt.tss = entries.create_tss_descriptor(tss_address, tss_size); +} + +pub fn update_tss(tss_address: u64, tss_size: u20) void { + global_gdt.tss = entries.create_tss_descriptor(tss_address, tss_size); +} diff --git a/mirai/boot/gdt/types/entry.zig b/mirai/boot/gdt/types/entry.zig new file mode 100644 index 0000000..c8e1798 --- /dev/null +++ b/mirai/boot/gdt/types/entry.zig @@ -0,0 +1,55 @@ +//! GDT Entry Type + +pub const Entry = packed struct { + limit_low: u16, + base_low: u16, + base_middle: u8, + access: u8, + limit_high_and_flags: u8, + base_high: u8, + + pub fn init(base: u32, limit: u20, access_byte: u8, flags_nibble: u4) Entry { + return Entry{ + .limit_low = @truncate(limit), + .base_low = @truncate(base), + .base_middle = @truncate(base >> 16), + .access = access_byte, + .limit_high_and_flags = @as(u8, flags_nibble) << 4 | @as(u8, @truncate(limit >> 16)), + .base_high = @truncate(base >> 24), + }; + } + + pub fn null_entry() Entry { + return Entry{ + .limit_low = 0, + .base_low = 0, + .base_middle = 0, + .access = 0, + .limit_high_and_flags = 0, + .base_high = 0, + }; + } + + pub fn get_base(self: Entry) u32 { + return @as(u32, self.base_high) << 24 | + @as(u32, self.base_middle) << 16 | + @as(u32, self.base_low); + } + + pub fn get_limit(self: Entry) u20 { + return @as(u20, @truncate(self.limit_high_and_flags & 0x0F)) << 16 | + @as(u20, self.limit_low); + } + + pub fn get_flags(self: Entry) u4 { + return @truncate(self.limit_high_and_flags >> 4); + } + + pub fn is_present(self: Entry) bool { + return (self.access & 0x80) != 0; + } + + pub fn get_dpl(self: Entry) u2 { + return @truncate((self.access >> 5) & 0x03); + } +}; diff --git a/mirai/boot/gdt/types/gdtr.zig b/mirai/boot/gdt/types/gdtr.zig new file mode 100644 index 0000000..ab23a75 --- /dev/null +++ b/mirai/boot/gdt/types/gdtr.zig @@ -0,0 +1,16 @@ +//! GDT Register Type + +const asm_gdt = @import("../../../asm/gdt/gdt.zig"); + +pub const Gdtr = asm_gdt.Gdtr; + +pub fn create(base_address: u64, num_entries: u16) Gdtr { + return Gdtr{ + .limit = (num_entries * 8) - 1, + .base = base_address, + }; +} + +pub fn get_entry_count(gdtr: Gdtr) u16 { + return (gdtr.limit + 1) / 8; +} diff --git a/mirai/boot/gdt/types/table.zig b/mirai/boot/gdt/types/table.zig new file mode 100644 index 0000000..5b6cc99 --- /dev/null +++ b/mirai/boot/gdt/types/table.zig @@ -0,0 +1,36 @@ +//! GDT Table Type + +const Entry = @import("entry.zig").Entry; +const TssDescriptor = @import("tss_descriptor.zig").TssDescriptor; +const Gdtr = @import("gdtr.zig").Gdtr; + +pub const Table = extern struct { + null: Entry, + kernel_code: Entry, + kernel_data: Entry, + user_code: Entry, + user_data: Entry, + tss: TssDescriptor, + + pub fn get_gdtr(self: *Table) Gdtr { + const base = @intFromPtr(self); + const size = @sizeOf(Table); + return Gdtr{ + .limit = size - 1, + .base = base, + }; + } + + pub fn get_entry(self: *Table, index: u16) ?*Entry { + const entries: [*]Entry = @ptrCast(self); + const max_entries = @sizeOf(Table) / @sizeOf(Entry); + if (index >= max_entries) { + return null; + } + return &entries[index]; + } + + pub fn get_tss_descriptor(self: *Table) *TssDescriptor { + return &self.tss; + } +}; diff --git a/mirai/boot/gdt/types/tss_descriptor.zig b/mirai/boot/gdt/types/tss_descriptor.zig new file mode 100644 index 0000000..960446c --- /dev/null +++ b/mirai/boot/gdt/types/tss_descriptor.zig @@ -0,0 +1,43 @@ +//! TSS Descriptor Type (16 bytes in Long Mode) + +const Entry = @import("entry.zig").Entry; + +pub const TssDescriptor = packed struct { + limit_low: u16, + base_low: u16, + base_middle_low: u8, + access: u8, + limit_high_and_flags: u8, + base_middle_high: u8, + base_high: u32, + reserved: u32, + + pub fn init(base: u64, limit: u20, access_byte: u8) TssDescriptor { + return TssDescriptor{ + .limit_low = @truncate(limit), + .base_low = @truncate(base), + .base_middle_low = @truncate(base >> 16), + .access = access_byte, + .limit_high_and_flags = @truncate(limit >> 16), + .base_middle_high = @truncate(base >> 24), + .base_high = @truncate(base >> 32), + .reserved = 0, + }; + } + + pub fn get_base(self: TssDescriptor) u64 { + return @as(u64, self.base_high) << 32 | + @as(u64, self.base_middle_high) << 24 | + @as(u64, self.base_middle_low) << 16 | + @as(u64, self.base_low); + } + + pub fn get_limit(self: TssDescriptor) u20 { + return @as(u20, @truncate(self.limit_high_and_flags & 0x0F)) << 16 | + @as(u20, self.limit_low); + } + + pub fn as_entries(self: *TssDescriptor) *[2]Entry { + return @ptrCast(self); + } +}; diff --git a/mirai/boot/gdt/types/types.zig b/mirai/boot/gdt/types/types.zig new file mode 100644 index 0000000..b4e583b --- /dev/null +++ b/mirai/boot/gdt/types/types.zig @@ -0,0 +1,11 @@ +//! GDT Types + +pub const entry = @import("entry.zig"); +pub const tss_descriptor = @import("tss_descriptor.zig"); +pub const gdtr = @import("gdtr.zig"); +pub const table = @import("table.zig"); + +pub const Entry = entry.Entry; +pub const TssDescriptor = tss_descriptor.TssDescriptor; +pub const Gdtr = gdtr.Gdtr; +pub const Table = table.Table; diff --git a/mirai/boot/sequence/constants/constants.zig b/mirai/boot/sequence/constants/constants.zig new file mode 100644 index 0000000..dc19129 --- /dev/null +++ b/mirai/boot/sequence/constants/constants.zig @@ -0,0 +1,7 @@ +//! Boot Sequence Constants + +pub const phases = @import("phases.zig"); + +pub const Phase = phases.Phase; +pub const phase_names = phases.phase_names; +pub const get_phase_name = phases.get_phase_name; diff --git a/mirai/boot/sequence/constants/phases.zig b/mirai/boot/sequence/constants/phases.zig new file mode 100644 index 0000000..cce1129 --- /dev/null +++ b/mirai/boot/sequence/constants/phases.zig @@ -0,0 +1,33 @@ +//! Boot Phase Constants + +pub const Phase = enum(u8) { + cpu = 0, + memory = 1, + interrupts = 2, + multicore = 3, + world = 4, + drivers = 5, + filesystem = 6, + pulse = 7, + complete = 8, +}; + +pub const phase_names = [_][]const u8{ + "CPU", + "Memory", + "Interrupts", + "Multicore", + "World", + "Drivers", + "Filesystem", + "Pulse", + "Complete", +}; + +pub fn get_phase_name(phase: Phase) []const u8 { + const index = @intFromEnum(phase); + if (index < phase_names.len) { + return phase_names[index]; + } + return "Unknown"; +} diff --git a/mirai/boot/sequence/message/message.zig b/mirai/boot/sequence/message/message.zig new file mode 100644 index 0000000..a9c29c5 --- /dev/null +++ b/mirai/boot/sequence/message/message.zig @@ -0,0 +1,12 @@ +//! Boot Messages + +pub const print = @import("print.zig"); + +pub const print_phase_start = print.print_phase_start; +pub const print_phase_complete = print.print_phase_complete; +pub const print_phase_error = print.print_phase_error; +pub const print_status = print.print_status; +pub const print_status_value = print.print_status_value; +pub const print_status_hex = print.print_status_hex; +pub const print_banner = print.print_banner; +pub const print_boot_complete = print.print_boot_complete; diff --git a/mirai/boot/sequence/message/print.zig b/mirai/boot/sequence/message/print.zig new file mode 100644 index 0000000..9071557 --- /dev/null +++ b/mirai/boot/sequence/message/print.zig @@ -0,0 +1,15 @@ +//! Boot Messages + +const serial = @import("../../../drivers/serial/serial.zig"); + +pub fn log(comptime fmt: []const u8, args: anytype) void { + serial.printf(fmt, args); +} + +pub fn print_banner() void { + serial.printf("\n", .{}); + serial.printf("+-----------------------+\n", .{}); + serial.printf("| A K I B A |\n", .{}); + serial.printf("+-----------------------+\n", .{}); + serial.printf("\n", .{}); +} diff --git a/mirai/boot/sequence/phases/cpu.zig b/mirai/boot/sequence/phases/cpu.zig new file mode 100644 index 0000000..addf1fe --- /dev/null +++ b/mirai/boot/sequence/phases/cpu.zig @@ -0,0 +1,17 @@ +//! CPU Phase + +const gdt = @import("../../gdt/gdt.zig"); +const tss = @import("../../tss/tss.zig"); +const tss_constants = @import("../../tss/constants/constants.zig"); +const serial = @import("../../../drivers/serial/serial.zig"); + +pub fn execute() bool { + serial.printf("Setting up Task State Segment for CPU exceptions\n", .{}); + tss.initialize_boot(); + + serial.printf("Setting up Global Descriptor Table with kernel and user segments\n", .{}); + const tss_address = tss.get_boot_tss_address(); + gdt.initialize(tss_address, tss_constants.tss_size); + + return true; +} diff --git a/mirai/boot/sequence/phases/memory.zig b/mirai/boot/sequence/phases/memory.zig new file mode 100644 index 0000000..3cd4152 --- /dev/null +++ b/mirai/boot/sequence/phases/memory.zig @@ -0,0 +1,60 @@ +//! Memory Phase + +const pmm = @import("../../../pmm/pmm.zig"); +const kagami = @import("../../../kagami/kagami.zig"); +const serial = @import("../../../drivers/serial/serial.zig"); +const types = @import("../types/types.zig"); + +const BootInfo = types.BootInfo; + +pub fn execute(boot_info: *const BootInfo) bool { + serial.printf("Detecting physical memory from Hikari bootloader\n", .{}); + + const bitmap_location = find_bitmap_location(boot_info); + if (bitmap_location == 0) { + serial.printf(" Could not find suitable location for page bitmap\n", .{}); + return false; + } + + pmm.initialize(boot_info.memory_map, boot_info.memory_map_count, bitmap_location); + + const stats = pmm.get_statistics(); + const total_mb = (stats.total_pages * 4096) / (1024 * 1024); + const free_mb = (stats.free_pages * 4096) / (1024 * 1024); + + serial.printf(" Found %d pages (%d MB total)\n", .{ stats.total_pages, total_mb }); + serial.printf(" Available: %d pages (%d MB)\n", .{ stats.free_pages, free_mb }); + + serial.printf("Setting up Kagami page table abstraction\n", .{}); + kagami.initialize(boot_info.pml4_physical); + serial.printf(" Using PML4 at physical address %x\n", .{boot_info.pml4_physical}); + + return true; +} + +fn find_bitmap_location(boot_info: *const BootInfo) u64 { + const bitmap_size = pmm.constants.bitmap_size_bytes; + const required_pages = (bitmap_size + 4095) / 4096; + + var index: u64 = 0; + while (index < boot_info.memory_map_count) : (index += 1) { + const region = boot_info.memory_map[index]; + + if (!region.is_usable()) continue; + + if (region.base_address < 0x100000) continue; + + if (region.base_address >= boot_info.kernel_physical_base and + region.base_address < boot_info.kernel_physical_end) + { + continue; + } + + const region_pages = region.page_count(); + if (region_pages >= required_pages) { + return region.base_address; + } + } + + return 0; +} diff --git a/mirai/boot/sequence/phases/phases.zig b/mirai/boot/sequence/phases/phases.zig new file mode 100644 index 0000000..2a09ed3 --- /dev/null +++ b/mirai/boot/sequence/phases/phases.zig @@ -0,0 +1,7 @@ +//! Boot Phases + +pub const cpu = @import("cpu.zig"); +pub const memory = @import("memory.zig"); + +pub const execute_cpu = cpu.execute; +pub const execute_memory = memory.execute; diff --git a/mirai/boot/sequence/sequence.zig b/mirai/boot/sequence/sequence.zig new file mode 100644 index 0000000..2500455 --- /dev/null +++ b/mirai/boot/sequence/sequence.zig @@ -0,0 +1,64 @@ +//! Boot Sequence + +const asm_cpu = @import("../../asm/cpu/cpu.zig"); +const serial = @import("../../drivers/serial/serial.zig"); + +pub const constants = @import("constants/constants.zig"); +pub const types = @import("types/types.zig"); +pub const phases = @import("phases/phases.zig"); +pub const message = @import("message/message.zig"); +pub const state = @import("state.zig"); + +pub const Phase = constants.Phase; +pub const BootInfo = types.BootInfo; + +pub fn execute(boot_info: *const BootInfo) bool { + state.set_boot_info(boot_info); + + if (!serial.initialize_default()) { + return false; + } + + message.print_banner(); + + serial.printf("Starting Akiba boot sequence\n", .{}); + serial.printf("Powered by the Mirai kernel\n\n", .{}); + + state.set_current_phase(Phase.cpu); + if (!phases.execute_cpu()) { + serial.printf("\nCPU initialization failed, cannot continue\n", .{}); + return false; + } + state.advance_phase(); + + serial.printf("\n", .{}); + + state.set_current_phase(Phase.memory); + if (!phases.execute_memory(boot_info)) { + serial.printf("\nMemory initialization failed, cannot continue\n", .{}); + return false; + } + state.advance_phase(); + + serial.printf("\nBoot sequence complete, Akiba is ready\n", .{}); + state.set_current_phase(Phase.complete); + + return true; +} + +pub fn halt_on_failure() noreturn { + serial.printf("\nSystem halted due to unrecoverable error\n", .{}); + asm_cpu.halt_loop(); +} + +pub fn get_current_phase() Phase { + return state.get_current_phase(); +} + +pub fn get_boot_info() ?*const BootInfo { + return state.get_boot_info(); +} + +pub fn is_complete() bool { + return state.is_complete(); +} diff --git a/mirai/boot/sequence/state.zig b/mirai/boot/sequence/state.zig new file mode 100644 index 0000000..5ea7c8a --- /dev/null +++ b/mirai/boot/sequence/state.zig @@ -0,0 +1,58 @@ +//! Boot Sequence State + +const constants = @import("constants/constants.zig"); +const types = @import("types/types.zig"); + +const Phase = constants.Phase; +const BootInfo = types.BootInfo; + +var current_phase: Phase = Phase.cpu; +var boot_info_ptr: ?*const BootInfo = null; +var boot_failed: bool = false; +var failure_phase: Phase = Phase.cpu; +var failure_message: []const u8 = ""; + +pub fn get_current_phase() Phase { + return current_phase; +} + +pub fn set_current_phase(phase: Phase) void { + current_phase = phase; +} + +pub fn advance_phase() void { + const next = @intFromEnum(current_phase) + 1; + if (next <= @intFromEnum(Phase.complete)) { + current_phase = @enumFromInt(next); + } +} + +pub fn set_boot_info(info: *const BootInfo) void { + boot_info_ptr = info; +} + +pub fn get_boot_info() ?*const BootInfo { + return boot_info_ptr; +} + +pub fn set_failure(phase: Phase, message: []const u8) void { + boot_failed = true; + failure_phase = phase; + failure_message = message; +} + +pub fn has_failed() bool { + return boot_failed; +} + +pub fn get_failure_phase() Phase { + return failure_phase; +} + +pub fn get_failure_message() []const u8 { + return failure_message; +} + +pub fn is_complete() bool { + return current_phase == Phase.complete; +} diff --git a/mirai/boot/sequence/types/boot_info.zig b/mirai/boot/sequence/types/boot_info.zig new file mode 100644 index 0000000..8d0c802 --- /dev/null +++ b/mirai/boot/sequence/types/boot_info.zig @@ -0,0 +1,44 @@ +//! Boot Information Type + +const pmm_types = @import("../../../pmm/types/types.zig"); +const MemoryRegion = pmm_types.MemoryRegion; + +pub const BootInfo = struct { + memory_map: [*]const MemoryRegion, + memory_map_count: u64, + framebuffer_address: u64, + framebuffer_width: u32, + framebuffer_height: u32, + framebuffer_pitch: u32, + framebuffer_bpp: u8, + kernel_physical_base: u64, + kernel_physical_end: u64, + kernel_virtual_base: u64, + pml4_physical: u64, + rsdp_address: u64, + boot_stack_top: u64, + + pub fn total_memory(self: BootInfo) u64 { + var total: u64 = 0; + var index: u64 = 0; + while (index < self.memory_map_count) : (index += 1) { + total += self.memory_map[index].length; + } + return total; + } + + pub fn usable_memory(self: BootInfo) u64 { + var usable: u64 = 0; + var index: u64 = 0; + while (index < self.memory_map_count) : (index += 1) { + if (self.memory_map[index].is_usable()) { + usable += self.memory_map[index].length; + } + } + return usable; + } + + pub fn kernel_size(self: BootInfo) u64 { + return self.kernel_physical_end - self.kernel_physical_base; + } +}; diff --git a/mirai/boot/sequence/types/types.zig b/mirai/boot/sequence/types/types.zig new file mode 100644 index 0000000..1883cb8 --- /dev/null +++ b/mirai/boot/sequence/types/types.zig @@ -0,0 +1,5 @@ +//! Boot Sequence Types + +pub const boot_info = @import("boot_info.zig"); + +pub const BootInfo = boot_info.BootInfo; diff --git a/mirai/boot/tss/constants/constants.zig b/mirai/boot/tss/constants/constants.zig new file mode 100644 index 0000000..2155572 --- /dev/null +++ b/mirai/boot/tss/constants/constants.zig @@ -0,0 +1,13 @@ +//! TSS Constants + +pub const limits = @import("limits.zig"); + +pub const tss_size = limits.tss_size; +pub const ist_count = limits.ist_count; +pub const ist_double_fault = limits.ist_double_fault; +pub const ist_nmi = limits.ist_nmi; +pub const ist_machine_check = limits.ist_machine_check; +pub const ist_debug = limits.ist_debug; +pub const default_stack_size = limits.default_stack_size; +pub const interrupt_stack_size = limits.interrupt_stack_size; +pub const max_cores = limits.max_cores; diff --git a/mirai/boot/tss/constants/limits.zig b/mirai/boot/tss/constants/limits.zig new file mode 100644 index 0000000..d29884b --- /dev/null +++ b/mirai/boot/tss/constants/limits.zig @@ -0,0 +1,15 @@ +//! TSS Constants + +pub const tss_size: u20 = 104; + +pub const ist_count: u8 = 7; + +pub const ist_double_fault: u8 = 1; +pub const ist_nmi: u8 = 2; +pub const ist_machine_check: u8 = 3; +pub const ist_debug: u8 = 4; + +pub const default_stack_size: u64 = 16 * 1024; +pub const interrupt_stack_size: u64 = 8 * 1024; + +pub const max_cores: u16 = 256; diff --git a/mirai/boot/tss/init/init.zig b/mirai/boot/tss/init/init.zig new file mode 100644 index 0000000..4080560 --- /dev/null +++ b/mirai/boot/tss/init/init.zig @@ -0,0 +1,6 @@ +//! TSS Initialization + +pub const setup = @import("setup.zig"); + +pub const setup_core_tss = setup.setup_core_tss; +pub const setup_minimal_tss = setup.setup_minimal_tss; diff --git a/mirai/boot/tss/init/setup.zig b/mirai/boot/tss/init/setup.zig new file mode 100644 index 0000000..95dbb53 --- /dev/null +++ b/mirai/boot/tss/init/setup.zig @@ -0,0 +1,32 @@ +//! TSS Setup + +const types = @import("../types/types.zig"); +const constants = @import("../constants/constants.zig"); +const stacks = @import("../stacks/stacks.zig"); +const common = @import("../../../../common/common.zig"); + +const CoreTss = types.CoreTss; +const Tss = types.Tss; +const AllocationError = common.errors.memory.AllocationError; + +pub fn setup_core_tss(core_tss: *CoreTss) AllocationError!void { + const kernel_stack = try stacks.allocate_kernel_stack(); + core_tss.set_kernel_stack(kernel_stack.base, constants.default_stack_size); + + const ist1_stack = try stacks.allocate_ist_stack(); + core_tss.set_ist_stack(constants.ist_double_fault, ist1_stack.base, constants.interrupt_stack_size); + + const ist2_stack = try stacks.allocate_ist_stack(); + core_tss.set_ist_stack(constants.ist_nmi, ist2_stack.base, constants.interrupt_stack_size); + + const ist3_stack = try stacks.allocate_ist_stack(); + core_tss.set_ist_stack(constants.ist_machine_check, ist3_stack.base, constants.interrupt_stack_size); + + const ist4_stack = try stacks.allocate_ist_stack(); + core_tss.set_ist_stack(constants.ist_debug, ist4_stack.base, constants.interrupt_stack_size); +} + +pub fn setup_minimal_tss(tss: *Tss, kernel_stack_top: u64) void { + tss.clear(); + tss.set_rsp0(kernel_stack_top); +} diff --git a/mirai/boot/tss/stacks/allocate.zig b/mirai/boot/tss/stacks/allocate.zig new file mode 100644 index 0000000..11f8598 --- /dev/null +++ b/mirai/boot/tss/stacks/allocate.zig @@ -0,0 +1,38 @@ +//! TSS Stack Allocation + +const pmm = @import("../../../pmm/pmm.zig"); +const common = @import("../../../../common/common.zig"); +const constants = @import("../constants/constants.zig"); + +const memory_layout = common.constants.memory.layout; +const AllocationError = common.errors.memory.AllocationError; + +pub fn allocate_kernel_stack() AllocationError!struct { base: u64, top: u64 } { + const page_count = constants.default_stack_size / 4096; + const physical_base = try pmm.allocate_contiguous(page_count); + const virtual_base = physical_base + memory_layout.physmap_base; + const stack_top = virtual_base + constants.default_stack_size; + + return .{ + .base = virtual_base, + .top = stack_top, + }; +} + +pub fn allocate_ist_stack() AllocationError!struct { base: u64, top: u64 } { + const page_count = constants.interrupt_stack_size / 4096; + const physical_base = try pmm.allocate_contiguous(page_count); + const virtual_base = physical_base + memory_layout.physmap_base; + const stack_top = virtual_base + constants.interrupt_stack_size; + + return .{ + .base = virtual_base, + .top = stack_top, + }; +} + +pub fn free_stack(base: u64, size: u64) void { + const physical_base = base - memory_layout.physmap_base; + const page_count = size / 4096; + pmm.free_range(physical_base, page_count); +} diff --git a/mirai/boot/tss/stacks/stacks.zig b/mirai/boot/tss/stacks/stacks.zig new file mode 100644 index 0000000..06682f1 --- /dev/null +++ b/mirai/boot/tss/stacks/stacks.zig @@ -0,0 +1,7 @@ +//! TSS Stack Operations + +pub const allocate = @import("allocate.zig"); + +pub const allocate_kernel_stack = allocate.allocate_kernel_stack; +pub const allocate_ist_stack = allocate.allocate_ist_stack; +pub const free_stack = allocate.free_stack; diff --git a/mirai/boot/tss/state.zig b/mirai/boot/tss/state.zig new file mode 100644 index 0000000..55b2bee --- /dev/null +++ b/mirai/boot/tss/state.zig @@ -0,0 +1,51 @@ +//! TSS State + +const types = @import("types/types.zig"); +const constants = @import("constants/constants.zig"); + +const CoreTss = types.CoreTss; +const Tss = types.Tss; + +var boot_tss: Tss = Tss{}; + +var core_tss_array: [constants.max_cores]CoreTss = undefined; +var core_count: u16 = 0; +var initialized: bool = false; + +pub fn get_boot_tss() *Tss { + return &boot_tss; +} + +pub fn get_boot_tss_address() u64 { + return @intFromPtr(&boot_tss); +} + +pub fn get_core_tss(core_id: u16) ?*CoreTss { + if (core_id >= core_count) { + return null; + } + return &core_tss_array[core_id]; +} + +pub fn register_core(core_id: u16) ?*CoreTss { + if (core_id >= constants.max_cores) { + return null; + } + if (core_id >= core_count) { + core_count = core_id + 1; + } + core_tss_array[core_id] = CoreTss.init(core_id); + return &core_tss_array[core_id]; +} + +pub fn get_core_count() u16 { + return core_count; +} + +pub fn is_initialized() bool { + return initialized; +} + +pub fn set_initialized() void { + initialized = true; +} diff --git a/mirai/boot/tss/tss.zig b/mirai/boot/tss/tss.zig new file mode 100644 index 0000000..923684d --- /dev/null +++ b/mirai/boot/tss/tss.zig @@ -0,0 +1,60 @@ +//! Task State Segment + +const gdt = @import("../gdt/gdt.zig"); + +pub const constants = @import("constants/constants.zig"); +pub const types = @import("types/types.zig"); +pub const stacks = @import("stacks/stacks.zig"); +pub const init = @import("init/init.zig"); +pub const state = @import("state.zig"); + +pub const Tss = types.Tss; +pub const CoreTss = types.CoreTss; + +pub fn initialize_boot() void { + const tss = state.get_boot_tss(); + tss.clear(); + state.set_initialized(); +} + +pub fn initialize_core(core_id: u16, kernel_stack_top: u64) !*CoreTss { + const core_tss = state.register_core(core_id) orelse return error.TooManyCores; + + core_tss.tss.clear(); + core_tss.tss.set_rsp0(kernel_stack_top); + + try init.setup_core_tss(core_tss); + + return core_tss; +} + +pub fn get_boot_tss() *Tss { + return state.get_boot_tss(); +} + +pub fn get_boot_tss_address() u64 { + return state.get_boot_tss_address(); +} + +pub fn get_core_tss(core_id: u16) ?*CoreTss { + return state.get_core_tss(core_id); +} + +pub fn get_current_rsp0(core_id: u16) u64 { + if (state.get_core_tss(core_id)) |core_tss| { + return core_tss.tss.rsp0; + } + return state.get_boot_tss().rsp0; +} + +pub fn set_current_rsp0(core_id: u16, stack_top: u64) void { + if (state.get_core_tss(core_id)) |core_tss| { + core_tss.tss.set_rsp0(stack_top); + } else { + state.get_boot_tss().set_rsp0(stack_top); + } +} + +pub fn is_initialized() bool { + return state.is_initialized(); +} diff --git a/mirai/boot/tss/types/core_tss.zig b/mirai/boot/tss/types/core_tss.zig new file mode 100644 index 0000000..9a63109 --- /dev/null +++ b/mirai/boot/tss/types/core_tss.zig @@ -0,0 +1,53 @@ +//! Per-Core TSS + +const Tss = @import("tss.zig").Tss; +const constants = @import("../constants/constants.zig"); + +pub const CoreTss = struct { + tss: Tss, + core_id: u16, + kernel_stack_base: u64, + kernel_stack_top: u64, + ist_stacks: [7]IstStack, + + pub const IstStack = struct { + base: u64, + top: u64, + size: u64, + }; + + pub fn init(core_id: u16) CoreTss { + return CoreTss{ + .tss = Tss{}, + .core_id = core_id, + .kernel_stack_base = 0, + .kernel_stack_top = 0, + .ist_stacks = [_]IstStack{.{ .base = 0, .top = 0, .size = 0 }} ** 7, + }; + } + + pub fn set_kernel_stack(self: *CoreTss, base: u64, size: u64) void { + self.kernel_stack_base = base; + self.kernel_stack_top = base + size; + self.tss.set_rsp0(self.kernel_stack_top); + } + + pub fn set_ist_stack(self: *CoreTss, index: u8, base: u64, size: u64) void { + if (index < 1 or index > 7) return; + const ist_index = index - 1; + self.ist_stacks[ist_index] = .{ + .base = base, + .top = base + size, + .size = size, + }; + self.tss.set_ist(index, base + size); + } + + pub fn get_tss(self: *CoreTss) *Tss { + return &self.tss; + } + + pub fn get_tss_address(self: *const CoreTss) u64 { + return @intFromPtr(&self.tss); + } +}; diff --git a/mirai/boot/tss/types/tss.zig b/mirai/boot/tss/types/tss.zig new file mode 100644 index 0000000..7c4896c --- /dev/null +++ b/mirai/boot/tss/types/tss.zig @@ -0,0 +1,71 @@ +//! TSS Structure Type + +pub const Tss = extern struct { + reserved_0: u32 = 0, + rsp0: u64 = 0, + rsp1: u64 = 0, + rsp2: u64 = 0, + reserved_1: u64 = 0, + ist1: u64 = 0, + ist2: u64 = 0, + ist3: u64 = 0, + ist4: u64 = 0, + ist5: u64 = 0, + ist6: u64 = 0, + ist7: u64 = 0, + reserved_2: u64 = 0, + reserved_3: u16 = 0, + iopb_offset: u16 = @sizeOf(Tss), + + pub fn set_rsp0(self: *Tss, stack_top: u64) void { + self.rsp0 = stack_top; + } + + pub fn set_rsp1(self: *Tss, stack_top: u64) void { + self.rsp1 = stack_top; + } + + pub fn set_rsp2(self: *Tss, stack_top: u64) void { + self.rsp2 = stack_top; + } + + pub fn set_ist(self: *Tss, index: u8, stack_top: u64) void { + switch (index) { + 1 => self.ist1 = stack_top, + 2 => self.ist2 = stack_top, + 3 => self.ist3 = stack_top, + 4 => self.ist4 = stack_top, + 5 => self.ist5 = stack_top, + 6 => self.ist6 = stack_top, + 7 => self.ist7 = stack_top, + else => {}, + } + } + + pub fn get_ist(self: *const Tss, index: u8) u64 { + return switch (index) { + 1 => self.ist1, + 2 => self.ist2, + 3 => self.ist3, + 4 => self.ist4, + 5 => self.ist5, + 6 => self.ist6, + 7 => self.ist7, + else => 0, + }; + } + + pub fn get_address(self: *const Tss) u64 { + return @intFromPtr(self); + } + + pub fn clear(self: *Tss) void { + self.* = Tss{}; + } +}; + +comptime { + if (@sizeOf(Tss) != 104) { + @compileError("TSS size must be 104 bytes"); + } +} diff --git a/mirai/boot/tss/types/types.zig b/mirai/boot/tss/types/types.zig new file mode 100644 index 0000000..aafeb73 --- /dev/null +++ b/mirai/boot/tss/types/types.zig @@ -0,0 +1,8 @@ +//! TSS Types + +pub const tss = @import("tss.zig"); +pub const core_tss = @import("core_tss.zig"); + +pub const Tss = tss.Tss; +pub const CoreTss = core_tss.CoreTss; +pub const IstStack = core_tss.CoreTss.IstStack; diff --git a/mirai/drivers/serial/serial.zig b/mirai/drivers/serial/serial.zig index 8f5d191..7fd374e 100644 --- a/mirai/drivers/serial/serial.zig +++ b/mirai/drivers/serial/serial.zig @@ -7,7 +7,4 @@ pub const initialize = init.initialize; pub const initialize_default = init.initialize_default; pub const set_port = write.set_port; -pub const print = write.print; -pub const print_character = write.print_character; -pub const print_hex = write.print_hex; -pub const print_decimal = write.print_decimal; +pub const printf = write.printf; diff --git a/mirai/drivers/serial/write.zig b/mirai/drivers/serial/write.zig index 447ac17..0921d40 100644 --- a/mirai/drivers/serial/write.zig +++ b/mirai/drivers/serial/write.zig @@ -13,68 +13,101 @@ pub fn set_port(port: u16) void { current_port = port; } -pub fn is_transmit_empty(port: u16) bool { +fn is_transmit_empty(port: u16) bool { return (asm_io.read_byte(port + registers.line_status_register) & registers.line_status_transmit_empty) != 0; } -pub fn write_character(port: u16, character: u8) void { +fn write_char(port: u16, char: u8) void { while (!is_transmit_empty(port)) { asm_io.io_wait(); } - asm_io.write_byte(port + registers.data_register, character); + asm_io.write_byte(port + registers.data_register, char); } -pub fn write_string(port: u16, string: []const u8) void { - for (string) |character| { - if (character == '\n') { - write_character(port, '\r'); +pub fn printf(comptime fmt: []const u8, args: anytype) void { + const ArgsType = @TypeOf(args); + const fields = @typeInfo(ArgsType).@"struct".fields; + + comptime var i: usize = 0; + comptime var arg_index: usize = 0; + + inline while (i < fmt.len) { + if (fmt[i] == '%' and i + 1 < fmt.len) { + switch (fmt[i + 1]) { + 's' => { + const str = @field(args, fields[arg_index].name); + for (str) |c| { + if (c == '\n') write_char(current_port, '\r'); + write_char(current_port, c); + } + arg_index += 1; + i += 2; + }, + 'd' => { + const val = @field(args, fields[arg_index].name); + print_decimal_value(@intCast(val)); + arg_index += 1; + i += 2; + }, + 'x' => { + const val = @field(args, fields[arg_index].name); + print_hex_value(@intCast(val)); + arg_index += 1; + i += 2; + }, + '%' => { + write_char(current_port, '%'); + i += 2; + }, + else => { + write_char(current_port, fmt[i]); + i += 1; + }, + } + } else { + if (fmt[i] == '\n') write_char(current_port, '\r'); + write_char(current_port, fmt[i]); + i += 1; } - write_character(port, character); } } -pub fn print(string: []const u8) void { - write_string(current_port, string); -} - -pub fn print_character(character: u8) void { - if (character == '\n') { - write_character(current_port, '\r'); - } - write_character(current_port, character); -} - -pub fn print_hex(value: u64) void { - const hex_chars = "0123456789ABCDEF"; - var buffer: [18]u8 = undefined; - buffer[0] = '0'; - buffer[1] = 'x'; - - var temp_value = value; - var index: usize = 17; - while (index > 1) : (index -= 1) { - buffer[index] = hex_chars[@truncate(temp_value & 0xF)]; - temp_value >>= 4; - } - - print(&buffer); -} - -pub fn print_decimal(value: u64) void { +fn print_decimal_value(value: u64) void { if (value == 0) { - print_character('0'); + write_char(current_port, '0'); return; } var buffer: [20]u8 = undefined; - var temp_value = value; - var index: usize = 20; + var temp = value; + var len: usize = 0; - while (temp_value > 0) { - index -= 1; - buffer[index] = @truncate((temp_value % 10) + '0'); - temp_value /= 10; + while (temp > 0) { + buffer[len] = @truncate((temp % 10) + '0'); + temp /= 10; + len += 1; } - print(buffer[index..]); + while (len > 0) { + len -= 1; + write_char(current_port, buffer[len]); + } +} + +fn print_hex_value(value: u64) void { + const hex = "0123456789abcdef"; + write_char(current_port, '0'); + write_char(current_port, 'x'); + + var started = false; + var shift: u6 = 60; + while (true) { + const nibble: u4 = @truncate((value >> shift) & 0xF); + if (nibble != 0 or started or shift == 0) { + write_char(current_port, hex[nibble]); + started = true; + } + if (shift == 0) break; + shift -= 4; + } } diff --git a/mirai/kagami/types/kagami.zig b/mirai/kagami/types/kagami.zig index f89863f..8979e5d 100644 --- a/mirai/kagami/types/kagami.zig +++ b/mirai/kagami/types/kagami.zig @@ -1,5 +1,7 @@ //! Kagami Structure +const state = @import("../state.zig"); + pub const Kagami = struct { pml4_physical: u64, reference_count: u32, @@ -9,7 +11,7 @@ pub const Kagami = struct { lock: bool, pub fn is_kernel(self: *const Kagami) bool { - const kernel_kagami = @import("../state.zig").get_kernel_kagami(); + const kernel_kagami = state.get_kernel_kagami(); return self.pml4_physical == kernel_kagami.pml4_physical; } |
