Microkernel thing OS experiment (Zig ⚡)
1const arch = @import("root.zig");
2const std = @import("std");
3const out = arch.port.out;
4const in = arch.port.in;
5const log = std.log.scoped(.tsc);
6
7pub var tsc_khz: usize = 0;
8
9pub inline fn rdtsc() u64 {
10 var low: u32 = undefined;
11 var high: u32 = undefined;
12
13 asm volatile ("rdtsc"
14 : [low] "={eax}" (low),
15 [high] "={edx}" (high),
16 );
17
18 return (@as(u64, high) << 32) | @as(u64, low);
19}
20
21/// This should be called if we cannot get the TSC rate from
22/// CPUID.15h and 16h on Intel platforms. The calibration will be done
23/// against the 8254 PIT.
24pub fn calibrate_pit() !void {
25 // Set up the PIC
26 arch.interrupts.pic.init();
27
28 out(u8, 0x61, in(u8, 0x61) & 0b1111_1101 | 0x01);
29
30 var pollcnt: u32 = 0;
31 var start: usize = 0;
32 var end: usize = 0;
33 var prev_end: usize = 0;
34 var delta: usize = 0;
35
36 arch.interrupts.pit.mode0(50);
37 start = rdtsc();
38 end = start;
39 while (in(u8, 0x61) & 0x20 == 0) {
40 end = rdtsc();
41 delta = end - prev_end;
42 prev_end = end;
43
44 pollcnt += 1;
45 }
46
47 if (pollcnt < 1000) return error.PitError;
48
49 tsc_khz = (end - start) / 50;
50
51 log.debug("{} MHz", .{tsc_khz / 1000});
52}
53
54/// Delay for a set amount of ms using crappy polling
55pub fn delay_poll(ms: usize) void {
56 const start = rdtsc();
57 const target = start + ms * tsc_khz;
58 while (rdtsc() < target) {}
59}