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 | |
11 | const acpi_madt_t *x86_acpi_madt = NULL; |
12 | ptr_t x86_ioapic_phyaddr = 0; |
13 | u32 x86_lapic_global_base = 0; |
14 | |
15 | #define IOAPIC_IRQ_OVERRIDE_MAX 255 // u8 can hold up to 255 |
16 | static u32 ioapic_irq_override[IOAPIC_IRQ_OVERRIDE_MAX] = { 0 }; |
17 | |
18 | u32 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 | |
25 | void 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 | |