feat(pc): enter x2APIC mode

This commit is contained in:
Loïc Grégoire
2026-04-15 20:12:12 -04:00
parent 7d9231960f
commit d600b89024
3 changed files with 38 additions and 10 deletions
+2
View File
@@ -5,6 +5,7 @@ const std = @import("std");
const impl = @import("impl.zig"); const impl = @import("impl.zig");
const ke = b.ke; const ke = b.ke;
const ki = b.ke.private; const ki = b.ke.private;
const pl = b.pl;
var gdt = extern struct { var gdt = extern struct {
entries: [9]u64 align(1), entries: [9]u64 align(1),
@@ -85,6 +86,7 @@ fn early_cpu_init() linksection(b.init) void {
pub fn ap_entry(cpu_id: u32) noreturn { pub fn ap_entry(cpu_id: u32) noreturn {
early_cpu_init(); early_cpu_init();
ki.cpu.init_cpu(cpu_id); ki.cpu.init_cpu(cpu_id);
pl.impl.init_ap();
while (true) { while (true) {
std.atomic.spinLoopHint(); std.atomic.spinLoopHint();
+25 -10
View File
@@ -3,6 +3,7 @@ const amd64 = @import("arch");
const b = @import("base"); const b = @import("base");
const acpi = b.pl.acpi; const acpi = b.pl.acpi;
const mm = b.mm; const mm = b.mm;
const ke = b.ke;
const MadtLapic = extern struct { const MadtLapic = extern struct {
header: acpi.MadtEntryHeader, header: acpi.MadtEntryHeader,
@@ -72,7 +73,7 @@ pub const ApicRegisters = enum(u32) {
pub var apics: std.ArrayList(u32) = .empty; pub var apics: std.ArrayList(u32) = .empty;
var xapic_address: ?usize = null; var xapic_address: ?usize = null;
pub var xapic_base_physical: usize = 0; pub var xapic_base_physical: usize = 0;
pub var in_x2apic_mode: bool = false; const in_x2apic_mode = ke.CpuLocal(bool, false);
const log = std.log.scoped(.apic); const log = std.log.scoped(.apic);
@@ -95,7 +96,7 @@ fn x2apic_read(register: ApicRegisters) u64 {
} }
pub fn write(register: ApicRegisters, value: u32) void { pub fn write(register: ApicRegisters, value: u32) void {
if (in_x2apic_mode) { if (in_x2apic_mode.local().*) {
x2apic_write(register, value); x2apic_write(register, value);
} else { } else {
xapic_write(register, value); xapic_write(register, value);
@@ -103,7 +104,7 @@ pub fn write(register: ApicRegisters, value: u32) void {
} }
pub fn read(register: ApicRegisters) u64 { pub fn read(register: ApicRegisters) u64 {
if (in_x2apic_mode) { if (in_x2apic_mode.local().*) {
return x2apic_read(register); return x2apic_read(register);
} else { } else {
return @intCast(xapic_read(register)); return @intCast(xapic_read(register));
@@ -111,7 +112,7 @@ pub fn read(register: ApicRegisters) u64 {
} }
pub fn get_id() u32 { pub fn get_id() u32 {
if (in_x2apic_mode) { if (in_x2apic_mode.local().*) {
return @truncate(x2apic_read(.Id)); return @truncate(x2apic_read(.Id));
} else { } else {
return xapic_read(.Id) >> 24; return xapic_read(.Id) >> 24;
@@ -119,7 +120,7 @@ pub fn get_id() u32 {
} }
pub fn send_init(apic_id: u32) void { pub fn send_init(apic_id: u32) void {
if (in_x2apic_mode) { if (in_x2apic_mode.local().*) {
x2apic_write(.Icr, (@as(u64, apic_id) << 32) | 0x0000C500); x2apic_write(.Icr, (@as(u64, apic_id) << 32) | 0x0000C500);
} else { } else {
xapic_write(.Icr1, @as(u32, apic_id) << 24); xapic_write(.Icr1, @as(u32, apic_id) << 24);
@@ -129,7 +130,7 @@ pub fn send_init(apic_id: u32) void {
} }
pub fn send_sipi(apic_id: u32, startup_page: u8) void { pub fn send_sipi(apic_id: u32, startup_page: u8) void {
if (in_x2apic_mode) { if (in_x2apic_mode.local().*) {
x2apic_write(.Icr, (@as(u64, apic_id) << 32) | 0x00004600 | startup_page); x2apic_write(.Icr, (@as(u64, apic_id) << 32) | 0x00004600 | startup_page);
} else { } else {
xapic_write(.Icr1, @as(u32, apic_id) << 24); xapic_write(.Icr1, @as(u32, apic_id) << 24);
@@ -140,7 +141,7 @@ pub fn send_sipi(apic_id: u32, startup_page: u8) void {
pub fn send_ipi(apic_id: u32, vector: u8, delivery_mode: u8) void { pub fn send_ipi(apic_id: u32, vector: u8, delivery_mode: u8) void {
const icr_value = (@as(u64, apic_id) << 32) | (@as(u64, delivery_mode) << 8) | vector; const icr_value = (@as(u64, apic_id) << 32) | (@as(u64, delivery_mode) << 8) | vector;
if (in_x2apic_mode) { if (in_x2apic_mode.local().*) {
x2apic_write(.Icr, icr_value); x2apic_write(.Icr, icr_value);
} else { } else {
// Write to ICR1 first, because writing to the low word causes // Write to ICR1 first, because writing to the low word causes
@@ -198,12 +199,26 @@ pub fn init() linksection(b.init) void {
if (base & (1 << 10) == 0) { if (base & (1 << 10) == 0) {
xapic_address = mm.p2v(base & 0xFFFFF000); xapic_address = mm.p2v(base & 0xFFFFF000);
xapic_base_physical = base & 0xFFFFF000; xapic_base_physical = base & 0xFFFFF000;
} else {
in_x2apic_mode.local().* = true;
} }
init_local();
}
pub fn init_local() void {
write(.Svr, @intCast(read(.Svr) | 0x1FF));
write(.Tpr, 0);
write(.Eoi, 0);
} }
pub fn enter_x2apic() void { pub fn enter_x2apic() void {
if (in_x2apic_mode) return;
const apic_base = amd64.read_msr(.LapicBase); const apic_base = amd64.read_msr(.LapicBase);
amd64.wrmsr(.LapicBase, apic_base | (1 << 10) | (1 << 11)); in_x2apic_mode.local().* = true;
if (apic_base & (1 << 10) != 0) return; // Already in x2apic.
if (apic_base & (1 << 11) == 0) {
// Ensure xAPIC is enabled first.
amd64.write_msr(.LapicBase, apic_base | (1 << 11));
}
amd64.write_msr(.LapicBase, apic_base | (1 << 10) | (1 << 11));
} }
+11
View File
@@ -72,6 +72,13 @@ fn init_hypervisor(hv: amd64.hypervisor.Info) void {
} }
} }
pub fn init_ap() void {
if (amd64.cpu_features.x2apic) {
apic.enter_x2apic();
}
apic.init_local();
}
pub fn late_init(boot_info: *pl.BootInfo) linksection(b.init) void { pub fn late_init(boot_info: *pl.BootInfo) linksection(b.init) void {
pl.acpi.init(boot_info); pl.acpi.init(boot_info);
@@ -85,6 +92,10 @@ pub fn late_init(boot_info: *pl.BootInfo) linksection(b.init) void {
if (apic.apics.items.len != 0) { if (apic.apics.items.len != 0) {
smp.init(); smp.init();
} }
if (amd64.cpu_features.x2apic) {
apic.enter_x2apic();
}
} }
pub fn debug_write(c: u8) void { pub fn debug_write(c: u8) void {