]>
Commit | Line | Data |
---|---|---|
eb66ffab GH |
1 | /* Support for generating ACPI tables and passing them to Guests |
2 | * | |
3 | * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net> | |
4 | * Copyright (C) 2006 Fabrice Bellard | |
5 | * Copyright (C) 2013 Red Hat Inc | |
6 | * | |
7 | * Author: Michael S. Tsirkin <mst@redhat.com> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | ||
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | ||
19 | * You should have received a copy of the GNU General Public License along | |
20 | * with this program; if not, see <http://www.gnu.org/licenses/>. | |
21 | */ | |
22 | ||
23 | #include "qemu/osdep.h" | |
24 | #include "qapi/error.h" | |
25 | ||
26 | #include "exec/memory.h" | |
27 | #include "hw/acpi/acpi.h" | |
28 | #include "hw/acpi/aml-build.h" | |
29 | #include "hw/acpi/utils.h" | |
30 | #include "hw/i386/pc.h" | |
31 | #include "target/i386/cpu.h" | |
32 | ||
33 | #include "acpi-build.h" | |
34 | #include "acpi-common.h" | |
35 | ||
d395b18d BB |
36 | void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, |
37 | GArray *entry, bool force_enabled) | |
eb66ffab GH |
38 | { |
39 | uint32_t apic_id = apic_ids->cpus[uid].arch_id; | |
dd092b9c IM |
40 | /* Flags – Local APIC Flags */ |
41 | uint32_t flags = apic_ids->cpus[uid].cpu != NULL || force_enabled ? | |
42 | 1 /* Enabled */ : 0; | |
eb66ffab GH |
43 | |
44 | /* ACPI spec says that LAPIC entry for non present | |
45 | * CPU may be omitted from MADT or it must be marked | |
46 | * as disabled. However omitting non present CPU from | |
47 | * MADT breaks hotplug on linux. So possible CPUs | |
48 | * should be put in MADT but kept disabled. | |
49 | */ | |
50 | if (apic_id < 255) { | |
dd092b9c IM |
51 | /* Rev 1.0b, Table 5-13 Processor Local APIC Structure */ |
52 | build_append_int_noprefix(entry, 0, 1); /* Type */ | |
53 | build_append_int_noprefix(entry, 8, 1); /* Length */ | |
54 | build_append_int_noprefix(entry, uid, 1); /* ACPI Processor ID */ | |
55 | build_append_int_noprefix(entry, apic_id, 1); /* APIC ID */ | |
56 | build_append_int_noprefix(entry, flags, 4); /* Flags */ | |
eb66ffab | 57 | } else { |
dd092b9c IM |
58 | /* Rev 4.0, 5.2.12.12 Processor Local x2APIC Structure */ |
59 | build_append_int_noprefix(entry, 9, 1); /* Type */ | |
60 | build_append_int_noprefix(entry, 16, 1); /* Length */ | |
61 | build_append_int_noprefix(entry, 0, 2); /* Reserved */ | |
62 | build_append_int_noprefix(entry, apic_id, 4); /* X2APIC ID */ | |
63 | build_append_int_noprefix(entry, flags, 4); /* Flags */ | |
64 | build_append_int_noprefix(entry, uid, 4); /* ACPI Processor UID */ | |
eb66ffab GH |
65 | } |
66 | } | |
67 | ||
dd092b9c IM |
68 | static void build_ioapic(GArray *entry, uint8_t id, uint32_t addr, uint32_t irq) |
69 | { | |
70 | /* Rev 1.0b, 5.2.8.2 IO APIC */ | |
71 | build_append_int_noprefix(entry, 1, 1); /* Type */ | |
72 | build_append_int_noprefix(entry, 12, 1); /* Length */ | |
73 | build_append_int_noprefix(entry, id, 1); /* IO APIC ID */ | |
74 | build_append_int_noprefix(entry, 0, 1); /* Reserved */ | |
75 | build_append_int_noprefix(entry, addr, 4); /* IO APIC Address */ | |
76 | build_append_int_noprefix(entry, irq, 4); /* System Vector Base */ | |
77 | } | |
78 | ||
79 | static void | |
80 | build_xrupt_override(GArray *entry, uint8_t src, uint32_t gsi, uint16_t flags) | |
81 | { | |
82 | /* Rev 1.0b, 5.2.8.3.1 Interrupt Source Overrides */ | |
83 | build_append_int_noprefix(entry, 2, 1); /* Type */ | |
84 | build_append_int_noprefix(entry, 10, 1); /* Length */ | |
85 | build_append_int_noprefix(entry, 0, 1); /* Bus */ | |
86 | build_append_int_noprefix(entry, src, 1); /* Source */ | |
87 | /* Global System Interrupt Vector */ | |
88 | build_append_int_noprefix(entry, gsi, 4); | |
89 | build_append_int_noprefix(entry, flags, 2); /* Flags */ | |
90 | } | |
91 | ||
99a7545f IM |
92 | /* |
93 | * ACPI spec, Revision 1.0b | |
94 | * 5.2.8 Multiple APIC Description Table | |
95 | */ | |
eb66ffab | 96 | void acpi_build_madt(GArray *table_data, BIOSLinker *linker, |
f4a06e59 | 97 | X86MachineState *x86ms, |
602b4582 | 98 | const char *oem_id, const char *oem_table_id) |
eb66ffab | 99 | { |
dd092b9c IM |
100 | int i; |
101 | bool x2apic_mode = false; | |
eb66ffab GH |
102 | MachineClass *mc = MACHINE_GET_CLASS(x86ms); |
103 | const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids(MACHINE(x86ms)); | |
6da94e27 | 104 | AcpiTable table = { .sig = "APIC", .rev = 3, .oem_id = oem_id, |
99a7545f | 105 | .oem_table_id = oem_table_id }; |
eb66ffab | 106 | |
99a7545f IM |
107 | acpi_table_begin(&table, table_data); |
108 | /* Local APIC Address */ | |
109 | build_append_int_noprefix(table_data, APIC_DEFAULT_ADDRESS, 4); | |
110 | build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ | |
eb66ffab GH |
111 | |
112 | for (i = 0; i < apic_ids->len; i++) { | |
f4a06e59 | 113 | pc_madt_cpu_entry(i, apic_ids, table_data, false); |
eb66ffab GH |
114 | if (apic_ids->cpus[i].arch_id > 254) { |
115 | x2apic_mode = true; | |
116 | } | |
117 | } | |
118 | ||
dd092b9c | 119 | build_ioapic(table_data, ACPI_BUILD_IOAPIC_ID, IO_APIC_DEFAULT_ADDRESS, 0); |
94c5a606 | 120 | if (x86ms->ioapic2) { |
dd092b9c IM |
121 | build_ioapic(table_data, ACPI_BUILD_IOAPIC_ID + 1, |
122 | IO_APIC_SECONDARY_ADDRESS, IO_APIC_SECONDARY_IRQBASE); | |
94c5a606 GH |
123 | } |
124 | ||
eb66ffab | 125 | if (x86ms->apic_xrupt_override) { |
dd092b9c IM |
126 | build_xrupt_override(table_data, 0, 2, |
127 | 0 /* Flags: Conforms to the specifications of the bus */); | |
eb66ffab | 128 | } |
5794d34a | 129 | |
a6518755 GH |
130 | for (i = 1; i < 16; i++) { |
131 | if (!(x86ms->pci_irq_mask & (1 << i))) { | |
132 | /* No need for a INT source override structure. */ | |
133 | continue; | |
eb66ffab | 134 | } |
dd092b9c IM |
135 | build_xrupt_override(table_data, i, i, |
136 | 0xd /* Flags: Active high, Level Triggered */); | |
eb66ffab GH |
137 | } |
138 | ||
139 | if (x2apic_mode) { | |
dd092b9c IM |
140 | /* Rev 4.0, 5.2.12.13 Local x2APIC NMI Structure*/ |
141 | build_append_int_noprefix(table_data, 0xA, 1); /* Type */ | |
142 | build_append_int_noprefix(table_data, 12, 1); /* Length */ | |
143 | build_append_int_noprefix(table_data, 0, 2); /* Flags */ | |
144 | /* ACPI Processor UID */ | |
145 | build_append_int_noprefix(table_data, 0xFFFFFFFF /* all processors */, | |
146 | 4); | |
147 | /* Local x2APIC LINT# */ | |
148 | build_append_int_noprefix(table_data, 1 /* ACPI_LINT1 */, 1); | |
149 | build_append_int_noprefix(table_data, 0, 3); /* Reserved */ | |
eb66ffab | 150 | } else { |
dd092b9c IM |
151 | /* Rev 1.0b, 5.2.8.3.3 Local APIC NMI */ |
152 | build_append_int_noprefix(table_data, 4, 1); /* Type */ | |
153 | build_append_int_noprefix(table_data, 6, 1); /* Length */ | |
154 | /* ACPI Processor ID */ | |
155 | build_append_int_noprefix(table_data, 0xFF /* all processors */, 1); | |
156 | build_append_int_noprefix(table_data, 0, 2); /* Flags */ | |
157 | /* Local APIC INTI# */ | |
158 | build_append_int_noprefix(table_data, 1 /* ACPI_LINT1 */, 1); | |
eb66ffab GH |
159 | } |
160 | ||
99a7545f | 161 | acpi_table_end(linker, &table); |
eb66ffab GH |
162 | } |
163 |