[Zion] Add a keyboard interrupt handler and a driver manager.
This commit is contained in:
		
							parent
							
								
									d9a936db09
								
							
						
					
					
						commit
						838ef01a2a
					
				|  | @ -183,7 +183,22 @@ glcr::ErrorCode AhciDriver::RegisterIrq() { | |||
|   if (pci_device_header_->interrupt_pin == 0) { | ||||
|     crash("Can't register IRQ without a pin num", glcr::INVALID_ARGUMENT); | ||||
|   } | ||||
|   uint64_t irq_num = Z_IRQ_PCI_BASE + pci_device_header_->interrupt_pin - 1; | ||||
|   uint64_t irq_num = 0; | ||||
|   switch (pci_device_header_->interrupt_pin) { | ||||
|     case 1: | ||||
|       irq_num = kZIrqPci1; | ||||
|       break; | ||||
|     case 2: | ||||
|       irq_num = kZIrqPci2; | ||||
|       break; | ||||
|     case 3: | ||||
|       irq_num = kZIrqPci3; | ||||
|       break; | ||||
|     case 4: | ||||
|       irq_num = kZIrqPci4; | ||||
|       break; | ||||
|   } | ||||
| 
 | ||||
|   RET_ERR(ZIrqRegister(irq_num, &irq_port_cap_)); | ||||
|   irq_thread_ = Thread(interrupt_thread, this); | ||||
|   ahci_hba_->global_host_control |= kGhc_InteruptEnable; | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ add_executable(zion | |||
|   debug/debug.cpp | ||||
|   interrupt/apic.cpp | ||||
|   interrupt/apic_timer.cpp | ||||
|   interrupt/driver_manager.cpp | ||||
|   interrupt/interrupt.cpp | ||||
|   interrupt/interrupt_enter.s | ||||
|   interrupt/timer.cpp | ||||
|  |  | |||
|  | @ -146,8 +146,8 @@ void ParseMadt(SdtHeader* rsdt) { | |||
|   MadtHeader* header = reinterpret_cast<MadtHeader*>(rsdt); | ||||
| 
 | ||||
| #if K_ACPI_DEBUG | ||||
|   dbgln("Local APIC {x}", header->local_apic_address); | ||||
|   dbgln("Flags: {x}", header->flags); | ||||
|   dbgln("Local APIC {x}", +header->local_apic_address); | ||||
|   dbgln("Flags: {x}", +header->flags); | ||||
| #endif | ||||
| 
 | ||||
|   gLApicBase = header->local_apic_address; | ||||
|  | @ -160,7 +160,7 @@ void ParseMadt(SdtHeader* rsdt) { | |||
|         MadtLocalApic* local = reinterpret_cast<MadtLocalApic*>(entry); | ||||
| #if K_ACPI_DEBUG | ||||
|         dbgln("Local APIC (Proc id, id, flags): {x}, {x}, {x}", | ||||
|               local->processor_id, local->apic_id, local->flags); | ||||
|               local->processor_id, local->apic_id, +local->flags); | ||||
| #endif | ||||
|         break; | ||||
|       } | ||||
|  | @ -168,7 +168,7 @@ void ParseMadt(SdtHeader* rsdt) { | |||
|         MadtIoApic* io = reinterpret_cast<MadtIoApic*>(entry); | ||||
| #if K_ACPI_DEBUG | ||||
|         dbgln("IO Apic (id, addr, gsi base): {x}, {x}, {x}", io->io_apic_id, | ||||
|               io->io_apic_address, io->global_system_interrupt_base); | ||||
|               +io->io_apic_address, +io->global_system_interrupt_base); | ||||
| #endif | ||||
|         if (gIOApicBase != 0) { | ||||
|           dbgln("More than one IOApic, unhandled"); | ||||
|  | @ -181,8 +181,8 @@ void ParseMadt(SdtHeader* rsdt) { | |||
|             reinterpret_cast<MadtIoApicInterruptSource*>(entry); | ||||
| #if K_ACPI_DEBUG | ||||
|         dbgln("IO Source (Bus, IRQ, GSI, flags): {x}, {x}, {x}, {x}", | ||||
|               src->bus_source, src->irq_source, src->global_system_interrupt, | ||||
|               src->flags); | ||||
|               src->bus_source, src->irq_source, +src->global_system_interrupt, | ||||
|               +src->flags); | ||||
| #endif | ||||
|         break; | ||||
|       } | ||||
|  | @ -191,7 +191,7 @@ void ParseMadt(SdtHeader* rsdt) { | |||
|             reinterpret_cast<MadtLocalApicNonMaskable*>(entry); | ||||
| #if K_ACPI_DEBUG | ||||
|         dbgln("Local NMI (proc id, flags, lint#): {x}, {x}, {x}", | ||||
|               lnmi->apic_processor_id, lnmi->flags, lnmi->lint_num); | ||||
|               lnmi->apic_processor_id, +lnmi->flags, lnmi->lint_num); | ||||
| #endif | ||||
|         break; | ||||
|       } | ||||
|  | @ -254,7 +254,7 @@ void ProbeRsdp() { | |||
| 
 | ||||
| #if K_ACPI_DEBUG | ||||
|   dbgln("ACPI Ver {}", rsdp->revision); | ||||
|   dbgln("RSDT Addr: {x}", rsdp->rsdt_addr); | ||||
|   dbgln("RSDT Addr: {x}", +rsdp->rsdt_addr); | ||||
| #endif | ||||
| 
 | ||||
|   ProbeRsdt(reinterpret_cast<SdtHeader*>(rsdp->rsdt_addr)); | ||||
|  | @ -270,7 +270,7 @@ void ProbeRsdp() { | |||
|   } | ||||
| 
 | ||||
| #if K_ACPI_DEBUG | ||||
|   dbgln("XSDT Addr: {x}", rsdp->xsdt_addr); | ||||
|   dbgln("XSDT Addr: {x}", +rsdp->xsdt_addr); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -50,8 +50,6 @@ const uint64_t kZionReplyPortSend = 0x63; | |||
| const uint64_t kZionReplyPortRecv = 0x64; | ||||
| const uint64_t kZionEndpointCall = 0x65; | ||||
| 
 | ||||
| #define Z_IRQ_PCI_BASE 0x30 | ||||
| 
 | ||||
| // Capability Calls
 | ||||
| const uint64_t kZionCapDuplicate = 0x70; | ||||
| const uint64_t kZionCapRelease = 0x71; | ||||
|  | @ -67,6 +65,13 @@ const uint64_t kZionSemaphoreSignal = 0x85; | |||
| // Debugging Calls.
 | ||||
| const uint64_t kZionDebug = 0x1'0000; | ||||
| 
 | ||||
| // Irq Types
 | ||||
| const uint64_t kZIrqKbd = 0x22; | ||||
| const uint64_t kZIrqPci1 = 0x30; | ||||
| const uint64_t kZIrqPci2 = 0x31; | ||||
| const uint64_t kZIrqPci3 = 0x32; | ||||
| const uint64_t kZIrqPci4 = 0x33; | ||||
| 
 | ||||
| /* ------------------------------
 | ||||
|  * Capability Types | ||||
|  * ------------------------------*/ | ||||
|  |  | |||
|  | @ -136,6 +136,9 @@ 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
 | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| #include "interrupt/driver_manager.h" | ||||
| 
 | ||||
| #include "debug/debug.h" | ||||
| 
 | ||||
| DriverManager* gDriverManager = nullptr; | ||||
| 
 | ||||
| DriverManager& DriverManager::Get() { return *gDriverManager; } | ||||
| 
 | ||||
| DriverManager::DriverManager() { gDriverManager = this; } | ||||
| 
 | ||||
| void DriverManager::WriteMessage(uint64_t irq_num, IpcMessage&& message) { | ||||
|   if (!driver_map_.Contains(irq_num)) { | ||||
|     dbgln("WARN IRQ for {x} with no registered driver", irq_num); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   driver_map_.at(irq_num)->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; | ||||
|   } | ||||
|   return driver_map_.Insert(irq_num, port); | ||||
| } | ||||
|  | @ -0,0 +1,22 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <glacier/container/hash_map.h> | ||||
| #include <glacier/memory/ref_ptr.h> | ||||
| 
 | ||||
| #include "object/port.h" | ||||
| 
 | ||||
| class DriverManager { | ||||
|  public: | ||||
|   static DriverManager& Get(); | ||||
| 
 | ||||
|   DriverManager(); | ||||
|   DriverManager(const DriverManager&) = delete; | ||||
|   DriverManager(DriverManager&&) = delete; | ||||
| 
 | ||||
|   void WriteMessage(uint64_t irq_num, IpcMessage&& message); | ||||
| 
 | ||||
|   glcr::ErrorCode RegisterListener(uint64_t irq_num, glcr::RefPtr<Port> port); | ||||
| 
 | ||||
|  private: | ||||
|   glcr::HashMap<uint64_t, glcr::RefPtr<Port>> driver_map_; | ||||
| }; | ||||
|  | @ -7,6 +7,7 @@ | |||
| #include "debug/debug.h" | ||||
| #include "interrupt/apic.h" | ||||
| #include "interrupt/apic_timer.h" | ||||
| #include "interrupt/driver_manager.h" | ||||
| #include "memory/kernel_heap.h" | ||||
| #include "memory/physical_memory.h" | ||||
| #include "scheduler/scheduler.h" | ||||
|  | @ -196,27 +197,39 @@ extern "C" void interrupt_apic_timer(InterruptFrame*) { | |||
|   gScheduler->Preempt(); | ||||
| } | ||||
| 
 | ||||
| glcr::RefPtr<Port> pci1_port; | ||||
| 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)); | ||||
| 
 | ||||
|   gApic->SignalEOI(); | ||||
| } | ||||
| 
 | ||||
| extern "C" void isr_pci1(); | ||||
| extern "C" void interrupt_pci1(InterruptFrame*) { | ||||
|   pci1_port->Send({}); | ||||
|   DriverManager::Get().WriteMessage(kZIrqPci1, {}); | ||||
|   gApic->SignalEOI(); | ||||
| } | ||||
| 
 | ||||
| extern "C" void isr_pci2(); | ||||
| extern "C" void interrupt_pci2(InterruptFrame*) { | ||||
|   DriverManager::Get().WriteMessage(kZIrqPci2, {}); | ||||
|   dbgln("Interrupt PCI line 2"); | ||||
|   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"); | ||||
|   gApic->SignalEOI(); | ||||
| } | ||||
|  | @ -230,6 +243,7 @@ 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); | ||||
|  | @ -253,5 +267,3 @@ void UpdateFaultHandlersToIst1() { | |||
|   }; | ||||
|   asm volatile("lidt %0" ::"m"(idtp)); | ||||
| } | ||||
| 
 | ||||
| void RegisterPciPort(const glcr::RefPtr<Port>& port) { pci1_port = port; } | ||||
|  |  | |||
|  | @ -7,5 +7,3 @@ | |||
| void InitIdt(); | ||||
| 
 | ||||
| void UpdateFaultHandlersToIst1(); | ||||
| 
 | ||||
| void RegisterPciPort(const glcr::RefPtr<Port>& port); | ||||
|  |  | |||
|  | @ -63,6 +63,7 @@ isr_handler fpe_fault | |||
| 
 | ||||
| isr_handler timer | ||||
| isr_handler apic_timer | ||||
| isr_handler keyboard | ||||
| 
 | ||||
| isr_handler pci1 | ||||
| isr_handler pci2 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| 
 | ||||
| #include "capability/capability.h" | ||||
| #include "debug/debug.h" | ||||
| #include "interrupt/driver_manager.h" | ||||
| #include "interrupt/interrupt.h" | ||||
| #include "object/endpoint.h" | ||||
| #include "object/reply_port.h" | ||||
|  | @ -157,13 +158,10 @@ glcr::ErrorCode PortPoll(ZPortPollReq* req) { | |||
| 
 | ||||
| glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req) { | ||||
|   auto& proc = gScheduler->CurrentProcess(); | ||||
|   if (req->irq_num != Z_IRQ_PCI_BASE) { | ||||
|     // FIXME: Don't hardcode this nonsense.
 | ||||
|     return glcr::UNIMPLEMENTED; | ||||
|   } | ||||
| 
 | ||||
|   glcr::RefPtr<Port> port = glcr::MakeRefCounted<Port>(); | ||||
|   *req->port_cap = proc.AddNewCapability(port); | ||||
|   RegisterPciPort(port); | ||||
|   DriverManager::Get().RegisterListener(req->irq_num, port); | ||||
|   return glcr::OK; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ | |||
| #include "debug/debug.h" | ||||
| #include "interrupt/apic.h" | ||||
| #include "interrupt/apic_timer.h" | ||||
| #include "interrupt/driver_manager.h" | ||||
| #include "interrupt/interrupt.h" | ||||
| #include "interrupt/timer.h" | ||||
| #include "loader/init_loader.h" | ||||
|  | @ -46,6 +47,7 @@ extern "C" void zion() { | |||
|   // These two need to occur after memory allocation is available.
 | ||||
|   Apic::Init(); | ||||
|   ApicTimer::Init(); | ||||
|   DriverManager driver_manager; | ||||
| 
 | ||||
|   dbgln("[boot] Init syscalls."); | ||||
|   InitSyscall(); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue