[Zion][Denali] Move to MSI for AHCI devices.

This will allow us to properly do interrupts for XHCI devices in the
future.

Also move PCI device header parsing to a shared library.

Get rid of the old irq register format which supplied an irq number and
instead pass the appropriate irq number back out to the caller.
This commit is contained in:
Drew Galbraith 2025-05-05 23:13:59 -07:00
parent c645405ca8
commit f26fd73116
21 changed files with 371 additions and 124 deletions

View file

@ -48,7 +48,7 @@ SYS5(PortRecv, z_cap_t, port_cap, uint64_t*, num_bytes, void*, data, uint64_t*,
SYS5(PortPoll, z_cap_t, port_cap, uint64_t*, num_bytes, void*, data, uint64_t*,
num_caps, z_cap_t*, caps);
SYS2(IrqRegister, uint64_t, irq_num, z_cap_t*, port_cap);
SYS2(MsiIrqRegister, uint64_t*, irq_num, z_cap_t*, port_cap);
SYS1(EndpointCreate, z_cap_t*, endpoint_cap);
SYS6(EndpointSend, z_cap_t, endpoint_cap, uint64_t, num_bytes, const void*,

View file

@ -43,7 +43,7 @@ const uint64_t kZionPortSend = 0x51;
const uint64_t kZionPortRecv = 0x52;
const uint64_t kZionPortPoll = 0x53;
const uint64_t kZionIrqRegister = 0x58;
const uint64_t kZionMsiIrqRegister = 0x59;
const uint64_t kZionEndpointCreate = 0x60;
const uint64_t kZionEndpointSend = 0x61;

View file

@ -136,23 +136,6 @@ Apic::Apic(const ApicConfiguration& config)
// FIXME: Get this offset from ACPI.
SetIoDoubleReg(0x14, 0x20 | APIC_MASK);
// Map Keyboard
SetIoDoubleReg(0x12, 0x22);
// For now set these based on the presets in the following spec.
// http://web.archive.org/web/20161130153145/http://download.intel.com/design/chipsets/datashts/29056601.pdf
// FIXME: However in the future we should likely use the MADT for legacy
// interrupts and AML for PCI etc.
// PCI Line 1-4
// FIXME: These should be level triggered according to spec I believe
// but because we handle the interrupt outside of the kernel it is tricky
// to wait to send the end of interrupt message.
// Because of this leave them as edge triggered and send EOI immediately.
SetIoDoubleReg(0x30, 0x30);
SetIoDoubleReg(0x32, 0x31);
SetIoDoubleReg(0x34, 0x32);
SetIoDoubleReg(0x36, 0x33);
DumpInfo();
}

View file

@ -9,18 +9,24 @@ DriverManager& DriverManager::Get() { return *gDriverManager; }
DriverManager::DriverManager() { gDriverManager = this; }
void DriverManager::WriteMessage(uint64_t irq_num, IpcMessage&& message) {
if (!driver_map_.Contains(irq_num)) {
if (irq_num < IRQ_OFFSET) {
dbgln("WARN IRQ {x} below min offset {x}", irq_num, IRQ_OFFSET);
}
uint64_t offset = irq_num - IRQ_OFFSET;
if (offset >= driver_list_.size()) {
dbgln("WARN IRQ for {x} with no registered driver", irq_num);
return;
}
driver_map_.at(irq_num)->Send(glcr::Move(message));
driver_list_[offset]->Send(glcr::Move(message));
}
glcr::ErrorCode DriverManager::RegisterListener(uint64_t irq_num,
glcr::RefPtr<Port> port) {
if (driver_map_.Contains(irq_num)) {
return glcr::ALREADY_EXISTS;
glcr::ErrorOr<uint8_t> DriverManager::RegisterListener(
glcr::RefPtr<Port> port) {
if (driver_list_.size() + IRQ_OFFSET >= 0xFF) {
return glcr::EXHAUSTED;
}
return driver_map_.Insert(irq_num, port);
uint8_t offset = (driver_list_.size() + IRQ_OFFSET);
driver_list_.PushBack(port);
return offset;
}

View file

@ -15,9 +15,10 @@ class DriverManager {
void WriteMessage(uint64_t irq_num, IpcMessage&& message);
[[nodiscard]] glcr::ErrorCode RegisterListener(uint64_t irq_num,
glcr::RefPtr<Port> port);
[[nodiscard]] glcr::ErrorOr<uint8_t> RegisterListener(
glcr::RefPtr<Port> port);
private:
glcr::HashMap<uint64_t, glcr::RefPtr<Port>> driver_map_;
const uint64_t IRQ_OFFSET = 0x60;
glcr::Vector<glcr::RefPtr<Port>> driver_list_;
};

View file

@ -109,7 +109,7 @@ extern "C" void interrupt_protection_fault(InterruptFrame* frame) {
} else {
dbgln("GDT");
}
dbgln("Index: {}", err >> 3);
dbgln("Index: {} ({x})", err >> 3, err >> 3);
dbgln("RIP: {x}", frame->rip);
dbgln("RAX: {x}, RBX: {x}, RCX: {x}, RDX: {x}", frame->rax, frame->rbx,
frame->rcx, frame->rdx);
@ -197,40 +197,27 @@ extern "C" void interrupt_apic_timer(InterruptFrame*) {
gScheduler->Preempt();
}
extern "C" void isr_keyboard();
extern "C" void interrupt_keyboard(InterruptFrame*) {
glcr::Array<uint8_t> data(1);
data[0] = inb(0x60);
IpcMessage msg{.data = glcr::Move(data)};
DriverManager::Get().WriteMessage(kZIrqKbd, glcr::Move(msg));
extern "C" void isr_60();
extern "C" void interrupt_60(InterruptFrame*) {
DriverManager::Get().WriteMessage(0x60, {});
gApic->SignalEOI();
}
extern "C" void isr_pci1();
extern "C" void interrupt_pci1(InterruptFrame*) {
DriverManager::Get().WriteMessage(kZIrqPci1, {});
extern "C" void isr_61();
extern "C" void interrupt_61(InterruptFrame*) {
DriverManager::Get().WriteMessage(0x61, {});
gApic->SignalEOI();
}
extern "C" void isr_pci2();
extern "C" void interrupt_pci2(InterruptFrame*) {
DriverManager::Get().WriteMessage(kZIrqPci2, {});
dbgln("Interrupt PCI line 2");
extern "C" void isr_62();
extern "C" void interrupt_62(InterruptFrame*) {
DriverManager::Get().WriteMessage(0x62, {});
gApic->SignalEOI();
}
extern "C" void isr_pci3();
extern "C" void interrupt_pci3(InterruptFrame*) {
DriverManager::Get().WriteMessage(kZIrqPci3, {});
dbgln("Interrupt PCI line 3");
gApic->SignalEOI();
}
extern "C" void isr_pci4();
extern "C" void interrupt_pci4(InterruptFrame*) {
DriverManager::Get().WriteMessage(kZIrqPci4, {});
dbgln("Interrupt PCI line 4");
extern "C" void isr_63();
extern "C" void interrupt_63(InterruptFrame*) {
DriverManager::Get().WriteMessage(0x63, {});
gApic->SignalEOI();
}
@ -243,12 +230,11 @@ void InitIdt() {
gIdt[0x20] = CreateDescriptor(isr_timer);
gIdt[0x21] = CreateDescriptor(isr_apic_timer);
gIdt[0x22] = CreateDescriptor(isr_keyboard);
gIdt[0x30] = CreateDescriptor(isr_pci1);
gIdt[0x31] = CreateDescriptor(isr_pci2);
gIdt[0x32] = CreateDescriptor(isr_pci3);
gIdt[0x33] = CreateDescriptor(isr_pci4);
gIdt[0x60] = CreateDescriptor(isr_60);
gIdt[0x61] = CreateDescriptor(isr_61);
gIdt[0x62] = CreateDescriptor(isr_62);
gIdt[0x63] = CreateDescriptor(isr_63);
InterruptDescriptorTablePointer idtp{
.size = sizeof(gIdt),

View file

@ -63,10 +63,8 @@ isr_handler fpe_fault
isr_handler timer
isr_handler apic_timer
isr_handler keyboard
isr_handler pci1
isr_handler pci2
isr_handler pci3
isr_handler pci4
isr_handler 60
isr_handler 61
isr_handler 62
isr_handler 63

View file

@ -156,13 +156,14 @@ glcr::ErrorCode PortPoll(ZPortPollReq* req) {
return TranslateIpcMessageToResponse(msg, req);
}
glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req) {
glcr::ErrorCode MsiIrqRegister(ZMsiIrqRegisterReq* req) {
auto& proc = gScheduler->CurrentProcess();
glcr::RefPtr<Port> port = glcr::MakeRefCounted<Port>();
*req->port_cap = proc.AddNewCapability(port);
return DriverManager::Get().RegisterListener(req->irq_num, port);
ASSIGN_OR_RETURN(*req->irq_num, DriverManager::Get().RegisterListener(port));
return glcr::OK;
}
glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req) {

View file

@ -12,7 +12,7 @@ glcr::ErrorCode PortCreate(ZPortCreateReq* req);
glcr::ErrorCode PortSend(ZPortSendReq* req);
glcr::ErrorCode PortRecv(ZPortRecvReq* req);
glcr::ErrorCode PortPoll(ZPortPollReq* req);
glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req);
glcr::ErrorCode MsiIrqRegister(ZMsiIrqRegisterReq* req);
glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req);
glcr::ErrorCode EndpointSend(ZEndpointSendReq* req);

View file

@ -77,7 +77,7 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) {
CASE(PortSend);
CASE(PortRecv);
CASE(PortPoll);
CASE(IrqRegister);
CASE(MsiIrqRegister);
CASE(EndpointCreate);
CASE(EndpointSend);
CASE(EndpointRecv);