1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/misc/panic.h"
4
5#include <mos/syslog/printk.h>
6#include <mos/x86/acpi/acpi.h>
7#include <mos/x86/acpi/acpi_types.h>
8#include <mos/x86/acpi/madt.h>
9#include <mos/x86/x86_platform.h>
10
11const acpi_madt_t *x86_acpi_madt = NULL;
12ptr_t x86_ioapic_phyaddr = 0;
13u32 x86_lapic_global_base = 0;
14
15#define IOAPIC_IRQ_OVERRIDE_MAX 255 // u8 can hold up to 255
16static u32 ioapic_irq_override[IOAPIC_IRQ_OVERRIDE_MAX] = { 0 };
17
18u32 x86_ioapic_get_irq_override(u32 irq)
19{
20 if (irq >= IOAPIC_IRQ_OVERRIDE_MAX)
21 return irq;
22 return ioapic_irq_override[irq];
23}
24
25void madt_parse_table()
26{
27 if (!x86_acpi_madt)
28 mos_panic("MADT not found");
29
30 x86_platform.num_cpus = 0;
31
32 for (u8 i = 0; i < IOAPIC_IRQ_OVERRIDE_MAX; i++)
33 ioapic_irq_override[i] = i; // Default: no override
34
35 madt_entry_foreach(entry, x86_acpi_madt)
36 {
37 switch (entry->type)
38 {
39 case 0:
40 {
41 acpi_madt_et0_lapic_t *lapic = container_of(entry, acpi_madt_et0_lapic_t, header);
42 pr_dinfo2(x86_acpi, "MADT entry LAPIC [%p], id=%u, processor=%u, flags=0x%x", (void *) lapic, lapic->apic_id, lapic->processor_id, lapic->flags);
43
44 bool enabled = lapic->flags & 1; // bit 0: processor is enabled
45 bool online_capable = lapic->flags & 2; // bit 1: online-capable
46
47 // If flags bit 0 is set the CPU is able to be enabled, if it is not set you need to check bit 1. If that one is set you can still enable it, if it is not
48 // the CPU can not be enabled and the OS should not try.
49
50 if (!enabled && !online_capable)
51 continue;
52
53 if (unlikely(x86_platform.num_cpus >= MOS_MAX_CPU_COUNT))
54 mos_panic("Too many CPUs");
55
56 x86_platform.num_cpus++;
57 break;
58 }
59 case 1:
60 {
61 acpi_madt_et1_ioapic_t *ioapic = container_of(entry, acpi_madt_et1_ioapic_t, header);
62 pr_dinfo2(x86_acpi, "MADT entry IOAPIC [%p], id=%u, address=%x, global_irq_base=%u", (void *) ioapic, ioapic->id, ioapic->address,
63 ioapic->global_intr_base);
64 if (unlikely(x86_ioapic_phyaddr))
65 mos_panic("Multiple IOAPICs not supported");
66 x86_ioapic_phyaddr = ioapic->address;
67 x86_lapic_global_base = ioapic->global_intr_base;
68 break;
69 }
70 case 2:
71 {
72 acpi_madt_et2_ioapic_override_t *int_override = container_of(entry, acpi_madt_et2_ioapic_override_t, header);
73 pr_dinfo2(x86_acpi, "MADT entry IOAPIC override [%p], bus=%u, flags=0x%x, 'irq source %u is now global irq %u'", (void *) int_override,
74 int_override->bus_source, int_override->flags, int_override->irq_source, int_override->global_intr);
75
76 if (unlikely(int_override->bus_source != 0))
77 mos_panic("IOAPIC override for non-ISA bus not supported");
78
79 if (unlikely(int_override->irq_source >= IOAPIC_IRQ_OVERRIDE_MAX))
80 mos_panic("IOAPIC override for IRQ >= 255 not supported");
81
82 if (unlikely(ioapic_irq_override[int_override->irq_source] != int_override->irq_source))
83 mos_panic("Multiple IOAPIC overrides for the same IRQ not supported");
84
85 ioapic_irq_override[int_override->irq_source] = int_override->global_intr;
86 break;
87 }
88 case 3:
89 {
90 acpi_madt_et3_ioapic_nmi_t *int_override = container_of(entry, acpi_madt_et3_ioapic_nmi_t, header);
91 pr_dinfo2(x86_acpi, "MADT entry IOAPIC NMI [%p], nmi_source=%u, global_irq=%u, flags=0x%x", (void *) int_override, int_override->nmi_source,
92 int_override->global_irq, int_override->flags);
93 pr_dwarn(x86_acpi, "Unhandled MADT entry type 3 (IOAPIC NMI)");
94 break;
95 }
96 case 4:
97 {
98 acpi_madt_et4_lapic_nmi_t *nmi = container_of(entry, acpi_madt_et4_lapic_nmi_t, header);
99 pr_dinfo2(x86_acpi, "MADT entry LAPIC NMI [%p], processor=%u, flags=0x%x, lint=%u", (void *) nmi, nmi->processor_id, nmi->flags, nmi->lint_number);
100 pr_dwarn(x86_acpi, "Unhandled MADT entry type 4 (LAPIC NMI)");
101 break;
102 }
103 case 5:
104 {
105 acpi_madt_et5_lapic_addr_t *local_apic_nmi = container_of(entry, acpi_madt_et5_lapic_addr_t, header);
106 pr_dinfo2(x86_acpi, "MADT entry LAPIC address override [%p], address=%llu", (void *) local_apic_nmi, local_apic_nmi->lapic_paddr);
107 pr_dwarn(x86_acpi, "Unhandled MADT entry type 5 (LAPIC address override)");
108 break;
109 }
110 case 9:
111 {
112 acpi_madt_et9_lx2apic_t *local_sapic_override = container_of(entry, acpi_madt_et9_lx2apic_t, header);
113 pr_dinfo2(x86_acpi, "MADT entry local x2 SAPIC override [%p], x2apic_id=%u, flags=0x%x, acpi_id=%u", (void *) local_sapic_override,
114 local_sapic_override->processor_lx2apic_id, local_sapic_override->flags, local_sapic_override->acpi_id);
115 pr_dwarn(x86_acpi, "Unhandled MADT entry type 9 (local x2 SAPIC override)");
116 break;
117 }
118 default:
119 {
120 pr_warn("Strange MADT entry type %u", entry->type);
121 }
122 }
123 }
124
125 pr_dinfo2(x86_lapic, "platform has %u cpu(s)", x86_platform.num_cpus);
126 return;
127}
128