Skip to content

Commit

Permalink
increased lapic calibration accuracy
Browse files Browse the repository at this point in the history
Signed-off-by: TalonFloof <[email protected]>
  • Loading branch information
TalonFloof committed Nov 29, 2024
1 parent e790469 commit de90f4a
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 31 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@
.zig-cache
zig-out
kobold.iso
limine-zig/
limine-zig/
kobold.bcfg
32 changes: 12 additions & 20 deletions kobold/hal/x86_64/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ fn ArchInit(stackTop: usize, limine_header: *allowzero anyopaque) void {
idt.initialize();
mem.init();

if (moduleRequest.response) |response| {
for (response.modules()) |module| {
if (std.mem.eql(u8, @ptrCast(module.cmdline[0..std.mem.len(module.cmdline)]), "KernelDebug")) {
hal.debug.file.LoadDebugFile(@ptrCast(module.address));
break;
}
}
}
if (fbRequest.response) |response| {
const fb = response.framebuffers()[0]; // 0x292D3E
const ansi = [_]u32{ 0x292D3E, 0xF07178, 0x62DE84, 0xFFCB6B, 0x75A1FF, 0xF580FF, 0x60BAEC, 0xABB2BF };
Expand Down Expand Up @@ -132,7 +140,10 @@ fn ArchInit(stackTop: usize, limine_header: *allowzero anyopaque) void {
0,
);
}

//if ((rdmsr(0x1A0) & (1 << 22)) != 0) {
// std.log.warn("[Firmware Bug] MISC_ENABLE.LCMV = 1", .{});
// wrmsr(0x1a0, rdmsr(0x1A0) & (~@as(u64, 1 << 22)));
//}
if (cpuid(0x80000001).edx & (@as(u32, @intCast(1)) << 20) == 0) {
std.log.warn("WARNING!!!! Your CPU does not support the NX (No Execute) bit extension!", .{});
std.log.warn(" This allows for programs to exploit buffer overflows to run malicious code.", .{});
Expand All @@ -141,25 +152,6 @@ fn ArchInit(stackTop: usize, limine_header: *allowzero anyopaque) void {
acpi.init();
timer.init();
hart.startSMP();

if (moduleRequest.response) |response| {
var len = response.modules().len;
var i: usize = 0;
for (response.modules()) |module| {
if (std.mem.eql(u8, @ptrCast(module.cmdline[0..std.mem.len(module.cmdline)]), "KernelDebug")) {
len -= 1;
hal.debug.file.LoadDebugFile(@ptrCast(module.address));
break;
}
}
for (response.modules()) |module| {
if (std.mem.eql(u8, @ptrCast(module.cmdline[0..std.mem.len(module.cmdline)]), "KernelDebug")) {
continue;
}
//elf.RelocateELF(@ptrCast(module.address)) catch @panic("failed!");
i += 1;
}
}
}

pub export fn HartStart(stackTop: usize) callconv(.C) noreturn {
Expand Down
46 changes: 36 additions & 10 deletions kobold/hal/x86_64/timer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub const timer_log = std.log.scoped(.X64Timer);
pub fn init() void {
if (ticksPerSecond == 0) {
const hvTest = hal.archData.cpuid(0x40000000);
if (hvTest.ebx == 0x7263694D and hvTest.ecx == 0x666F736F and hvTest.edx == 0x76482074) { // "Microsoft Hv"
if ((hvTest.ebx == 0x7263694D and hvTest.ecx == 0x666F736F and hvTest.edx == 0x76482074) or hvTest.ebx == 0x786f4256) { // "Microsoft Hv" or "VBoxVBoxVBox"
if (hal.archData.cpuid(0x40000003).edx & (1 << 8) != 0) {
const freq = hal.archData.rdmsr(0x40000023); // HV_X64_MSR_APIC_FREQUENCY
timer_log.info("Microsoft Hyper-V reported {} APIC Ticks/s", .{freq});
Expand All @@ -33,6 +33,13 @@ pub fn init() void {
if ((hal.archData.cpuid(0x80000007).edx & (1 << 8)) == 0) {
timer_log.warn("TSC isn't invariant, reverting to discrete timer for timekeeping", .{});
}
const rwFreqReport = hal.archData.cpuid(0x16);
const hvFreqReport = hal.archData.cpuid(0x40000010);
if (rwFreqReport.eax != 0 and rwFreqReport.ecx != 0) {
timer_log.info("Comparing calibration against {} MHz Core and {} MHz Bus", .{ hvFreqReport.eax, hvFreqReport.ecx });
} else if (hvFreqReport.ebx != 0) {
timer_log.info("Hypervisor reported {} APIC Ticks/s, will attempt to compare with calibration", .{hvFreqReport.ebx * 1000});
}
if (acpi.HPETAddr != null) {
const addr: usize = acpi.HPETAddr.?.address;
const hpetAddr: [*]align(1) volatile u64 = @as([*]align(1) volatile u64, @ptrFromInt(addr));
Expand All @@ -43,21 +50,30 @@ pub fn init() void {
apic.hpetTicksPer100NS = 100000000.0 / apic.hpetPeriod;
hpetAddr[2] = 0;
hpetAddr[30] = 0;
hpetAddr[2] = 1;

const hz = 1000000000000000.0 / @as(f64, @floatFromInt(clock));
const interval = @as(usize, @intFromFloat(apic.hpetTicksPer100NS * 10000.0 * 100.0));
timer_log.info("HPET @ {d} MHz for APIC Timer Calibration", .{hz / 1000 / 1000});
apic.write(0x320, 0x10000);
//apic.write(0x320, 0x10000);
apic.write(0x380, 0);
apic.write(0x3e0, 0xb);
const duration = hpetAddr[30] + interval;
hpetAddr[2] = 1;
apic.write(0x380, 0xffffffff);
while (hpetAddr[30] < duration) {
std.atomic.spinLoopHint();
}
apic.write(0x320, 0x10000);
const endCount = hpetAddr[30];
const count = 0xffffffff - apic.read(0x390);
ticksPerSecond = count;
const errorCount = @as(f64, @floatFromInt(endCount - duration)) / (1000000.0 / apic.hpetPeriod);
timer_log.info("{} ns HPET error", .{errorCount});
//timer_log.info("Interval was actually {} ns", .{@as(u64, @intFromFloat((100.0 * 10000.0 * 100.0) + errorCount))});
const correctedBase = @as(f64, @floatFromInt(count)) / (((100.0 * 10000.0 * 100.0) + errorCount) / 1000000.0);
//timer_log.info("Corrected to {} APIC Ticks/ms", .{@as(u64, @intFromFloat(correctedBase)) * 1000});
//apic.write(0x320, 0x10000);
//const count = 0xffffffff - apic.read(0x390);
ticksPerSecond = @as(u64, @intFromFloat(correctedBase)) * 1000;
} else {
const freq: f64 = 105000000.0 / 88.0 / 65536.0;
timer_log.info("PIT @ ~{} Hz for APIC Timer Calibration", .{freq});
Expand All @@ -76,22 +92,32 @@ pub fn init() void {
while (io.inb(0x61) & 0x20 == 0) {
std.atomic.spinLoopHint();
}
apic.write(0x320, 0x10000);
const count = 0xffffffff - apic.read(0x390);
//apic.write(0x320, 0x10000);
ticksPerSecond = @intFromFloat(@as(f64, @floatFromInt(count)) * freq);
}
const rawTicks = ticksPerSecond;
ticksPerSecond = (ticksPerSecond / 100000) * 100000;
timer_log.info("~{} APIC Ticks/s ({} Raw Ticks)", .{ ticksPerSecond, rawTicks });
//const rawTicks = ticksPerSecond;
//ticksPerSecond = (ticksPerSecond / 100000) * 100000;
timer_log.info("{} APIC Ticks/s Calibration Result", .{ticksPerSecond});
if (hvFreqReport.ebx != 0) {
const diff = (@as(i64, @intCast(ticksPerSecond))) - (@as(i64, @intCast(hvFreqReport.ebx)) * 1000);
timer_log.info("HV-Calib Regression is {} APIC Ticks", .{diff});
if (@abs(diff) < 2_000_000) { // If the regression is +-2MHz, then the Hypervisor Report is accurate
ticksPerSecond = @as(u64, @intCast(hvFreqReport.ebx)) * 1000;
timer_log.info("Regression is safe, will use {} APIC Ticks/s", .{ticksPerSecond});
} else {
timer_log.warn("Regression highly deviates from report, will use {} APIC Ticks/s", .{ticksPerSecond});
}
}
}
}
apic.write(0x3e0, 0xb);
apic.write(0x3e0, 0x1);
apic.write(0x320, 0x20);
apic.write(0x380, 0);
}

pub fn setDeadline(microsecs: u64) void {
const t: u64 = @intFromFloat(@as(f64, @floatFromInt(ticksPerSecond)) * (@as(f64, @floatFromInt(microsecs)) / 1000000.0));
const t: u64 = @as(u64, @intFromFloat(@as(f64, @floatFromInt(ticksPerSecond)) * (@as(f64, @floatFromInt(microsecs)) / 1000000.0 / 4.0)));
if (t > 0xffffffff) {
apic.write(0x380, 0xffffffff);
} else {
Expand Down
8 changes: 8 additions & 0 deletions kobold/kernel/port.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const std = @import("std");
const team = @import("team.zig");

pub const Message = struct {
sourceTID: usize = 0,
Expand All @@ -7,3 +8,10 @@ pub const Message = struct {
bufSize: usize = 0,
buf: *anyopaque = undefined,
};

pub const Port = struct {
id: u64,
creatorTeam: *team.Team = undefined,
badge: u64 = 0, // 0 = Null Badge
name: [32]u8 = [_]u8{0} ** 32,
};

0 comments on commit de90f4a

Please sign in to comment.