refactor: send the command with retry and error detection
[lunaix-os.git] / lunaix-os / hal / ioapic.c
1 #include <arch/x86/interrupts.h>
2 #include <hal/acpi/acpi.h>
3 #include <hal/ioapic.h>
4 #include <lunaix/common.h>
5 #include <lunaix/mm/mmio.h>
6
7 #define IOAPIC_REG_SEL *((volatile uint32_t*)(_ioapic_base + IOAPIC_IOREGSEL))
8 #define IOAPIC_REG_WIN *((volatile uint32_t*)(_ioapic_base + IOAPIC_IOWIN))
9
10 static volatile uintptr_t _ioapic_base;
11
12 uint8_t
13 ioapic_get_irq(acpi_context* acpi_ctx, uint8_t old_irq);
14
15 void
16 ioapic_init()
17 {
18     // Remapping the IRQs
19
20     acpi_context* acpi_ctx = acpi_get_context();
21
22     _ioapic_base = ioremap(acpi_ctx->madt.ioapic->ioapic_addr & ~0xfff, 4096);
23
24     // Remap the IRQ 8 (rtc timer's vector) to RTC_TIMER_IV in ioapic
25     //       (Remarks IRQ 8 is pin INTIN8)
26     //       See IBM PC/AT Technical Reference 1-10 for old RTC IRQ
27     //       See Intel's Multiprocessor Specification for IRQ - IOAPIC INTIN
28     //       mapping config.
29
30     // The ioapic_get_irq is to make sure we capture those overriden IRQs
31
32     // grab ourselves these irq numbers
33     uint8_t irq_rtc = ioapic_get_irq(acpi_ctx, PC_AT_IRQ_RTC);
34
35     // PC_AT_IRQ_RTC -> RTC_TIMER_IV, fixed, edge trigged, polarity=high,
36     // physical, APIC ID 0
37     ioapic_redirect(irq_rtc, RTC_TIMER_IV, 0, IOAPIC_DELMOD_FIXED);
38 }
39
40 uint8_t
41 ioapic_get_irq(acpi_context* acpi_ctx, uint8_t old_irq)
42 {
43     if (old_irq >= 24) {
44         return old_irq;
45     }
46     acpi_intso_t* int_override = acpi_ctx->madt.irq_exception[old_irq];
47     return int_override ? (uint8_t)int_override->gsi : old_irq;
48 }
49
50 void
51 ioapic_write(uint8_t sel, uint32_t val)
52 {
53     IOAPIC_REG_SEL = sel;
54     IOAPIC_REG_WIN = val;
55 }
56
57 uint32_t
58 ioapic_read(uint8_t sel)
59 {
60     IOAPIC_REG_SEL = sel;
61     return IOAPIC_REG_WIN;
62 }
63
64 void
65 ioapic_redirect(uint8_t irq, uint8_t vector, uint8_t dest, uint32_t flags)
66 {
67     uint8_t reg_sel = IOAPIC_IOREDTBL_BASE + irq * 2;
68
69     // Write low 32 bits
70     ioapic_write(reg_sel, (vector | flags) & 0x1FFFF);
71
72     // Write high 32 bits
73     ioapic_write(reg_sel + 1, (dest << 24));
74 }