+1
components/root_server/src/main.zig
+1
components/root_server/src/main.zig
+5
-86
components/ukernel/arch/amd64/boot.zig
+5
-86
components/ukernel/arch/amd64/boot.zig
···
51
51
52
52
// Add in a framebuffer if found
53
53
initConsole();
54
+
// Get basic information through CPUID
55
+
arch.instructions.cpuid.init();
54
56
55
57
// Add in ACPI/dtb if found, prefer ACPI
56
58
initHwDesc();
···
135
137
136
138
init_syscalls();
137
139
140
+
arch.interrupts.apic.armTimer(1000);
138
141
enter_userspace(entry, 0x69, 0x7ffe_0001_0000);
139
142
}
140
143
···
236
239
// Calibrate the APIC timer
237
240
arch.interrupts.apic.init.calibrateTimer();
238
241
239
-
// Enable periodic interrupts
240
-
arch.interrupts.apic.init.enablePeriodicInterrupt(1000);
242
+
// Enable one-shot interrupts
243
+
arch.interrupts.apic.init.enableOneshotInterrupt();
241
244
}
242
245
243
246
fn initConsole() void {
···
258
261
.blue_mask_size = fb.blue_mask_size,
259
262
.blue_mask_shift = fb.blue_mask_shift,
260
263
});
261
-
// common.init_data.console = flanterm.init(
262
-
// //malloc and free
263
-
// null,
264
-
// null,
265
-
// // fb info
266
-
// fb.address,
267
-
// fb.width,
268
-
// fb.height,
269
-
// fb.pitch,
270
-
// fb.red_mask_size,
271
-
// fb.red_mask_shift,
272
-
// fb.green_mask_size,
273
-
// fb.green_mask_shift,
274
-
// fb.blue_mask_size,
275
-
// fb.blue_mask_shift,
276
-
// // canvas
277
-
// null,
278
-
// // colors
279
-
// flanterm.ansi_colors,
280
-
// flanterm.bold_ansi_colors,
281
-
// // default bg and fg
282
-
// null,
283
-
// null,
284
-
// // default bright bg and fg
285
-
// null,
286
-
// null,
287
-
// // font
288
-
// null,
289
-
// // font width and height
290
-
// 0,
291
-
// 0,
292
-
// // font spacing
293
-
// 1,
294
-
// // font scale x and y
295
-
// font_scale_x,
296
-
// font_scale_y,
297
-
// // margin
298
-
// 0,
299
-
// );
300
264
}
301
265
}
302
266
}
···
309
273
common.init_data.hardware_description = .{ .acpi_rsdp = rsdp_response.address };
310
274
}
311
275
}
312
-
313
-
// TODO: update the type reflection thing to make a custom
314
-
// function type for the ISR
315
-
pub const PageFaultErrorCode = packed struct(u64) {
316
-
present: bool,
317
-
write: bool,
318
-
user: bool,
319
-
reserved_write: bool,
320
-
instruction_fetch: bool,
321
-
protection_key: bool,
322
-
shadow_stack: bool,
323
-
_reserved: u8,
324
-
sgx: bool,
325
-
_reserved2: u48,
326
-
327
-
pub fn val(self: *const PageFaultErrorCode) u64 {
328
-
return @bitCast(self.*);
329
-
}
330
-
};
331
-
// pub fn page_fault(stack_frame: *arch.structures.Idt.InterruptStackFrame, err_code_u64: u64) callconv(.{ .x86_64_interrupt = .{} }) void {
332
-
// const err_code: PageFaultErrorCode = @bitCast(err_code_u64);
333
-
// log.err("PAGE FAULT @ 0x{x:0>16}, code 0x{x}!!!!!!!!!!!", .{ stack_frame.instruction_pointer, err_code.val() });
334
-
// const cr2 = arch.registers.ControlRegisters.Cr2.read();
335
-
// switch (err_code.write) {
336
-
// true => log.err("Tried to write to vaddr 0x{x:0>16}", .{cr2}),
337
-
// false => log.err("Tried to read from vaddr 0x{x:0>16}", .{cr2}),
338
-
// }
339
-
// log.err("dying...", .{});
340
-
// arch.instructions.die();
341
-
// }
342
-
343
-
// pub fn breakpoint_handler(stack_frame: *Idt.InterruptStackFrame) callconv(.{ .x86_64_interrupt = .{} }) void {
344
-
// log.warn("Breakpoint @ 0x{x:0>16}, returning execution...", .{stack_frame.instruction_pointer});
345
-
// }
346
-
347
-
// pub fn gpf(stack_frame: *Idt.InterruptStackFrame, err_code: u64) callconv(.{ .x86_64_interrupt = .{} }) void {
348
-
// log.warn("gpf @ 0x{x:0>16} ERR CODE {}, returning execution...", .{ stack_frame.instruction_pointer, err_code });
349
-
// arch.instructions.die();
350
-
// }
351
-
352
-
// pub fn double_fault(stack_frame: *Idt.InterruptStackFrame, err_code: u64) callconv(.{ .x86_64_interrupt = .{} }) noreturn {
353
-
// log.err("FATAL DOUBLE FAULT @ 0x{x:0>16}, code 0x{x}!!!!!!!!!!!", .{ stack_frame.instruction_pointer, err_code });
354
-
// log.err("dying...", .{});
355
-
// arch.instructions.die();
356
-
// }
357
276
358
277
fn bootstrapAPs() void {
359
278
log.info("Bootstrapping APs...", .{});
+31
components/ukernel/arch/amd64/instructions/cpuid.zig
+31
components/ukernel/arch/amd64/instructions/cpuid.zig
···
1
+
// Do all the needed CPUID calls here, and store the info for later use
2
+
const std = @import("std");
3
+
const arch = @import("../root.zig");
4
+
5
+
pub const captured = struct {
6
+
pub var vendor_str: [12]u8 = undefined;
7
+
};
8
+
pub fn init() void {
9
+
capture_vendor_str();
10
+
capture_cpu_features();
11
+
}
12
+
13
+
fn capture_vendor_str() void {
14
+
const res = cpuid(0, 0);
15
+
@memcpy(captured.vendor_str[0..4], std.mem.asBytes(&res.ebx));
16
+
@memcpy(captured.vendor_str[4..8], std.mem.asBytes(&res.edx));
17
+
@memcpy(captured.vendor_str[8..12], std.mem.asBytes(&res.ecx));
18
+
}
19
+
20
+
fn capture_cpu_features() void {
21
+
const res = cpuid(1, 0);
22
+
const feat_ecx: FeaturesEcx = @bitCast(res.ecx);
23
+
arch.interrupts.apic.tsc_deadline_available = feat_ecx.tsc_deadline;
24
+
}
25
+
26
+
const FeaturesEcx = packed struct(u32) {
27
+
_reserved0: u23,
28
+
tsc_deadline: bool,
29
+
_reserved1: u8,
30
+
};
31
+
1
32
pub inline fn cpuid(leaf: u32, sub: u32) DefaultResults {
2
33
var eax: u32 = undefined;
3
34
var ebx: u32 = undefined;
+25
-7
components/ukernel/arch/amd64/interrupts/apic.zig
+25
-7
components/ukernel/arch/amd64/interrupts/apic.zig
···
3
3
const log = std.log.scoped(.apic);
4
4
5
5
pub var lapic_timer_khz: usize = 0;
6
+
pub var tsc_deadline_available = false;
6
7
7
8
// tbh every cpu will be either x2apic or not, and if xapic it will
8
9
// have the exact same base address anyways so this is fine
···
277
278
log.debug("APIC timer: {} kHz", .{lapic_timer_khz});
278
279
}
279
280
280
-
pub fn enablePeriodicInterrupt(ms: usize) void {
281
-
singleton.setInitialCountRegister(0);
282
-
singleton.setDivideConfigurationRegister(.div2);
281
+
pub fn enableOneshotInterrupt() void {
282
+
const mode: LAPIC.LVTTimerRegister.Mode = switch (tsc_deadline_available) {
283
+
true => .tsc_deadline,
284
+
false => blk: {
285
+
singleton.setInitialCountRegister(0);
286
+
singleton.setDivideConfigurationRegister(.div2);
287
+
break :blk .oneshot;
288
+
},
289
+
};
283
290
291
+
// TODO: detect and support tsc_deadline, ditto @ armTimer
284
292
singleton.setLVTTimerRegister(.{
285
293
.idt_entry = 48,
286
-
.mode = .periodic,
294
+
.mode = mode,
287
295
.masked = false,
288
296
});
297
+
}
298
+
};
289
299
300
+
pub fn armTimer(ms: usize) void {
301
+
if (tsc_deadline_available) {
302
+
const IA32_TSC_DEADLINE = arch.registers.MSR(u64, 0x6E0);
303
+
const delta = arch.tsc.tsc_khz * ms;
304
+
const target = arch.tsc.rdtsc() + delta;
305
+
306
+
IA32_TSC_DEADLINE.write(target);
307
+
} else {
290
308
const ticks: u32 = @truncate(lapic_timer_khz * ms);
291
-
292
309
singleton.setInitialCountRegister(ticks);
293
310
}
294
-
};
311
+
}
295
312
296
313
pub fn spurious_interrupt_handler(_: *arch.interrupts.idt.InterruptFrame(u64)) callconv(.{ .x86_64_sysv = .{} }) void {
297
314
log.warn("Got a spurious interrupt!", .{});
298
315
}
299
316
300
317
pub fn periodic_handler(stack_trace: *arch.interrupts.idt.InterruptFrame(u64)) callconv(.{ .x86_64_sysv = .{} }) void {
301
-
log.warn("Got an APIC timer interrupt, incrementing user's %rsi...", .{});
318
+
log.warn("Got an APIC timer interrupt, incrementing user's rsi...", .{});
302
319
stack_trace.regs.rsi += 1;
303
320
singleton.setRegister(.eoi, 0);
321
+
armTimer(1000);
304
322
}