Microkernel thing OS experiment (Zig ⚡)

TSC calibration demo

pci.express e0afa531 0e62c4b3

verified
Changed files
+42 -8
components
ukernel
arch
amd64
+2 -1
components/ukernel/arch/amd64/boot.zig
··· 95 95 bootstrapAPs(); 96 96 97 97 // Calibrate our TSC 98 - arch.tsc.calibrate(); 98 + const rate = arch.tsc.get_tsc_rate(); 99 + log.info("TSC estimated CPU MHz = {?}", .{rate / 1000}); 99 100 100 101 log.info("Setting up scheduling...", .{}); 101 102 // // Initialize the APIC
+1 -1
components/ukernel/arch/amd64/interrupts/pic.zig
··· 44 44 wait(); 45 45 46 46 // Unmask only the 8254 47 - out(u8, PIC_ONE_DATA_PORT, 0b1111_1110); 47 + out(u8, PIC_ONE_DATA_PORT, 0b1111_1111); 48 48 wait(); 49 49 out(u8, PIC_TWO_DATA_PORT, 0b1111_1111); 50 50 wait();
+13
components/ukernel/arch/amd64/interrupts/pit.zig
··· 4 4 const Idt = arch.structures.Idt; 5 5 const PIT_HZ = 1_193_180; 6 6 const DATA_PORT = 0x40; 7 + const DATA_PORT_1 = 0x41; 8 + const DATA_PORT_2 = 0x42; 7 9 const CMD_PORT = 0x43; 8 10 11 + // If we want a repeating square wave 9 12 pub fn set_frequency(hz: u32) void { 10 13 const divider = PIT_HZ / hz; 11 14 @import("std").log.debug("divider = {}", .{divider}); ··· 16 19 out(u8, DATA_PORT, @truncate(divider)); 17 20 out(u8, DATA_PORT, @truncate(divider >> 8)); 18 21 } 22 + 23 + pub inline fn mode0(ms: u32) void { 24 + out(u8, CMD_PORT, 0xb0); 25 + 26 + // Interrupt On Terminal Count 27 + const latch = (PIT_HZ / (1000 / ms)); 28 + out(u8, 0x42, @truncate(latch)); 29 + out(u8, 0x42, @truncate(latch >> 8)); 30 + } 31 + 19 32 var ctr: usize = 0; 20 33 pub fn handler(_: *Idt.InterruptStackFrame) callconv(.{ .x86_64_interrupt = .{} }) void { 21 34 if (ctr % 1000 == 0)
+26 -6
components/ukernel/arch/amd64/tsc.zig
··· 1 1 const arch = @import("root.zig"); 2 + const out = arch.port.out; 3 + const in = arch.port.in; 4 + 2 5 pub inline fn rdtsc() u64 { 3 6 var low: u32 = undefined; 4 7 var high: u32 = undefined; 5 8 6 9 asm volatile ("rdtsc" 7 10 : [low] "={eax}" (low), 8 - [high] "={eax}" (high), 11 + [high] "={edx}" (high), 9 12 ); 10 13 11 14 return (@as(u64, high) << 32) | @as(u64, low); ··· 14 17 /// This should be called if we cannot get the TSC rate from 15 18 /// CPUID.15h and 16h on Intel platforms. The calibration will be done 16 19 /// against the 8254 PIT. 17 - pub fn calibrate() void { 20 + pub fn get_tsc_rate() ?usize { 18 21 // Set up the PIC 19 22 arch.interrupts.pic.init(); 20 23 21 - // Set up the PIT at 1 kHz 22 - arch.interrupts.pit.set_frequency(1000); 24 + out(u8, 0x61, in(u8, 0x61) & 0b1111_1101 | 0x01); 23 25 24 - // Enable interrupts 25 - // arch.interrupts.enable(); 26 + var pollcnt: u32 = 0; 27 + var start: usize = 0; 28 + var end: usize = 0; 29 + var prev_end: usize = 0; 30 + var delta: usize = 0; 31 + 32 + arch.interrupts.pit.mode0(50); 33 + start = rdtsc(); 34 + end = start; 35 + while (in(u8, 0x61) & 0x20 == 0) { 36 + end = rdtsc(); 37 + delta = end - prev_end; 38 + prev_end = end; 39 + 40 + pollcnt += 1; 41 + } 42 + 43 + if (pollcnt < 1000) return null; 44 + 45 + return (end - start) / 50; 26 46 }