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