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
···
bootstrapAPs();
// Calibrate our TSC
-
arch.tsc.calibrate();
+
const rate = arch.tsc.get_tsc_rate();
+
log.info("TSC estimated CPU MHz = {?}", .{rate / 1000});
log.info("Setting up scheduling...", .{});
// // Initialize the APIC
+1 -1
components/ukernel/arch/amd64/interrupts/pic.zig
···
wait();
// Unmask only the 8254
-
out(u8, PIC_ONE_DATA_PORT, 0b1111_1110);
+
out(u8, PIC_ONE_DATA_PORT, 0b1111_1111);
wait();
out(u8, PIC_TWO_DATA_PORT, 0b1111_1111);
wait();
+13
components/ukernel/arch/amd64/interrupts/pit.zig
···
const Idt = arch.structures.Idt;
const PIT_HZ = 1_193_180;
const DATA_PORT = 0x40;
+
const DATA_PORT_1 = 0x41;
+
const DATA_PORT_2 = 0x42;
const CMD_PORT = 0x43;
+
// If we want a repeating square wave
pub fn set_frequency(hz: u32) void {
const divider = PIT_HZ / hz;
@import("std").log.debug("divider = {}", .{divider});
···
out(u8, DATA_PORT, @truncate(divider));
out(u8, DATA_PORT, @truncate(divider >> 8));
}
+
+
pub inline fn mode0(ms: u32) void {
+
out(u8, CMD_PORT, 0xb0);
+
+
// Interrupt On Terminal Count
+
const latch = (PIT_HZ / (1000 / ms));
+
out(u8, 0x42, @truncate(latch));
+
out(u8, 0x42, @truncate(latch >> 8));
+
}
+
var ctr: usize = 0;
pub fn handler(_: *Idt.InterruptStackFrame) callconv(.{ .x86_64_interrupt = .{} }) void {
if (ctr % 1000 == 0)
+26 -6
components/ukernel/arch/amd64/tsc.zig
···
const arch = @import("root.zig");
+
const out = arch.port.out;
+
const in = arch.port.in;
+
pub inline fn rdtsc() u64 {
var low: u32 = undefined;
var high: u32 = undefined;
asm volatile ("rdtsc"
: [low] "={eax}" (low),
-
[high] "={eax}" (high),
+
[high] "={edx}" (high),
);
return (@as(u64, high) << 32) | @as(u64, low);
···
/// This should be called if we cannot get the TSC rate from
/// CPUID.15h and 16h on Intel platforms. The calibration will be done
/// against the 8254 PIT.
-
pub fn calibrate() void {
+
pub fn get_tsc_rate() ?usize {
// Set up the PIC
arch.interrupts.pic.init();
-
// Set up the PIT at 1 kHz
-
arch.interrupts.pit.set_frequency(1000);
+
out(u8, 0x61, in(u8, 0x61) & 0b1111_1101 | 0x01);
-
// Enable interrupts
-
// arch.interrupts.enable();
+
var pollcnt: u32 = 0;
+
var start: usize = 0;
+
var end: usize = 0;
+
var prev_end: usize = 0;
+
var delta: usize = 0;
+
+
arch.interrupts.pit.mode0(50);
+
start = rdtsc();
+
end = start;
+
while (in(u8, 0x61) & 0x20 == 0) {
+
end = rdtsc();
+
delta = end - prev_end;
+
prev_end = end;
+
+
pollcnt += 1;
+
}
+
+
if (pollcnt < 1000) return null;
+
+
return (end - start) / 50;
}