diff options
| author | Bobby <[email protected]> | 2026-02-20 16:01:41 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2026-02-20 16:01:41 +0530 |
| commit | c1c827540981247fd943318f503e5d814e91921d (patch) | |
| tree | 487565051922295d669ed560b04c10916db35c29 | |
| parent | eb4c4dd3c9fe7d2424298c7b53cbe6fc1c3707eb (diff) | |
| download | akiba-c1c827540981247fd943318f503e5d814e91921d.tar.xz akiba-c1c827540981247fd943318f503e5d814e91921d.zip | |
feat: Implement CMOS/RTC and CPUID operations, add PIT driver, and enhance AFS with disk info retrieval
| -rw-r--r-- | mirai/asm/cmos.zig | 56 | ||||
| -rw-r--r-- | mirai/asm/cpuid.zig | 58 | ||||
| -rw-r--r-- | mirai/boot/sequence/sequence.zig | 5 | ||||
| -rw-r--r-- | mirai/common/constants/invocations.zig | 5 | ||||
| -rw-r--r-- | mirai/common/constants/pit.zig | 20 | ||||
| -rw-r--r-- | mirai/common/constants/ports.zig | 4 | ||||
| -rw-r--r-- | mirai/common/constants/time.zig | 9 | ||||
| -rw-r--r-- | mirai/drivers/pit/pit.zig | 12 | ||||
| -rw-r--r-- | mirai/fs/afs/afs.zig | 6 | ||||
| -rw-r--r-- | mirai/fs/afs/info.zig | 49 | ||||
| -rw-r--r-- | mirai/fs/afs/types.zig | 5 | ||||
| -rw-r--r-- | mirai/kata/sensei/sensei.zig | 28 | ||||
| -rw-r--r-- | mirai/memory/pmm.zig | 12 |
13 files changed, 258 insertions, 11 deletions
diff --git a/mirai/asm/cmos.zig b/mirai/asm/cmos.zig new file mode 100644 index 0000000..ba4005b --- /dev/null +++ b/mirai/asm/cmos.zig @@ -0,0 +1,56 @@ +//! CMOS/RTC Operations + +const io = @import("io.zig"); +const ports = @import("../common/constants/ports.zig"); + +/// Read a CMOS register +pub inline fn read_register(reg: u8) u8 { + io.out_byte(ports.CMOS_ADDRESS, reg); + return io.in_byte(ports.CMOS_DATA); +} + +/// Write to a CMOS register +pub inline fn write_register(reg: u8, value: u8) void { + io.out_byte(ports.CMOS_ADDRESS, reg); + io.out_byte(ports.CMOS_DATA, value); +} + +/// Read RTC seconds (BCD) +pub inline fn read_seconds() u8 { + return read_register(0x00); +} + +/// Read RTC minutes (BCD) +pub inline fn read_minutes() u8 { + return read_register(0x02); +} + +/// Read RTC hours (BCD) +pub inline fn read_hours() u8 { + return read_register(0x04); +} + +/// Read RTC day of month (BCD) +pub inline fn read_day() u8 { + return read_register(0x07); +} + +/// Read RTC month (BCD) +pub inline fn read_month() u8 { + return read_register(0x08); +} + +/// Read RTC year (BCD, 00-99) +pub inline fn read_year() u8 { + return read_register(0x09); +} + +/// Read RTC century (BCD) +pub inline fn read_century() u8 { + return read_register(0x32); +} + +/// Convert BCD to binary +pub inline fn bcd_to_bin(bcd: u8) u8 { + return (bcd & 0x0F) + ((bcd >> 4) * 10); +} diff --git a/mirai/asm/cpuid.zig b/mirai/asm/cpuid.zig new file mode 100644 index 0000000..6367b42 --- /dev/null +++ b/mirai/asm/cpuid.zig @@ -0,0 +1,58 @@ +//! CPUID Operations + +pub const CpuidResult = struct { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, +}; + +/// Execute CPUID instruction with given leaf +pub inline fn cpuid(leaf: u32) CpuidResult { + var eax: u32 = undefined; + var ebx: u32 = undefined; + var ecx: u32 = undefined; + var edx: u32 = undefined; + + asm volatile ("cpuid" + : [eax] "={eax}" (eax), + [ebx] "={ebx}" (ebx), + [ecx] "={ecx}" (ecx), + [edx] "={edx}" (edx), + : [leaf] "{eax}" (leaf), + ); + + return CpuidResult{ + .eax = eax, + .ebx = ebx, + .ecx = ecx, + .edx = edx, + }; +} + +/// Get maximum extended CPUID leaf +pub inline fn get_max_extended() u32 { + return cpuid(0x80000000).eax; +} + +/// Check if extended brand string is supported +pub inline fn has_brand_string() bool { + return get_max_extended() >= 0x80000004; +} + +/// Get CPU brand string (48 bytes) +pub fn get_brand_string(buffer: *[48]u8) void { + var pos: usize = 0; + + inline for ([_]u32{ 0x80000002, 0x80000003, 0x80000004 }) |leaf| { + const result = cpuid(leaf); + + inline for ([_]u32{ result.eax, result.ebx, result.ecx, result.edx }) |reg| { + buffer[pos] = @truncate(reg); + buffer[pos + 1] = @truncate(reg >> 8); + buffer[pos + 2] = @truncate(reg >> 16); + buffer[pos + 3] = @truncate(reg >> 24); + pos += 4; + } + } +} diff --git a/mirai/boot/sequence/sequence.zig b/mirai/boot/sequence/sequence.zig index 1f735d5..3bf6128 100644 --- a/mirai/boot/sequence/sequence.zig +++ b/mirai/boot/sequence/sequence.zig @@ -18,6 +18,7 @@ const keyboard = @import("../../drivers/keyboard/keyboard.zig"); const message = @import("message.zig"); const multiboot = @import("../multiboot/multiboot.zig"); const pci = @import("../../drivers/pci/pci.zig"); +const pit = @import("../../drivers/pit/pit.zig"); const pmm = @import("../../memory/pmm.zig"); const sensei = @import("../../kata/sensei/sensei.zig"); const serial = @import("../../drivers/serial/serial.zig"); @@ -62,6 +63,10 @@ pub fn run(multiboot_addr: u64) void { idt.init(); ok(); + step("Setting up PIT"); + pit.init(); + ok(); + step("Scanning PCI bus"); pci.scan_bus(); ok(); diff --git a/mirai/common/constants/invocations.zig b/mirai/common/constants/invocations.zig index 7a44406..775d39e 100644 --- a/mirai/common/constants/invocations.zig +++ b/mirai/common/constants/invocations.zig @@ -14,6 +14,11 @@ pub const GETLOCATION: u64 = 0x0B; pub const SETLOCATION: u64 = 0x0C; pub const POSTMAN: u64 = 0x0D; pub const WIPE: u64 = 0x0E; +pub const CPUINFO: u64 = 0x0F; +pub const MEMINFO: u64 = 0x10; +pub const UPTIME: u64 = 0x11; +pub const GETTIME: u64 = 0x12; +pub const DISKINFO: u64 = 0x13; pub const ERROR: u64 = @as(u64, @bitCast(@as(i64, -1))); pub const NO_DATA: u64 = @as(u64, @bitCast(@as(i64, -2))); diff --git a/mirai/common/constants/pit.zig b/mirai/common/constants/pit.zig new file mode 100644 index 0000000..423e3f3 --- /dev/null +++ b/mirai/common/constants/pit.zig @@ -0,0 +1,20 @@ +//! PIT (Programmable Interval Timer) constants + +pub const CHANNEL_0: u16 = 0x40; +pub const CHANNEL_1: u16 = 0x41; +pub const CHANNEL_2: u16 = 0x42; +pub const COMMAND: u16 = 0x43; + +pub const BASE_FREQUENCY: u32 = 1193182; + +// Command byte bits +pub const SELECT_CHANNEL_0: u8 = 0x00; +pub const ACCESS_LOHI: u8 = 0x30; // Low byte then high byte +pub const MODE_RATE_GENERATOR: u8 = 0x04; // Mode 2: rate generator +pub const MODE_SQUARE_WAVE: u8 = 0x06; // Mode 3: square wave + +// For 1000 Hz (1ms ticks): divisor = 1193182 / 1000 = 1193 +pub const DIVISOR_1000HZ: u16 = 1193; + +// For 100 Hz (10ms ticks): divisor = 1193182 / 100 = 11932 +pub const DIVISOR_100HZ: u16 = 11932; diff --git a/mirai/common/constants/ports.zig b/mirai/common/constants/ports.zig index 68e985b..57ede2f 100644 --- a/mirai/common/constants/ports.zig +++ b/mirai/common/constants/ports.zig @@ -26,3 +26,7 @@ pub const PCI_CONFIG_DATA: u16 = 0xCFC; // VGA pub const VGA_BUFFER_ADDR: usize = 0xB8000; + +// CMOS/RTC +pub const CMOS_ADDRESS: u16 = 0x70; +pub const CMOS_DATA: u16 = 0x71; diff --git a/mirai/common/constants/time.zig b/mirai/common/constants/time.zig new file mode 100644 index 0000000..ce50e2a --- /dev/null +++ b/mirai/common/constants/time.zig @@ -0,0 +1,9 @@ +//! Time constants + +pub const TICKS_PER_SECOND: u64 = 100; + +pub const SECONDS_PER_MINUTE: u64 = 60; +pub const SECONDS_PER_HOUR: u64 = 3600; +pub const SECONDS_PER_DAY: u64 = 86400; + +pub const EPOCH_YEAR: u64 = 1970; diff --git a/mirai/drivers/pit/pit.zig b/mirai/drivers/pit/pit.zig new file mode 100644 index 0000000..93609b4 --- /dev/null +++ b/mirai/drivers/pit/pit.zig @@ -0,0 +1,12 @@ +//! PIT (Programmable Interval Timer) Driver + +const io = @import("../../asm/io.zig"); +const pit = @import("../../common/constants/pit.zig"); + +pub fn init() void { + // 100 Hz for stable operation + const command = pit.SELECT_CHANNEL_0 | pit.ACCESS_LOHI | pit.MODE_RATE_GENERATOR; + io.out_byte(pit.COMMAND, command); + io.out_byte(pit.CHANNEL_0, @truncate(pit.DIVISOR_100HZ)); + io.out_byte(pit.CHANNEL_0, @truncate(pit.DIVISOR_100HZ >> 8)); +} diff --git a/mirai/fs/afs/afs.zig b/mirai/fs/afs/afs.zig index 489f975..4f33ade 100644 --- a/mirai/fs/afs/afs.zig +++ b/mirai/fs/afs/afs.zig @@ -4,6 +4,7 @@ const cache = @import("cache.zig"); const cluster_ops = @import("cluster.zig"); const compare = @import("../../utils/string/compare.zig"); const fs = @import("../../common/constants/fs.zig"); +const info = @import("info.zig"); const ptr = @import("../../utils/types/ptr.zig"); const read = @import("read.zig"); const types = @import("types.zig"); @@ -12,6 +13,7 @@ const write = @import("write.zig"); pub const BootSector = types.BootSector; pub const Entry = types.Entry; pub const StackItem = types.StackItem; +pub const DiskInfo = types.DiskInfo; pub fn AFS(comptime BlockDeviceType: type) type { return struct { @@ -103,5 +105,9 @@ pub fn AFS(comptime BlockDeviceType: type) type { pub fn mark_unit(self: *Self, location: []const u8, data: []const u8) !void { return write.mark_unit(self, location, data); } + + pub fn get_disk_info(self: *Self) DiskInfo { + return info.get_disk_info(self); + } }; } diff --git a/mirai/fs/afs/info.zig b/mirai/fs/afs/info.zig new file mode 100644 index 0000000..8c3df0a --- /dev/null +++ b/mirai/fs/afs/info.zig @@ -0,0 +1,49 @@ +//! AFS disk info operations + +const endian = @import("../../utils/bytes/endian.zig"); +const fs = @import("../../common/constants/fs.zig"); +const types = @import("types.zig"); + +pub fn get_disk_info(afs: anytype) types.DiskInfo { + const cluster_size: u64 = @as(u64, afs.sectors_per_cluster) * fs.SECTOR_SIZE; + const total = @as(u64, afs.total_clusters) * cluster_size; + + // Count used clusters by scanning allocation table in bulk + var used_clusters: u64 = 0; + var sector_buf: [fs.SECTOR_SIZE]u8 align(fs.SECTOR_ALIGN) = undefined; + + const entries_per_sector = fs.SECTOR_SIZE / 4; // 4 bytes per entry + const table_sectors = (afs.total_clusters + entries_per_sector - 1) / entries_per_sector; + + var sector_idx: u32 = 0; + while (sector_idx < table_sectors) : (sector_idx += 1) { + const table_sector = afs.partition_offset + afs.alloc_table_sector + sector_idx; + + if (!afs.device.read_sector(table_sector, §or_buf)) { + break; + } + + // Count non-free entries in this sector + var entry_idx: usize = 0; + while (entry_idx < entries_per_sector) : (entry_idx += 1) { + const cluster = sector_idx * entries_per_sector + entry_idx; + if (cluster >= afs.total_clusters) break; + if (cluster < fs.CLUSTER_MIN) { + entry_idx += 1; + continue; + } + + const offset = entry_idx * 4; + const value = endian.read_u32_le(sector_buf[offset..]); + + if (value != fs.CLUSTER_FREE) { + used_clusters += 1; + } + } + } + + return types.DiskInfo{ + .total_bytes = total, + .used_bytes = used_clusters * cluster_size, + }; +} diff --git a/mirai/fs/afs/types.zig b/mirai/fs/afs/types.zig index 81eae5b..2ee5352 100644 --- a/mirai/fs/afs/types.zig +++ b/mirai/fs/afs/types.zig @@ -73,3 +73,8 @@ pub const ParentCacheEntry = struct { cluster: u32, parent: u32, }; + +pub const DiskInfo = struct { + total_bytes: u64, + used_bytes: u64, +}; diff --git a/mirai/kata/sensei/sensei.zig b/mirai/kata/sensei/sensei.zig index 9c30a09..2e801b3 100644 --- a/mirai/kata/sensei/sensei.zig +++ b/mirai/kata/sensei/sensei.zig @@ -15,22 +15,24 @@ const TICK_NS: u64 = 1_000_000; pub fn on_tick() void { tick_count += 1; +} - if (current) |kata| { - const delta = (TICK_NS * 1024) / kata.weight; - kata.vruntime += delta; - - if (queue.get_head()) |head| { - min_vruntime = head.vruntime; - } else { - min_vruntime = kata.vruntime; - } - } +pub fn get_tick_count() u64 { + return tick_count; } pub fn schedule() void { waker.wake_all_waiting(); + if (current) |kata| { + const elapsed = tick_count - kata.last_run; + if (elapsed > 0) { + const delta = (TICK_NS * 1024 * elapsed) / kata.weight; + kata.vruntime += delta; + kata.last_run = tick_count; + } + } + const next = pick_next(); if (next == null and current == null) { @@ -53,6 +55,7 @@ pub fn schedule() void { if (next) |n| { queue.dequeue(n); n.state = .Running; + n.last_run = tick_count; current = n; shift.to_kata(n); unreachable; @@ -111,7 +114,10 @@ fn pick_next() ?*types.Kata { curr = kata.next; } - if (chosen) |k| return k; + if (chosen) |k| { + min_vruntime = k.vruntime; + return k; + } if (current) |c| { if (c.state == .Running) return c; diff --git a/mirai/memory/pmm.zig b/mirai/memory/pmm.zig index a4b67d8..8207387 100644 --- a/mirai/memory/pmm.zig +++ b/mirai/memory/pmm.zig @@ -16,6 +16,11 @@ var total_pages: u64 = 0; var used_pages: u64 = 0; var initialized: bool = false; +pub const MemoryInfo = struct { + total: u64, + used: u64, +}; + pub fn init(kernel_end_phys: u64, memory_map: []multiboot.MemoryEntry) void { serial.print("\n=== PMM ===\n"); @@ -172,3 +177,10 @@ fn reserve_active_page_tables() void { } } } + +pub fn get_info() MemoryInfo { + return MemoryInfo{ + .total = total_pages, + .used = used_pages, + }; +} |
