aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-02-25 06:09:23 +0530
committerBobby <[email protected]>2026-02-25 06:09:23 +0530
commitbd462bccea2a637486f863a6342b9870b35c69aa (patch)
treec68dc848542f53b701c553bd0124874948598c8d
parent313ab7ea7d5a5d902005d8543ab6b323ed948048 (diff)
downloadakiba-bd462bccea2a637486f863a6342b9870b35c69aa.tar.xz
akiba-bd462bccea2a637486f863a6342b9870b35c69aa.zip
feat: Add common constants, errors, and serial driver functionality
-rw-r--r--build.zig.zon11
-rw-r--r--common/common.zig4
-rw-r--r--common/constants/constants.zig5
-rw-r--r--common/constants/memory/flags.zig25
-rw-r--r--common/constants/memory/layout.zig17
-rw-r--r--common/constants/memory/memory.zig5
-rw-r--r--common/constants/memory/sizes.zig21
-rw-r--r--common/constants/paging/flags.zig27
-rw-r--r--common/constants/paging/indices.zig36
-rw-r--r--common/constants/paging/paging.zig4
-rw-r--r--common/constants/serial/ports.zig16
-rw-r--r--common/constants/serial/registers.zig30
-rw-r--r--common/constants/serial/serial.zig4
-rw-r--r--common/errors/errors.zig3
-rw-r--r--common/errors/memory/allocation.zig9
-rw-r--r--common/errors/memory/mapping.zig11
-rw-r--r--common/errors/memory/memory.zig7
-rw-r--r--mirai/asm/asm.zig4
-rw-r--r--mirai/asm/cpu/control.zig68
-rw-r--r--mirai/asm/cpu/cpu.zig22
-rw-r--r--mirai/asm/cpu/halt.zig36
-rw-r--r--mirai/asm/io/io.zig11
-rw-r--r--mirai/asm/io/port.zig56
-rw-r--r--mirai/drivers/drivers.zig3
-rw-r--r--mirai/drivers/serial/init.zig38
-rw-r--r--mirai/drivers/serial/serial.zig13
-rw-r--r--mirai/drivers/serial/write.zig80
-rw-r--r--mirai/kernel/boot.zig2
-rw-r--r--mirai/kernel/mirai.zig2
29 files changed, 558 insertions, 12 deletions
diff --git a/build.zig.zon b/build.zig.zon
index b309a37..2f7209d 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -3,14 +3,5 @@
.version = "1.0.0",
.fingerprint = 0xa42f71a68564f824,
.minimum_zig_version = "0.15.2",
- .paths = .{
- "build.zig",
- "build.zig.zon",
- "hikari",
- "mirai",
- "linker",
- "toolchain",
- "scripts",
- "resources",
- },
+ .paths = .{ "build.zig", "build.zig.zon", "hikari", "mirai", "linker", "toolchain", "scripts", "resources", "common" },
}
diff --git a/common/common.zig b/common/common.zig
new file mode 100644
index 0000000..fd9945e
--- /dev/null
+++ b/common/common.zig
@@ -0,0 +1,4 @@
+//! Common Definitions
+
+pub const constants = @import("constants/constants.zig");
+pub const errors = @import("errors/errors.zig");
diff --git a/common/constants/constants.zig b/common/constants/constants.zig
new file mode 100644
index 0000000..b4344fb
--- /dev/null
+++ b/common/constants/constants.zig
@@ -0,0 +1,5 @@
+//! Common Constants
+
+pub const memory = @import("memory/memory.zig");
+pub const paging = @import("paging/paging.zig");
+pub const serial = @import("serial/serial.zig");
diff --git a/common/constants/memory/flags.zig b/common/constants/memory/flags.zig
new file mode 100644
index 0000000..a057cf9
--- /dev/null
+++ b/common/constants/memory/flags.zig
@@ -0,0 +1,25 @@
+//! Memory Flag Constants
+
+pub const protection_read: u8 = 0x01;
+pub const protection_write: u8 = 0x02;
+pub const protection_execute: u8 = 0x04;
+pub const protection_user: u8 = 0x08;
+
+pub const protection_kernel_read_only: u8 = protection_read;
+pub const protection_kernel_read_write: u8 = protection_read | protection_write;
+pub const protection_kernel_execute: u8 = protection_read | protection_execute;
+pub const protection_user_read_only: u8 = protection_read | protection_user;
+pub const protection_user_read_write: u8 = protection_read | protection_write | protection_user;
+pub const protection_user_execute: u8 = protection_read | protection_execute | protection_user;
+
+pub const allocation_wired: u32 = 0x00000001;
+pub const allocation_contiguous: u32 = 0x00000002;
+pub const allocation_zero_fill: u32 = 0x00000004;
+pub const allocation_no_cache: u32 = 0x00000008;
+pub const allocation_write_combine: u32 = 0x00000010;
+
+pub const region_anonymous: u32 = 0x00000001;
+pub const region_shared: u32 = 0x00000002;
+pub const region_copy_on_write: u32 = 0x00000004;
+pub const region_stack: u32 = 0x00000008;
+pub const region_guard: u32 = 0x00000010;
diff --git a/common/constants/memory/layout.zig b/common/constants/memory/layout.zig
new file mode 100644
index 0000000..0e3780f
--- /dev/null
+++ b/common/constants/memory/layout.zig
@@ -0,0 +1,17 @@
+//! Memory Layout Constants
+
+pub const kernel_base: u64 = 0xFFFFFE0000000000;
+pub const kernel_text: u64 = 0xFFFFFE0001000000;
+pub const kernel_heap: u64 = 0xFFFFFE1000000000;
+pub const physmap_base: u64 = 0xFFFFFF0000000000;
+pub const mmio_base: u64 = 0xFFFFFF8000000000;
+
+pub const kernel_physical_base: u64 = 0x100000;
+
+pub const user_space_start: u64 = 0x0000000000000000;
+pub const user_space_end: u64 = 0x00007FFFFFFFFFFF;
+
+pub const kernel_stack_size: u64 = 64 * 1024;
+pub const kernel_stack_pages: u64 = kernel_stack_size / 4096;
+
+pub const physmap_max_size: u64 = 512 * 1024 * 1024 * 1024;
diff --git a/common/constants/memory/memory.zig b/common/constants/memory/memory.zig
new file mode 100644
index 0000000..9d82b78
--- /dev/null
+++ b/common/constants/memory/memory.zig
@@ -0,0 +1,5 @@
+//! Memory Constants
+
+pub const layout = @import("layout.zig");
+pub const sizes = @import("sizes.zig");
+pub const flags = @import("flags.zig");
diff --git a/common/constants/memory/sizes.zig b/common/constants/memory/sizes.zig
new file mode 100644
index 0000000..049b087
--- /dev/null
+++ b/common/constants/memory/sizes.zig
@@ -0,0 +1,21 @@
+//! Memory Size Constants
+
+pub const page_size: u64 = 4096;
+pub const page_shift: u6 = 12;
+pub const page_mask: u64 = page_size - 1;
+
+pub const large_page_size: u64 = 2 * 1024 * 1024;
+pub const large_page_shift: u6 = 21;
+pub const large_page_mask: u64 = large_page_size - 1;
+
+pub const huge_page_size: u64 = 1024 * 1024 * 1024;
+pub const huge_page_shift: u6 = 30;
+pub const huge_page_mask: u64 = huge_page_size - 1;
+
+pub const kilobyte: u64 = 1024;
+pub const megabyte: u64 = 1024 * kilobyte;
+pub const gigabyte: u64 = 1024 * megabyte;
+pub const terabyte: u64 = 1024 * gigabyte;
+
+pub const entries_per_page_table: u64 = 512;
+pub const page_table_levels: u8 = 4;
diff --git a/common/constants/paging/flags.zig b/common/constants/paging/flags.zig
new file mode 100644
index 0000000..e6acad3
--- /dev/null
+++ b/common/constants/paging/flags.zig
@@ -0,0 +1,27 @@
+//! Paging Flag Constants
+
+pub const present: u64 = 1 << 0;
+pub const writable: u64 = 1 << 1;
+pub const user_accessible: u64 = 1 << 2;
+pub const write_through: u64 = 1 << 3;
+pub const cache_disabled: u64 = 1 << 4;
+pub const accessed: u64 = 1 << 5;
+pub const dirty: u64 = 1 << 6;
+pub const huge_page: u64 = 1 << 7;
+pub const global: u64 = 1 << 8;
+pub const no_execute: u64 = 1 << 63;
+
+pub const kernel_read_only: u64 = present | global;
+pub const kernel_read_write: u64 = present | writable | global;
+pub const kernel_execute: u64 = present | global;
+pub const kernel_read_write_no_execute: u64 = present | writable | global | no_execute;
+
+pub const user_read_only: u64 = present | user_accessible;
+pub const user_read_write: u64 = present | writable | user_accessible;
+pub const user_execute: u64 = present | user_accessible;
+pub const user_read_write_no_execute: u64 = present | writable | user_accessible | no_execute;
+
+pub const table_flags: u64 = present | writable | user_accessible;
+pub const kernel_table_flags: u64 = present | writable;
+
+pub const mmio_flags: u64 = present | writable | cache_disabled | no_execute;
diff --git a/common/constants/paging/indices.zig b/common/constants/paging/indices.zig
new file mode 100644
index 0000000..9d82bfa
--- /dev/null
+++ b/common/constants/paging/indices.zig
@@ -0,0 +1,36 @@
+//! Paging Index Constants
+
+pub const pml4_shift: u6 = 39;
+pub const pdpt_shift: u6 = 30;
+pub const pd_shift: u6 = 21;
+pub const pt_shift: u6 = 12;
+
+pub const index_mask: u64 = 0x1FF;
+
+pub const pml4_index_mask: u64 = index_mask << pml4_shift;
+pub const pdpt_index_mask: u64 = index_mask << pdpt_shift;
+pub const pd_index_mask: u64 = index_mask << pd_shift;
+pub const pt_index_mask: u64 = index_mask << pt_shift;
+
+pub const address_mask: u64 = 0x000FFFFFFFFFF000;
+pub const offset_mask: u64 = 0xFFF;
+
+pub fn extract_pml4_index(virtual_address: u64) u9 {
+ return @truncate((virtual_address >> pml4_shift) & index_mask);
+}
+
+pub fn extract_pdpt_index(virtual_address: u64) u9 {
+ return @truncate((virtual_address >> pdpt_shift) & index_mask);
+}
+
+pub fn extract_pd_index(virtual_address: u64) u9 {
+ return @truncate((virtual_address >> pd_shift) & index_mask);
+}
+
+pub fn extract_pt_index(virtual_address: u64) u9 {
+ return @truncate((virtual_address >> pt_shift) & index_mask);
+}
+
+pub fn extract_offset(virtual_address: u64) u12 {
+ return @truncate(virtual_address & offset_mask);
+}
diff --git a/common/constants/paging/paging.zig b/common/constants/paging/paging.zig
new file mode 100644
index 0000000..2c98f52
--- /dev/null
+++ b/common/constants/paging/paging.zig
@@ -0,0 +1,4 @@
+//! Paging Constants
+
+pub const indices = @import("indices.zig");
+pub const flags = @import("flags.zig");
diff --git a/common/constants/serial/ports.zig b/common/constants/serial/ports.zig
new file mode 100644
index 0000000..e9c11f4
--- /dev/null
+++ b/common/constants/serial/ports.zig
@@ -0,0 +1,16 @@
+//! Serial Port Constants
+
+pub const com1: u16 = 0x3F8;
+pub const com2: u16 = 0x2F8;
+pub const com3: u16 = 0x3E8;
+pub const com4: u16 = 0x2E8;
+
+pub const default_port: u16 = com1;
+
+pub const baud_rate_115200: u16 = 1;
+pub const baud_rate_57600: u16 = 2;
+pub const baud_rate_38400: u16 = 3;
+pub const baud_rate_19200: u16 = 6;
+pub const baud_rate_9600: u16 = 12;
+
+pub const default_baud_divisor: u16 = baud_rate_115200;
diff --git a/common/constants/serial/registers.zig b/common/constants/serial/registers.zig
new file mode 100644
index 0000000..633bc45
--- /dev/null
+++ b/common/constants/serial/registers.zig
@@ -0,0 +1,30 @@
+//! Serial Register Constants
+
+pub const data_register: u16 = 0;
+pub const interrupt_enable_register: u16 = 1;
+pub const fifo_control_register: u16 = 2;
+pub const line_control_register: u16 = 3;
+pub const modem_control_register: u16 = 4;
+pub const line_status_register: u16 = 5;
+pub const modem_status_register: u16 = 6;
+pub const scratch_register: u16 = 7;
+
+pub const divisor_latch_low: u16 = 0;
+pub const divisor_latch_high: u16 = 1;
+
+pub const line_control_8_bits: u8 = 0x03;
+pub const line_control_dlab: u8 = 0x80;
+
+pub const fifo_enable: u8 = 0x01;
+pub const fifo_clear_receive: u8 = 0x02;
+pub const fifo_clear_transmit: u8 = 0x04;
+pub const fifo_trigger_14: u8 = 0xC0;
+
+pub const modem_dtr: u8 = 0x01;
+pub const modem_rts: u8 = 0x02;
+pub const modem_out1: u8 = 0x04;
+pub const modem_out2: u8 = 0x08;
+pub const modem_loopback: u8 = 0x10;
+
+pub const line_status_data_ready: u8 = 0x01;
+pub const line_status_transmit_empty: u8 = 0x20;
diff --git a/common/constants/serial/serial.zig b/common/constants/serial/serial.zig
new file mode 100644
index 0000000..883bd02
--- /dev/null
+++ b/common/constants/serial/serial.zig
@@ -0,0 +1,4 @@
+//! Serial Constants
+
+pub const ports = @import("ports.zig");
+pub const registers = @import("registers.zig");
diff --git a/common/errors/errors.zig b/common/errors/errors.zig
new file mode 100644
index 0000000..38cd106
--- /dev/null
+++ b/common/errors/errors.zig
@@ -0,0 +1,3 @@
+//! Common Errors
+
+pub const memory = @import("memory/memory.zig");
diff --git a/common/errors/memory/allocation.zig b/common/errors/memory/allocation.zig
new file mode 100644
index 0000000..2359cac
--- /dev/null
+++ b/common/errors/memory/allocation.zig
@@ -0,0 +1,9 @@
+//! Memory Allocation Errors
+
+pub const AllocationError = error{
+ OutOfMemory,
+ InvalidSize,
+ InvalidAlignment,
+ RegionExhausted,
+ ZoneExhausted,
+};
diff --git a/common/errors/memory/mapping.zig b/common/errors/memory/mapping.zig
new file mode 100644
index 0000000..3f24216
--- /dev/null
+++ b/common/errors/memory/mapping.zig
@@ -0,0 +1,11 @@
+//! Memory Mapping Errors
+
+pub const MappingError = error{
+ InvalidAddress,
+ AddressNotAligned,
+ RegionOverlap,
+ PermissionDenied,
+ PageTableAllocationFailed,
+ AlreadyMapped,
+ NotMapped,
+};
diff --git a/common/errors/memory/memory.zig b/common/errors/memory/memory.zig
new file mode 100644
index 0000000..de76bf2
--- /dev/null
+++ b/common/errors/memory/memory.zig
@@ -0,0 +1,7 @@
+//! Memory Errors
+
+pub const allocation = @import("allocation.zig");
+pub const mapping = @import("mapping.zig");
+
+pub const AllocationError = allocation.AllocationError;
+pub const MappingError = mapping.MappingError;
diff --git a/mirai/asm/asm.zig b/mirai/asm/asm.zig
new file mode 100644
index 0000000..e6d1f24
--- /dev/null
+++ b/mirai/asm/asm.zig
@@ -0,0 +1,4 @@
+//! Assembly Operations
+
+pub const cpu = @import("cpu/cpu.zig");
+pub const io = @import("io/io.zig");
diff --git a/mirai/asm/cpu/control.zig b/mirai/asm/cpu/control.zig
new file mode 100644
index 0000000..ec408c1
--- /dev/null
+++ b/mirai/asm/cpu/control.zig
@@ -0,0 +1,68 @@
+//! CPU Control Register Operations
+
+pub fn read_cr0() u64 {
+ var result: u64 = undefined;
+ asm volatile ("mov %%cr0, %[result]"
+ : [result] "=r" (result),
+ );
+ return result;
+}
+
+pub fn write_cr0(value: u64) void {
+ asm volatile ("mov %[value], %%cr0"
+ :
+ : [value] "r" (value),
+ );
+}
+
+pub fn read_cr2() u64 {
+ var result: u64 = undefined;
+ asm volatile ("mov %%cr2, %[result]"
+ : [result] "=r" (result),
+ );
+ return result;
+}
+
+pub fn read_cr3() u64 {
+ var result: u64 = undefined;
+ asm volatile ("mov %%cr3, %[result]"
+ : [result] "=r" (result),
+ );
+ return result;
+}
+
+pub fn write_cr3(value: u64) void {
+ asm volatile ("mov %[value], %%cr3"
+ :
+ : [value] "r" (value),
+ : .{ .memory = true }
+ );
+}
+
+pub fn read_cr4() u64 {
+ var result: u64 = undefined;
+ asm volatile ("mov %%cr4, %[result]"
+ : [result] "=r" (result),
+ );
+ return result;
+}
+
+pub fn write_cr4(value: u64) void {
+ asm volatile ("mov %[value], %%cr4"
+ :
+ : [value] "r" (value),
+ );
+}
+
+pub fn flush_tlb() void {
+ const cr3_value = read_cr3();
+ write_cr3(cr3_value);
+}
+
+pub fn invalidate_page(virtual_address: u64) void {
+ asm volatile ("invlpg (%[address])"
+ :
+ : [address] "r" (virtual_address),
+ : .{ .memory = true }
+ );
+}
diff --git a/mirai/asm/cpu/cpu.zig b/mirai/asm/cpu/cpu.zig
new file mode 100644
index 0000000..a2c6a78
--- /dev/null
+++ b/mirai/asm/cpu/cpu.zig
@@ -0,0 +1,22 @@
+//! CPU Operations
+
+pub const control = @import("control.zig");
+pub const halt = @import("halt.zig");
+
+pub const read_cr0 = control.read_cr0;
+pub const write_cr0 = control.write_cr0;
+pub const read_cr2 = control.read_cr2;
+pub const read_cr3 = control.read_cr3;
+pub const write_cr3 = control.write_cr3;
+pub const read_cr4 = control.read_cr4;
+pub const write_cr4 = control.write_cr4;
+pub const flush_tlb = control.flush_tlb;
+pub const invalidate_page = control.invalidate_page;
+
+pub const halt_cpu = halt.halt;
+pub const halt_loop = halt.halt_loop;
+pub const enable_interrupts = halt.enable_interrupts;
+pub const disable_interrupts = halt.disable_interrupts;
+pub const are_interrupts_enabled = halt.are_interrupts_enabled;
+pub const read_flags = halt.read_flags;
+pub const pause = halt.pause;
diff --git a/mirai/asm/cpu/halt.zig b/mirai/asm/cpu/halt.zig
new file mode 100644
index 0000000..c401bc9
--- /dev/null
+++ b/mirai/asm/cpu/halt.zig
@@ -0,0 +1,36 @@
+//! CPU Halt Operations
+
+pub fn halt() void {
+ asm volatile ("hlt");
+}
+
+pub fn halt_loop() noreturn {
+ while (true) {
+ halt();
+ }
+}
+
+pub fn enable_interrupts() void {
+ asm volatile ("sti");
+}
+
+pub fn disable_interrupts() void {
+ asm volatile ("cli");
+}
+
+pub fn are_interrupts_enabled() bool {
+ const flags = read_flags();
+ return (flags & 0x200) != 0;
+}
+
+pub fn read_flags() u64 {
+ var result: u64 = undefined;
+ asm volatile ("pushfq; pop %[result]"
+ : [result] "=r" (result),
+ );
+ return result;
+}
+
+pub fn pause() void {
+ asm volatile ("pause");
+}
diff --git a/mirai/asm/io/io.zig b/mirai/asm/io/io.zig
new file mode 100644
index 0000000..8f322f8
--- /dev/null
+++ b/mirai/asm/io/io.zig
@@ -0,0 +1,11 @@
+//! I/O Operations
+
+pub const port = @import("port.zig");
+
+pub const read_byte = port.read_byte;
+pub const write_byte = port.write_byte;
+pub const read_word = port.read_word;
+pub const write_word = port.write_word;
+pub const read_long = port.read_long;
+pub const write_long = port.write_long;
+pub const io_wait = port.io_wait;
diff --git a/mirai/asm/io/port.zig b/mirai/asm/io/port.zig
new file mode 100644
index 0000000..4c2ffbb
--- /dev/null
+++ b/mirai/asm/io/port.zig
@@ -0,0 +1,56 @@
+//! Port I/O Operations
+
+pub fn read_byte(port: u16) u8 {
+ var result: u8 = undefined;
+ asm volatile ("inb %[port], %[result]"
+ : [result] "={al}" (result),
+ : [port] "N{dx}" (port),
+ );
+ return result;
+}
+
+pub fn write_byte(port: u16, value: u8) void {
+ asm volatile ("outb %[value], %[port]"
+ :
+ : [value] "{al}" (value),
+ [port] "N{dx}" (port),
+ );
+}
+
+pub fn read_word(port: u16) u16 {
+ var result: u16 = undefined;
+ asm volatile ("inw %[port], %[result]"
+ : [result] "={ax}" (result),
+ : [port] "N{dx}" (port),
+ );
+ return result;
+}
+
+pub fn write_word(port: u16, value: u16) void {
+ asm volatile ("outw %[value], %[port]"
+ :
+ : [value] "{ax}" (value),
+ [port] "N{dx}" (port),
+ );
+}
+
+pub fn read_long(port: u16) u32 {
+ var result: u32 = undefined;
+ asm volatile ("inl %[port], %[result]"
+ : [result] "={eax}" (result),
+ : [port] "N{dx}" (port),
+ );
+ return result;
+}
+
+pub fn write_long(port: u16, value: u32) void {
+ asm volatile ("outl %[value], %[port]"
+ :
+ : [value] "{eax}" (value),
+ [port] "N{dx}" (port),
+ );
+}
+
+pub fn io_wait() void {
+ write_byte(0x80, 0);
+}
diff --git a/mirai/drivers/drivers.zig b/mirai/drivers/drivers.zig
new file mode 100644
index 0000000..b12736b
--- /dev/null
+++ b/mirai/drivers/drivers.zig
@@ -0,0 +1,3 @@
+//! Drivers
+
+pub const serial = @import("serial/serial.zig");
diff --git a/mirai/drivers/serial/init.zig b/mirai/drivers/serial/init.zig
new file mode 100644
index 0000000..28c9dd5
--- /dev/null
+++ b/mirai/drivers/serial/init.zig
@@ -0,0 +1,38 @@
+//! Serial Initialization
+
+const common = @import("../../../common/common.zig");
+const asm_io = @import("../../asm/io/io.zig");
+
+const serial_constants = common.constants.serial;
+const ports = serial_constants.ports;
+const registers = serial_constants.registers;
+
+pub fn initialize(port: u16) bool {
+ asm_io.write_byte(port + registers.interrupt_enable_register, 0x00);
+
+ asm_io.write_byte(port + registers.line_control_register, registers.line_control_dlab);
+ asm_io.write_byte(port + registers.divisor_latch_low, @truncate(ports.default_baud_divisor));
+ asm_io.write_byte(port + registers.divisor_latch_high, @truncate(ports.default_baud_divisor >> 8));
+
+ asm_io.write_byte(port + registers.line_control_register, registers.line_control_8_bits);
+
+ asm_io.write_byte(port + registers.fifo_control_register, registers.fifo_enable | registers.fifo_clear_receive | registers.fifo_clear_transmit | registers.fifo_trigger_14);
+
+ asm_io.write_byte(port + registers.modem_control_register, registers.modem_dtr | registers.modem_rts | registers.modem_out2);
+
+ asm_io.write_byte(port + registers.modem_control_register, registers.modem_dtr | registers.modem_rts | registers.modem_out1 | registers.modem_out2 | registers.modem_loopback);
+
+ asm_io.write_byte(port + registers.data_register, 0xAE);
+
+ if (asm_io.read_byte(port + registers.data_register) != 0xAE) {
+ return false;
+ }
+
+ asm_io.write_byte(port + registers.modem_control_register, registers.modem_dtr | registers.modem_rts | registers.modem_out1 | registers.modem_out2);
+
+ return true;
+}
+
+pub fn initialize_default() bool {
+ return initialize(ports.default_port);
+}
diff --git a/mirai/drivers/serial/serial.zig b/mirai/drivers/serial/serial.zig
new file mode 100644
index 0000000..8f5d191
--- /dev/null
+++ b/mirai/drivers/serial/serial.zig
@@ -0,0 +1,13 @@
+//! Serial Driver
+
+pub const init = @import("init.zig");
+pub const write = @import("write.zig");
+
+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;
diff --git a/mirai/drivers/serial/write.zig b/mirai/drivers/serial/write.zig
new file mode 100644
index 0000000..447ac17
--- /dev/null
+++ b/mirai/drivers/serial/write.zig
@@ -0,0 +1,80 @@
+//! Serial Write Operations
+
+const common = @import("../../../common/common.zig");
+const asm_io = @import("../../asm/io/io.zig");
+
+const serial_constants = common.constants.serial;
+const ports = serial_constants.ports;
+const registers = serial_constants.registers;
+
+var current_port: u16 = ports.default_port;
+
+pub fn set_port(port: u16) void {
+ current_port = port;
+}
+
+pub 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 {
+ while (!is_transmit_empty(port)) {
+ asm_io.io_wait();
+ }
+ asm_io.write_byte(port + registers.data_register, character);
+}
+
+pub fn write_string(port: u16, string: []const u8) void {
+ for (string) |character| {
+ if (character == '\n') {
+ write_character(port, '\r');
+ }
+ 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 {
+ if (value == 0) {
+ print_character('0');
+ return;
+ }
+
+ var buffer: [20]u8 = undefined;
+ var temp_value = value;
+ var index: usize = 20;
+
+ while (temp_value > 0) {
+ index -= 1;
+ buffer[index] = @truncate((temp_value % 10) + '0');
+ temp_value /= 10;
+ }
+
+ print(buffer[index..]);
+}
diff --git a/mirai/kernel/boot.zig b/mirai/kernel/boot.zig
index 8d46901..4506d11 100644
--- a/mirai/kernel/boot.zig
+++ b/mirai/kernel/boot.zig
@@ -1,4 +1,4 @@
-//! Mirai Boot Parameters
+//! Boot Parameters
//!
//! This structure matches what Hikari bootloader passes to the kernel.
diff --git a/mirai/kernel/mirai.zig b/mirai/kernel/mirai.zig
index 5d2bc66..201cedf 100644
--- a/mirai/kernel/mirai.zig
+++ b/mirai/kernel/mirai.zig
@@ -1,4 +1,4 @@
-//! Mirai - AkibaOS Kernel
+//! - AkibaOS Kernel
//!
//! The kernel receives boot parameters from Hikari bootloader
//! and initializes the system.