aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-02-20 16:01:41 +0530
committerBobby <[email protected]>2026-02-20 16:01:41 +0530
commitc1c827540981247fd943318f503e5d814e91921d (patch)
tree487565051922295d669ed560b04c10916db35c29
parenteb4c4dd3c9fe7d2424298c7b53cbe6fc1c3707eb (diff)
downloadakiba-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.zig56
-rw-r--r--mirai/asm/cpuid.zig58
-rw-r--r--mirai/boot/sequence/sequence.zig5
-rw-r--r--mirai/common/constants/invocations.zig5
-rw-r--r--mirai/common/constants/pit.zig20
-rw-r--r--mirai/common/constants/ports.zig4
-rw-r--r--mirai/common/constants/time.zig9
-rw-r--r--mirai/drivers/pit/pit.zig12
-rw-r--r--mirai/fs/afs/afs.zig6
-rw-r--r--mirai/fs/afs/info.zig49
-rw-r--r--mirai/fs/afs/types.zig5
-rw-r--r--mirai/kata/sensei/sensei.zig28
-rw-r--r--mirai/memory/pmm.zig12
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, &sector_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,
+ };
+}