Microkernel thing OS experiment (Zig ⚡)

add support for tsc_deadline

pci.express bee02dce 329ce7f4

verified
Changed files
+62 -93
components
root_server
src
ukernel
arch
amd64
instructions
interrupts
+1
components/root_server/src/main.zig
···
export fn _start() callconv(.c) noreturn {
// _ = os.syscall1(SYS_poke, 0xB16B00B5BADBABE);
// _ = os.syscall1(SYS_exit, 0x69696969);
+
asm volatile ("int3");
asm volatile (
\\ mov $0x69696969, %%rdi
\\ xor %%rsi, %%rsi
+5 -86
components/ukernel/arch/amd64/boot.zig
···
// Add in a framebuffer if found
initConsole();
+
// Get basic information through CPUID
+
arch.instructions.cpuid.init();
// Add in ACPI/dtb if found, prefer ACPI
initHwDesc();
···
init_syscalls();
+
arch.interrupts.apic.armTimer(1000);
enter_userspace(entry, 0x69, 0x7ffe_0001_0000);
}
···
// Calibrate the APIC timer
arch.interrupts.apic.init.calibrateTimer();
-
// Enable periodic interrupts
-
arch.interrupts.apic.init.enablePeriodicInterrupt(1000);
+
// Enable one-shot interrupts
+
arch.interrupts.apic.init.enableOneshotInterrupt();
}
fn initConsole() void {
···
.blue_mask_size = fb.blue_mask_size,
.blue_mask_shift = fb.blue_mask_shift,
});
-
// common.init_data.console = flanterm.init(
-
// //malloc and free
-
// null,
-
// null,
-
// // fb info
-
// fb.address,
-
// fb.width,
-
// fb.height,
-
// fb.pitch,
-
// fb.red_mask_size,
-
// fb.red_mask_shift,
-
// fb.green_mask_size,
-
// fb.green_mask_shift,
-
// fb.blue_mask_size,
-
// fb.blue_mask_shift,
-
// // canvas
-
// null,
-
// // colors
-
// flanterm.ansi_colors,
-
// flanterm.bold_ansi_colors,
-
// // default bg and fg
-
// null,
-
// null,
-
// // default bright bg and fg
-
// null,
-
// null,
-
// // font
-
// null,
-
// // font width and height
-
// 0,
-
// 0,
-
// // font spacing
-
// 1,
-
// // font scale x and y
-
// font_scale_x,
-
// font_scale_y,
-
// // margin
-
// 0,
-
// );
}
}
}
···
common.init_data.hardware_description = .{ .acpi_rsdp = rsdp_response.address };
}
}
-
-
// TODO: update the type reflection thing to make a custom
-
// function type for the ISR
-
pub const PageFaultErrorCode = packed struct(u64) {
-
present: bool,
-
write: bool,
-
user: bool,
-
reserved_write: bool,
-
instruction_fetch: bool,
-
protection_key: bool,
-
shadow_stack: bool,
-
_reserved: u8,
-
sgx: bool,
-
_reserved2: u48,
-
-
pub fn val(self: *const PageFaultErrorCode) u64 {
-
return @bitCast(self.*);
-
}
-
};
-
// pub fn page_fault(stack_frame: *arch.structures.Idt.InterruptStackFrame, err_code_u64: u64) callconv(.{ .x86_64_interrupt = .{} }) void {
-
// const err_code: PageFaultErrorCode = @bitCast(err_code_u64);
-
// log.err("PAGE FAULT @ 0x{x:0>16}, code 0x{x}!!!!!!!!!!!", .{ stack_frame.instruction_pointer, err_code.val() });
-
// const cr2 = arch.registers.ControlRegisters.Cr2.read();
-
// switch (err_code.write) {
-
// true => log.err("Tried to write to vaddr 0x{x:0>16}", .{cr2}),
-
// false => log.err("Tried to read from vaddr 0x{x:0>16}", .{cr2}),
-
// }
-
// log.err("dying...", .{});
-
// arch.instructions.die();
-
// }
-
-
// pub fn breakpoint_handler(stack_frame: *Idt.InterruptStackFrame) callconv(.{ .x86_64_interrupt = .{} }) void {
-
// log.warn("Breakpoint @ 0x{x:0>16}, returning execution...", .{stack_frame.instruction_pointer});
-
// }
-
-
// pub fn gpf(stack_frame: *Idt.InterruptStackFrame, err_code: u64) callconv(.{ .x86_64_interrupt = .{} }) void {
-
// log.warn("gpf @ 0x{x:0>16} ERR CODE {}, returning execution...", .{ stack_frame.instruction_pointer, err_code });
-
// arch.instructions.die();
-
// }
-
-
// pub fn double_fault(stack_frame: *Idt.InterruptStackFrame, err_code: u64) callconv(.{ .x86_64_interrupt = .{} }) noreturn {
-
// log.err("FATAL DOUBLE FAULT @ 0x{x:0>16}, code 0x{x}!!!!!!!!!!!", .{ stack_frame.instruction_pointer, err_code });
-
// log.err("dying...", .{});
-
// arch.instructions.die();
-
// }
fn bootstrapAPs() void {
log.info("Bootstrapping APs...", .{});
+31
components/ukernel/arch/amd64/instructions/cpuid.zig
···
+
// Do all the needed CPUID calls here, and store the info for later use
+
const std = @import("std");
+
const arch = @import("../root.zig");
+
+
pub const captured = struct {
+
pub var vendor_str: [12]u8 = undefined;
+
};
+
pub fn init() void {
+
capture_vendor_str();
+
capture_cpu_features();
+
}
+
+
fn capture_vendor_str() void {
+
const res = cpuid(0, 0);
+
@memcpy(captured.vendor_str[0..4], std.mem.asBytes(&res.ebx));
+
@memcpy(captured.vendor_str[4..8], std.mem.asBytes(&res.edx));
+
@memcpy(captured.vendor_str[8..12], std.mem.asBytes(&res.ecx));
+
}
+
+
fn capture_cpu_features() void {
+
const res = cpuid(1, 0);
+
const feat_ecx: FeaturesEcx = @bitCast(res.ecx);
+
arch.interrupts.apic.tsc_deadline_available = feat_ecx.tsc_deadline;
+
}
+
+
const FeaturesEcx = packed struct(u32) {
+
_reserved0: u23,
+
tsc_deadline: bool,
+
_reserved1: u8,
+
};
+
pub inline fn cpuid(leaf: u32, sub: u32) DefaultResults {
var eax: u32 = undefined;
var ebx: u32 = undefined;
+25 -7
components/ukernel/arch/amd64/interrupts/apic.zig
···
const log = std.log.scoped(.apic);
pub var lapic_timer_khz: usize = 0;
+
pub var tsc_deadline_available = false;
// tbh every cpu will be either x2apic or not, and if xapic it will
// have the exact same base address anyways so this is fine
···
log.debug("APIC timer: {} kHz", .{lapic_timer_khz});
}
-
pub fn enablePeriodicInterrupt(ms: usize) void {
-
singleton.setInitialCountRegister(0);
-
singleton.setDivideConfigurationRegister(.div2);
+
pub fn enableOneshotInterrupt() void {
+
const mode: LAPIC.LVTTimerRegister.Mode = switch (tsc_deadline_available) {
+
true => .tsc_deadline,
+
false => blk: {
+
singleton.setInitialCountRegister(0);
+
singleton.setDivideConfigurationRegister(.div2);
+
break :blk .oneshot;
+
},
+
};
+
// TODO: detect and support tsc_deadline, ditto @ armTimer
singleton.setLVTTimerRegister(.{
.idt_entry = 48,
-
.mode = .periodic,
+
.mode = mode,
.masked = false,
});
+
}
+
};
+
pub fn armTimer(ms: usize) void {
+
if (tsc_deadline_available) {
+
const IA32_TSC_DEADLINE = arch.registers.MSR(u64, 0x6E0);
+
const delta = arch.tsc.tsc_khz * ms;
+
const target = arch.tsc.rdtsc() + delta;
+
+
IA32_TSC_DEADLINE.write(target);
+
} else {
const ticks: u32 = @truncate(lapic_timer_khz * ms);
-
singleton.setInitialCountRegister(ticks);
}
-
};
+
}
pub fn spurious_interrupt_handler(_: *arch.interrupts.idt.InterruptFrame(u64)) callconv(.{ .x86_64_sysv = .{} }) void {
log.warn("Got a spurious interrupt!", .{});
}
pub fn periodic_handler(stack_trace: *arch.interrupts.idt.InterruptFrame(u64)) callconv(.{ .x86_64_sysv = .{} }) void {
-
log.warn("Got an APIC timer interrupt, incrementing user's %rsi...", .{});
+
log.warn("Got an APIC timer interrupt, incrementing user's rsi...", .{});
stack_trace.regs.rsi += 1;
singleton.setRegister(.eoi, 0);
+
armTimer(1000);
}