[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:
parent
c645405ca8
commit
f26fd73116
21 changed files with 371 additions and 124 deletions
|
|
@ -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*,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue