Skip to content

Commit

Permalink
Some changes, improve apic/acpi and start pit
Browse files Browse the repository at this point in the history
  • Loading branch information
Ratakor committed Oct 4, 2023
1 parent 9a5b572 commit 3936fed
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 150 deletions.
97 changes: 45 additions & 52 deletions kernel/acpi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ const root = @import("root");
const vmm = @import("vmm.zig");
const apic = @import("apic.zig");
const log = std.log.scoped(.acpi);

const readIntNative = std.mem.readIntNative;

/// System Description Table
const SDT = extern struct {
signature: [4]u8,
length: u32,
Expand All @@ -23,6 +23,7 @@ const SDT = extern struct {
}
};

/// Root System Description Pointer
const RSDP = extern struct {
signature: [8]u8,
checksum: u8,
Expand All @@ -45,66 +46,58 @@ pub fn init() void {
log.info("revision: {}", .{rsdp.revision});
log.info("uses XSDT: {}", .{rsdp.useXSDT()});

switch (rsdp.revision) {
0 => parse(u32, @intCast(rsdp.rsdt_addr)),
2 => parse(u64, rsdp.xsdt_addr),
else => unreachable,
if (rsdp.useXSDT()) {
parse(u64, rsdp.xsdt_addr);
} else {
parse(u32, @intCast(rsdp.rsdt_addr));
}
}

fn parse(comptime T: type, addr: u64) void {
const sdt: *SDT = @ptrFromInt(addr + vmm.higher_half);
const entries = std.mem.bytesAsSlice(T, sdt.data());
const rsdt: *SDT = @ptrFromInt(addr + vmm.higher_half);

log.info("RSDT is at 0x{x}", .{@intFromPtr(sdt)});
var sum: u8 = 0;
for (0..rsdt.length) |i| {
sum +%= @as([*]u8, @ptrCast(rsdt))[i];
}
if (sum != 0) {
std.debug.panic("RSDT is invalid: sum = {}", .{sum});
}

log.info("RSDT is at 0x{x}", .{@intFromPtr(rsdt)});

const entries = std.mem.bytesAsSlice(T, rsdt.data());
for (entries) |entry| {
handleTable(@ptrFromInt(entry + vmm.higher_half));
const sdt: *const SDT = @ptrFromInt(entry + vmm.higher_half);

switch (readIntNative(u32, &sdt.signature)) {
readIntNative(u32, "APIC") => handleMADT(sdt),
else => log.warn("unhandled ACPI table: {s}", .{sdt.signature}),
}
}
}

fn handleTable(sdt: *const SDT) void {
switch (readIntNative(u32, sdt.signature[0..4])) {
readIntNative(u32, "APIC") => {
var data = sdt.data()[8..];

while (data.len >= 2) {
const kind = data[0];
const size = data[1];

if (size >= data.len) break;

const record_data = data[2..size];
switch (kind) {
0 => {}, // TODO: find about this
1 => apic.handleIOAPIC(
record_data[0],
readIntNative(u32, record_data[2..6]),
readIntNative(u32, record_data[6..10]),
),
2 => apic.handleIOAPICISO(
record_data[0],
record_data[1],
readIntNative(u32, record_data[2..6]),
readIntNative(u16, record_data[6..8]),
),
3 => log.debug("unhandled IO/APIC NMI source: {any}", .{record_data}),
4 => log.debug("unhandled LAPIC NMI: {any}", .{record_data}),
5 => log.debug("unhandled LAPIC Address Override: {any}", .{record_data}),
9 => log.debug("unhandled x2LAPIC: {any}", .{record_data}),
else => log.warn("unknown MADT record 0x{x}: {any}", .{ kind, record_data }),
}

data = data[@max(2, size)..];
}
},
// TODO:
// readIntNative(u32, "FACP") => {
// const fadt_flags = @as([*]const u32, @ptrCast(sdt))[28];
// if (fadt_flags & (1 << 20) != 0) {
// @panic("Ubik does not support HW reduced ACPI systems");
// }
// },
else => log.debug("unhandled ACPI table: {s}", .{sdt.signature}),
fn handleMADT(madt: *const SDT) void {
var data = madt.data()[8..]; // discard madt header

while (data.len > 2) {
const kind = data[0];
const size = data[1];

if (size >= data.len) break;

const entry = data[2..size];
switch (kind) {
0 => log.warn("unhandled LAPIC: {any}", .{entry}),
1 => apic.io_apics.append(@ptrCast(entry)) catch unreachable,
2 => apic.isos.append(@ptrCast(entry)) catch unreachable,
3 => log.warn("unhandled IO/APIC NMI source: {any}", .{entry}),
4 => log.warn("unhandled LAPIC NMI: {any}", .{entry}),
5 => log.warn("unhandled LAPIC Address Override: {any}", .{entry}),
9 => log.warn("unhandled x2LAPIC: {any}", .{entry}),
else => unreachable,
}

data = data[@max(2, size)..];
}
}
130 changes: 50 additions & 80 deletions kernel/apic.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const std = @import("std");
const root = @import("root");
const vmm = @import("vmm.zig");
const cpu = @import("cpu.zig");
const idt = @import("idt.zig");
Expand All @@ -18,9 +19,12 @@ const Register = enum(u64) {
timer_divide = 0x3e0,
};

const IOAPIC = struct {
addr: u32,
base_gsi: u32,
/// Input/Output Advanced Programmable Interrupt Controller
const IOAPIC = extern struct {
apic_id: u8 align(1),
reserved: u8 align(1),
addr: u32 align(1),
base_gsi: u32 align(1),

const Self = @This();

Expand All @@ -39,37 +43,18 @@ const IOAPIC = struct {
fn gsiCount(self: Self) u32 {
return (self.read(1) & 0xff0000) >> 16;
}

fn setGSIRedirect(self: Self, gsi: u32, lapic_id: u32, vector: u8, flags: u16) void {
var redirect: u64 = vector;
if ((flags & (1 << 1)) != 0) {
redirect |= (1 << 13);
}

if ((flags & (1 << 3)) != 0) {
redirect |= (1 << 15);
}

// redirect |= @as(u64, @intCast(flags & 0b1010)) << 12;
redirect |= @as(u64, @intCast(lapic_id)) << 56;

const io_redirect_table = 0x10 + (gsi - self.base_gsi) * 2;
self.write(io_redirect_table, @truncate(redirect));
self.write(io_redirect_table + 1, @truncate(redirect >> 32));
}
};

// TODO
const SourceOverride = struct {
ioapic_id: u8,
gsi: u32,
flags: u16,
/// Interrupt Source Override
const ISO = extern struct {
bus_source: u8 align(1),
irq_source: u8 align(1),
gsi: u32 align(1),
flags: u16 align(1),
};

// var time_vector: u8 = undefined;
// var one_shot_vector: u8 = undefined;
var io_apics = [1]?IOAPIC{null} ** 16;
var source_overrides = [1]?SourceOverride{null} ** 256;
pub var io_apics = std.ArrayList(*const IOAPIC).init(root.allocator);
pub var isos = std.ArrayList(*const ISO).init(root.allocator);

pub fn init() void {
// timerCalibrate();
Expand All @@ -96,10 +81,6 @@ pub fn eoi() void {
writeRegister(.eoi, 0);
}

pub fn localApicId() u32 {
return readRegister(.lapic_id);
}

// TODO
// pub fn timerOneShot(us: u64, vector: u8) void {
// _ = us;
Expand All @@ -115,15 +96,15 @@ pub fn localApicId() u32 {
// // interrupt_toggle(old_int_state);
// }

// pub fn timerStop() void {
// writeRegister(.timer_initial_count, 0);
// writeRegister(.lvt_timer, 1 << 16);
// }
pub fn timerStop() void {
writeRegister(.timer_initial_count, 0);
writeRegister(.lvt_timer, 1 << 16);
}

// pub fn sendIPI(lapic_id: u32, vec: u32) void {
// writeRegister(.icr1, lapic_id << 24);
// writeRegister(.icr0, vec);
// }
pub fn sendIPI(lapic_id: u32, vec: u32) void {
writeRegister(.icr1, lapic_id << 24);
writeRegister(.icr0, vec);
}

// pub fn timerCalibrate() void {
// timerStop();
Expand All @@ -132,15 +113,15 @@ pub fn localApicId() u32 {
// writeRegister(.lvt_timer, (1 << 16) | 0xff); // vector 0xff, masked
// writeRegister(.timer_divide, 0);

// // pit_set_reload_value(0xffff); // Reset PIT
// // pit.setReloadValue(0xffff); // reset PIT

// const samples = 0xfffff;
// // const initial_tick = pit_get_current_count();

// writeRegister(.timer_initial_count, samples);
// while (readRegister(.timer_current_count) != 0) {}

// // const final_tick = pit_get_current_count();
// // const final_tick = pit.getCurrentCount();

// // const total_ticks = initial_tick - final_tick;
// // this_cpu().lapic_freq = (samples / total_ticks) * PIT_DIVIDEND;
Expand All @@ -159,49 +140,38 @@ fn writeRegister(register: Register, val: u32) void {
ptr.* = val;
}

pub fn handleIOAPIC(id: u8, addr: u32, base_gsi: u32) void {
std.debug.assert(io_apics[id] == null);

io_apics[id] = .{
.addr = addr,
.base_gsi = base_gsi,
};
}

pub fn handleIOAPICISO(ioapic_id: u8, irq_source: u8, gsi: u32, flags: u16) void {
std.debug.assert(source_overrides[irq_source] == null);

source_overrides[irq_source] = .{
.ioapic_id = ioapic_id,
.gsi = gsi,
.flags = flags,
fn setGSIRedirect(lapic_id: u32, vector: u8, gsi: u8, flags: u16) void {
const io_apic = for (io_apics.items) |io_apic| {
if (gsi >= io_apic.base_gsi and gsi < io_apic.base_gsi + io_apic.gsiCount()) {
break io_apic;
}
} else {
std.debug.panic("could not find an IOAPIC for GSI {}", .{gsi});
};
}

fn mapIRQtoGSI(irq: u8) SourceOverride {
return source_overrides[irq] orelse .{
.ioapic_id = mapGSItoIOAPIC(irq),
.gsi = irq,
.flags = 0,
};
}
var redirect: u64 = vector;
if ((flags & (1 << 1)) != 0) {
redirect |= (1 << 13);
}

fn mapGSItoIOAPIC(gsi: u32) u8 {
for (io_apics, 0..) |io_apic, i| {
if (io_apic) |ioa| {
if (gsi >= ioa.base_gsi and gsi < ioa.base_gsi + ioa.gsiCount()) {
return @intCast(i);
}
}
if ((flags & (1 << 3)) != 0) {
redirect |= (1 << 15);
}

std.debug.panic("could not find an IOAPIC for GSI {}", .{gsi});
redirect |= @as(u64, @intCast(lapic_id)) << 56;

const io_redirect_table = 0x10 + (gsi - io_apic.base_gsi) * 2;
io_apic.write(io_redirect_table, @truncate(redirect));
io_apic.write(io_redirect_table + 1, @truncate(redirect >> 32));
}

pub fn setIRQRedirect(lapic_id: u32, vector: u8, irq: u8) void {
const gsi = mapIRQtoGSI(irq);
const ioapic_id = mapGSItoIOAPIC(gsi.gsi);
const ioapic = io_apics[ioapic_id].?;
for (isos.items) |iso| {
if (iso.irq_source == irq) {
setGSIRedirect(lapic_id, vector, @intCast(iso.gsi), iso.flags);
return;
}
}

ioapic.setGSIRedirect(gsi.gsi, lapic_id, vector, gsi.flags);
setGSIRedirect(lapic_id, vector, irq, 0);
}
12 changes: 10 additions & 2 deletions kernel/cpu.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const std = @import("std");
const root = @import("root");
const SpinLock = @import("lock.zig").SpinLock;
const log = std.log.scoped(.cpu);

// TODO: defined elsewhere
pub const Thread = struct {};
Expand Down Expand Up @@ -31,6 +33,7 @@ pub const Context = extern struct {
ss: u64,
};

/// Task State Segment
pub const TSS = extern struct {
reserved0: u32 align(1) = 0,
rsp: [3]u64 align(1),
Expand All @@ -56,7 +59,7 @@ pub const CpuLocal = struct {
};

pub var sysenter: bool = false;
pub var bsp_lapic_id: u32 = undefined;
pub var bsp_lapic_id: u32 = undefined; // TODO: x86 specific
pub var smp_started: bool = undefined;

pub var cpus: []CpuLocal = undefined;
Expand All @@ -67,6 +70,11 @@ pub var fpu_storage_size: usize = 0;

pub var cpu_count: usize = undefined;

pub fn init() void {}
pub fn init() void {
const smp = root.smp_request.response.?;
bsp_lapic_id = smp.bsp_lapic_id;
cpu_count = smp.cpu_count;
log.info("{} processors detected", .{cpu_count});
}

// TODO: a lot of functions with inline assembly
1 change: 1 addition & 0 deletions kernel/gdt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const TSSDescriptor = packed struct {
reserved: u32 = 0,
};

/// Global Descriptor Table
const GDT = extern struct {
null_entry: GDTEntry align(8),
kernel_code: GDTEntry align(8),
Expand Down
17 changes: 9 additions & 8 deletions kernel/idt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ const trap_gate = 0b1000_1111;
const InterruptStub = *const fn () callconv(.Naked) void;
pub const InterruptHandler = *const fn (ctx: *cpu.Context) void;

const IDTEntry = packed struct {
offset_low: u16,
selector: u16,
ist: u8,
type_attributes: u8,
offset_mid: u16,
offset_high: u32,
reserved: u32,
/// Interrupt Descriptor Table Entry
const IDTEntry = extern struct {
offset_low: u16 align(1),
selector: u16 align(1),
ist: u8 align(1),
type_attributes: u8 align(1),
offset_mid: u16 align(1),
offset_high: u32 align(1),
reserved: u32 align(1),

fn init(handler: u64, ist: u8, attributes: u8) IDTEntry {
return .{
Expand Down
Loading

0 comments on commit 3936fed

Please sign in to comment.