mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-30 23:08:21 +00:00
feat(pc): add AP startup
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
const std = @import("std");
|
||||
const amd64 = @import("arch");
|
||||
const b = @import("base");
|
||||
const acpi = b.pl.acpi;
|
||||
const mm = b.mm;
|
||||
|
||||
const MadtLapic = extern struct {
|
||||
header: acpi.MadtEntryHeader,
|
||||
id: u8 align(1),
|
||||
version: u8 align(1),
|
||||
flags: u32 align(1),
|
||||
};
|
||||
|
||||
const MadtIoapic = extern struct {
|
||||
header: acpi.MadtEntryHeader,
|
||||
id: u8 align(1),
|
||||
version: u8 align(1),
|
||||
flags: u32 align(1),
|
||||
address: u32 align(1),
|
||||
global_system_interrupt_base: u32 align(1),
|
||||
};
|
||||
|
||||
const MadtIso = extern struct {
|
||||
header: acpi.MadtEntryHeader,
|
||||
bus_source: u8 align(1),
|
||||
irq_source: u8 align(1),
|
||||
global_system_interrupt: u32 align(1),
|
||||
flags: u16 align(1),
|
||||
};
|
||||
|
||||
const MadtX2Lapic = extern struct {
|
||||
header: acpi.MadtEntryHeader,
|
||||
reserved: u16 align(1),
|
||||
id: u32 align(1),
|
||||
flags: u32 align(1),
|
||||
acpi_uid: u32 align(1),
|
||||
};
|
||||
|
||||
pub const ApicRegisters = enum(u32) {
|
||||
Id = 0x20,
|
||||
Version = 0x30,
|
||||
|
||||
Tpr = 0x80,
|
||||
Apr = 0x90,
|
||||
Ppr = 0xA0,
|
||||
Eoi = 0xB0,
|
||||
RemoteRead = 0xC0,
|
||||
Ldr = 0xD0,
|
||||
Dfr = 0xE0,
|
||||
Svr = 0xF0,
|
||||
|
||||
Isr = 0x100,
|
||||
Tmr = 0x180,
|
||||
Irr = 0x200,
|
||||
Esr = 0x280,
|
||||
|
||||
LvtCmci = 0x2F0,
|
||||
Icr = 0x300,
|
||||
Icr1 = 0x310,
|
||||
LvtTimer = 0x320,
|
||||
LvtThermal = 0x330,
|
||||
LvtPerf = 0x340,
|
||||
LvtLint0 = 0x350,
|
||||
LvtLint1 = 0x360,
|
||||
LvtError = 0x370,
|
||||
|
||||
TimerInitialCount = 0x380,
|
||||
TimerCurrentCount = 0x390,
|
||||
TimerDivideConfig = 0x3E0,
|
||||
};
|
||||
|
||||
pub var apics: std.ArrayList(u32) = .empty;
|
||||
var xapic_address: ?usize = null;
|
||||
pub var xapic_base_physical: usize = 0;
|
||||
pub var in_x2apic_mode: bool = false;
|
||||
|
||||
const log = std.log.scoped(.apic);
|
||||
|
||||
fn xapic_write(register: ApicRegisters, value: u32) void {
|
||||
const lapic_base = xapic_address orelse return;
|
||||
b.mmio_write(u32, lapic_base + @intFromEnum(register), value);
|
||||
}
|
||||
|
||||
fn xapic_read(register: ApicRegisters) u32 {
|
||||
const lapic_base = xapic_address orelse return 0;
|
||||
return b.mmio_read(u32, lapic_base + @intFromEnum(register));
|
||||
}
|
||||
|
||||
fn x2apic_write(register: ApicRegisters, value: u64) void {
|
||||
amd64.wrmsr(@intFromEnum(amd64.Msr.X2ApicBase) + (@as(u32, @intFromEnum(register)) >> 4), value);
|
||||
}
|
||||
|
||||
fn x2apic_read(register: ApicRegisters) u64 {
|
||||
return amd64.rdmsr(@intFromEnum(amd64.Msr.X2ApicBase) + (@as(u32, @intFromEnum(register)) >> 4));
|
||||
}
|
||||
|
||||
pub fn write(register: ApicRegisters, value: u32) void {
|
||||
if (in_x2apic_mode) {
|
||||
x2apic_write(register, value);
|
||||
} else {
|
||||
xapic_write(register, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(register: ApicRegisters) u64 {
|
||||
if (in_x2apic_mode) {
|
||||
return x2apic_read(register);
|
||||
} else {
|
||||
return @intCast(xapic_read(register));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_id() u32 {
|
||||
if (in_x2apic_mode) {
|
||||
return @truncate(x2apic_read(.Id));
|
||||
} else {
|
||||
return xapic_read(.Id) >> 24;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_init(apic_id: u32) void {
|
||||
if (in_x2apic_mode) {
|
||||
x2apic_write(.Icr, (@as(u64, apic_id) << 32) | 0x0000C500);
|
||||
} else {
|
||||
xapic_write(.Icr1, @as(u32, apic_id) << 24);
|
||||
xapic_write(.Icr, 0x0000C500);
|
||||
while (xapic_read(.Icr) & (1 << 12) != 0) {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_sipi(apic_id: u32, startup_page: u8) void {
|
||||
if (in_x2apic_mode) {
|
||||
x2apic_write(.Icr, (@as(u64, apic_id) << 32) | 0x00004600 | startup_page);
|
||||
} else {
|
||||
xapic_write(.Icr1, @as(u32, apic_id) << 24);
|
||||
xapic_write(.Icr, @as(u32, 0x00004600) | startup_page);
|
||||
while (xapic_read(.Icr) & (1 << 12) != 0) {}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if (in_x2apic_mode) {
|
||||
x2apic_write(.Icr, icr_value);
|
||||
} else {
|
||||
// Write to ICR1 first, because writing to the low word causes
|
||||
// the IPI to be sent.
|
||||
xapic_write(.Icr1, @as(u32, apic_id) << 24);
|
||||
xapic_write(.Icr, @intCast(icr_value));
|
||||
|
||||
// Wait for the delivery status bit to clear.
|
||||
while (xapic_read(.Icr) & (1 << 12) != 0) {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init() linksection(b.init) void {
|
||||
var iter = acpi.madt.iterator();
|
||||
|
||||
const cur_cpu_id = get_id();
|
||||
|
||||
// First, we iterate to check if we find *any* APICs. If we do, then we must use them over x2APIC entries for IDs under 255.
|
||||
var has_lapics = false;
|
||||
while (iter.next()) |entry| {
|
||||
switch (entry.type) {
|
||||
.LocalApic => {
|
||||
const lapic: *const MadtLapic = @ptrCast(entry);
|
||||
if (lapic.flags & 1 == 0 or lapic.id == cur_cpu_id) continue;
|
||||
has_lapics = true;
|
||||
break;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
// Now, actually iterate and add the APIC IDs to the list.
|
||||
iter = acpi.madt.iterator();
|
||||
|
||||
while (iter.next()) |entry| {
|
||||
switch (entry.type) {
|
||||
.LocalApic => {
|
||||
const lapic: *const MadtLapic = @ptrCast(entry);
|
||||
if (lapic.flags & 1 == 0 or lapic.id == cur_cpu_id) continue;
|
||||
apics.append(mm.zone.gpa, lapic.id) catch @panic("Could not append APIC ID to list");
|
||||
},
|
||||
.X2LocalApic => {
|
||||
const x2lapic: *const MadtX2Lapic = @ptrCast(entry);
|
||||
if (has_lapics and x2lapic.id <= 0xFF) continue;
|
||||
if (x2lapic.flags & 1 == 0 or x2lapic.id == cur_cpu_id) continue;
|
||||
apics.append(mm.zone.gpa, x2lapic.id) catch @panic("Could not append APIC ID to list");
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
// If in xapic mode, set the xapic base address.
|
||||
const base = amd64.read_msr(.LapicBase);
|
||||
|
||||
if (base & (1 << 10) == 0) {
|
||||
xapic_address = mm.p2v(base & 0xFFFFF000);
|
||||
xapic_base_physical = base & 0xFFFFF000;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enter_x2apic() void {
|
||||
if (in_x2apic_mode) return;
|
||||
|
||||
const apic_base = amd64.read_msr(.LapicBase);
|
||||
amd64.wrmsr(.LapicBase, apic_base | (1 << 10) | (1 << 11));
|
||||
}
|
||||
Reference in New Issue
Block a user