]>
Commit | Line | Data |
---|---|---|
735143f1 XY |
1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
2 | /* | |
3 | * Support for generating ACPI tables and passing them to Guests | |
4 | * | |
5 | * Copyright (C) 2021 Loongson Technology Corporation Limited | |
6 | */ | |
7 | ||
8 | #include "qemu/osdep.h" | |
9 | #include "qapi/error.h" | |
10 | #include "qemu/bitmap.h" | |
11 | #include "hw/pci/pci.h" | |
12 | #include "hw/core/cpu.h" | |
13 | #include "target/loongarch/cpu.h" | |
14 | #include "hw/acpi/acpi-defs.h" | |
15 | #include "hw/acpi/acpi.h" | |
16 | #include "hw/nvram/fw_cfg.h" | |
17 | #include "hw/acpi/bios-linker-loader.h" | |
18 | #include "migration/vmstate.h" | |
19 | #include "hw/mem/memory-device.h" | |
20 | #include "sysemu/reset.h" | |
21 | ||
22 | /* Supported chipsets: */ | |
23 | #include "hw/pci-host/ls7a.h" | |
24 | #include "hw/loongarch/virt.h" | |
25 | #include "hw/acpi/aml-build.h" | |
26 | ||
27 | #include "hw/acpi/utils.h" | |
28 | #include "hw/acpi/pci.h" | |
29 | ||
30 | #include "qom/qom-qobject.h" | |
31 | ||
32 | #include "hw/acpi/generic_event_device.h" | |
1895b967 | 33 | #include "hw/pci-host/gpex.h" |
3dfbb6de XY |
34 | #include "sysemu/tpm.h" |
35 | #include "hw/platform-bus.h" | |
36 | #include "hw/acpi/aml-build.h" | |
735143f1 XY |
37 | |
38 | #define ACPI_BUILD_ALIGN_SIZE 0x1000 | |
39 | #define ACPI_BUILD_TABLE_SIZE 0x20000 | |
40 | ||
41 | #ifdef DEBUG_ACPI_BUILD | |
42 | #define ACPI_BUILD_DPRINTF(fmt, ...) \ | |
43 | do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0) | |
44 | #else | |
45 | #define ACPI_BUILD_DPRINTF(fmt, ...) | |
46 | #endif | |
47 | ||
48 | /* build FADT */ | |
49 | static void init_common_fadt_data(AcpiFadtData *data) | |
50 | { | |
51 | AcpiFadtData fadt = { | |
52 | /* ACPI 5.0: 4.1 Hardware-Reduced ACPI */ | |
53 | .rev = 5, | |
54 | .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) | | |
55 | (1 << ACPI_FADT_F_RESET_REG_SUP)), | |
56 | ||
57 | /* ACPI 5.0: 4.8.3.7 Sleep Control and Status Registers */ | |
58 | .sleep_ctl = { | |
59 | .space_id = AML_AS_SYSTEM_MEMORY, | |
60 | .bit_width = 8, | |
61 | .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_CTL, | |
62 | }, | |
63 | .sleep_sts = { | |
64 | .space_id = AML_AS_SYSTEM_MEMORY, | |
65 | .bit_width = 8, | |
66 | .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_STS, | |
67 | }, | |
68 | ||
69 | /* ACPI 5.0: 4.8.3.6 Reset Register */ | |
70 | .reset_reg = { | |
71 | .space_id = AML_AS_SYSTEM_MEMORY, | |
72 | .bit_width = 8, | |
73 | .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_RESET, | |
74 | }, | |
75 | .reset_val = ACPI_GED_RESET_VALUE, | |
76 | }; | |
77 | *data = fadt; | |
78 | } | |
79 | ||
80 | static void acpi_align_size(GArray *blob, unsigned align) | |
81 | { | |
82 | /* | |
83 | * Align size to multiple of given size. This reduces the chance | |
84 | * we need to change size in the future (breaking cross version migration). | |
85 | */ | |
86 | g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); | |
87 | } | |
88 | ||
89 | /* build FACS */ | |
90 | static void | |
91 | build_facs(GArray *table_data) | |
92 | { | |
93 | const char *sig = "FACS"; | |
94 | const uint8_t reserved[40] = {}; | |
95 | ||
96 | g_array_append_vals(table_data, sig, 4); /* Signature */ | |
97 | build_append_int_noprefix(table_data, 64, 4); /* Length */ | |
98 | build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */ | |
99 | build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */ | |
100 | build_append_int_noprefix(table_data, 0, 4); /* Global Lock */ | |
101 | build_append_int_noprefix(table_data, 0, 4); /* Flags */ | |
102 | g_array_append_vals(table_data, reserved, 40); /* Reserved */ | |
103 | } | |
104 | ||
105 | /* build MADT */ | |
106 | static void | |
107 | build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams) | |
108 | { | |
109 | MachineState *ms = MACHINE(lams); | |
110 | int i; | |
111 | AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id, | |
112 | .oem_table_id = lams->oem_table_id }; | |
113 | ||
114 | acpi_table_begin(&table, table_data); | |
115 | ||
116 | /* Local APIC Address */ | |
117 | build_append_int_noprefix(table_data, 0, 4); | |
118 | build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ | |
119 | ||
120 | for (i = 0; i < ms->smp.cpus; i++) { | |
121 | /* Processor Core Interrupt Controller Structure */ | |
122 | build_append_int_noprefix(table_data, 17, 1); /* Type */ | |
123 | build_append_int_noprefix(table_data, 15, 1); /* Length */ | |
124 | build_append_int_noprefix(table_data, 1, 1); /* Version */ | |
125 | build_append_int_noprefix(table_data, i + 1, 4); /* ACPI Processor ID */ | |
126 | build_append_int_noprefix(table_data, i, 4); /* Core ID */ | |
127 | build_append_int_noprefix(table_data, 1, 4); /* Flags */ | |
128 | } | |
129 | ||
130 | /* Extend I/O Interrupt Controller Structure */ | |
131 | build_append_int_noprefix(table_data, 20, 1); /* Type */ | |
132 | build_append_int_noprefix(table_data, 13, 1); /* Length */ | |
133 | build_append_int_noprefix(table_data, 1, 1); /* Version */ | |
134 | build_append_int_noprefix(table_data, 3, 1); /* Cascade */ | |
135 | build_append_int_noprefix(table_data, 0, 1); /* Node */ | |
136 | build_append_int_noprefix(table_data, 0xffff, 8); /* Node map */ | |
137 | ||
138 | /* MSI Interrupt Controller Structure */ | |
139 | build_append_int_noprefix(table_data, 21, 1); /* Type */ | |
140 | build_append_int_noprefix(table_data, 19, 1); /* Length */ | |
141 | build_append_int_noprefix(table_data, 1, 1); /* Version */ | |
74725231 | 142 | build_append_int_noprefix(table_data, VIRT_PCH_MSI_ADDR_LOW, 8);/* Address */ |
735143f1 XY |
143 | build_append_int_noprefix(table_data, 0x40, 4); /* Start */ |
144 | build_append_int_noprefix(table_data, 0xc0, 4); /* Count */ | |
145 | ||
146 | /* Bridge I/O Interrupt Controller Structure */ | |
147 | build_append_int_noprefix(table_data, 22, 1); /* Type */ | |
148 | build_append_int_noprefix(table_data, 17, 1); /* Length */ | |
149 | build_append_int_noprefix(table_data, 1, 1); /* Version */ | |
74725231 | 150 | build_append_int_noprefix(table_data, VIRT_PCH_REG_BASE, 8);/* Address */ |
735143f1 XY |
151 | build_append_int_noprefix(table_data, 0x1000, 2); /* Size */ |
152 | build_append_int_noprefix(table_data, 0, 2); /* Id */ | |
153 | build_append_int_noprefix(table_data, 0x40, 2); /* Base */ | |
154 | ||
155 | acpi_table_end(linker, &table); | |
156 | } | |
157 | ||
158 | /* build SRAT */ | |
159 | static void | |
160 | build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) | |
161 | { | |
162 | uint64_t i; | |
163 | LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); | |
164 | MachineState *ms = MACHINE(lams); | |
165 | AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id, | |
166 | .oem_table_id = lams->oem_table_id }; | |
167 | ||
168 | acpi_table_begin(&table, table_data); | |
169 | build_append_int_noprefix(table_data, 1, 4); /* Reserved */ | |
170 | build_append_int_noprefix(table_data, 0, 8); /* Reserved */ | |
171 | ||
172 | for (i = 0; i < ms->smp.cpus; ++i) { | |
173 | /* Processor Local APIC/SAPIC Affinity Structure */ | |
174 | build_append_int_noprefix(table_data, 0, 1); /* Type */ | |
175 | build_append_int_noprefix(table_data, 16, 1); /* Length */ | |
176 | /* Proximity Domain [7:0] */ | |
177 | build_append_int_noprefix(table_data, 0, 1); | |
178 | build_append_int_noprefix(table_data, i, 1); /* APIC ID */ | |
179 | /* Flags, Table 5-36 */ | |
180 | build_append_int_noprefix(table_data, 1, 4); | |
181 | build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */ | |
182 | /* Proximity Domain [31:8] */ | |
183 | build_append_int_noprefix(table_data, 0, 3); | |
184 | build_append_int_noprefix(table_data, 0, 4); /* Reserved */ | |
185 | } | |
186 | ||
187 | build_srat_memory(table_data, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, | |
188 | 0, MEM_AFFINITY_ENABLED); | |
189 | ||
190 | build_srat_memory(table_data, VIRT_HIGHMEM_BASE, machine->ram_size - VIRT_LOWMEM_SIZE, | |
191 | 0, MEM_AFFINITY_ENABLED); | |
192 | ||
c3da26f3 XY |
193 | if (ms->device_memory) { |
194 | build_srat_memory(table_data, ms->device_memory->base, | |
195 | memory_region_size(&ms->device_memory->mr), | |
196 | 0, MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED); | |
197 | } | |
198 | ||
735143f1 XY |
199 | acpi_table_end(linker, &table); |
200 | } | |
201 | ||
202 | typedef | |
203 | struct AcpiBuildState { | |
204 | /* Copy of table in RAM (for patching). */ | |
205 | MemoryRegion *table_mr; | |
206 | /* Is table patched? */ | |
207 | uint8_t patched; | |
208 | void *rsdp; | |
209 | MemoryRegion *rsdp_mr; | |
210 | MemoryRegion *linker_mr; | |
211 | } AcpiBuildState; | |
212 | ||
735143f1 XY |
213 | static void build_uart_device_aml(Aml *table) |
214 | { | |
215 | Aml *dev; | |
216 | Aml *crs; | |
217 | Aml *pkg0, *pkg1, *pkg2; | |
74725231 | 218 | uint32_t uart_irq = VIRT_UART_IRQ; |
735143f1 XY |
219 | |
220 | Aml *scope = aml_scope("_SB"); | |
221 | dev = aml_device("COMA"); | |
222 | aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501"))); | |
223 | aml_append(dev, aml_name_decl("_UID", aml_int(0))); | |
224 | aml_append(dev, aml_name_decl("_CCA", aml_int(1))); | |
225 | crs = aml_resource_template(); | |
226 | aml_append(crs, | |
227 | aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, | |
228 | AML_NON_CACHEABLE, AML_READ_WRITE, | |
4451cc46 XY |
229 | 0, VIRT_UART_BASE, VIRT_UART_BASE + VIRT_UART_SIZE - 1, |
230 | 0, VIRT_UART_SIZE)); | |
735143f1 XY |
231 | aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, |
232 | AML_SHARED, &uart_irq, 1)); | |
233 | aml_append(dev, aml_name_decl("_CRS", crs)); | |
234 | pkg0 = aml_package(0x2); | |
235 | aml_append(pkg0, aml_int(0x05F5E100)); | |
236 | aml_append(pkg0, aml_string("clock-frenquency")); | |
237 | pkg1 = aml_package(0x1); | |
238 | aml_append(pkg1, pkg0); | |
239 | pkg2 = aml_package(0x2); | |
240 | aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301")); | |
241 | aml_append(pkg2, pkg1); | |
242 | aml_append(dev, aml_name_decl("_DSD", pkg2)); | |
243 | aml_append(scope, dev); | |
244 | aml_append(table, scope); | |
245 | } | |
246 | ||
c3da26f3 XY |
247 | static void |
248 | build_la_ged_aml(Aml *dsdt, MachineState *machine) | |
249 | { | |
250 | uint32_t event; | |
251 | LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); | |
252 | ||
253 | build_ged_aml(dsdt, "\\_SB."GED_DEVICE, | |
254 | HOTPLUG_HANDLER(lams->acpi_ged), | |
255 | VIRT_SCI_IRQ, AML_SYSTEM_MEMORY, | |
256 | VIRT_GED_EVT_ADDR); | |
257 | event = object_property_get_uint(OBJECT(lams->acpi_ged), | |
258 | "ged-event", &error_abort); | |
259 | if (event & ACPI_GED_MEM_HOTPLUG_EVT) { | |
260 | build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL, | |
261 | AML_SYSTEM_MEMORY, | |
262 | VIRT_GED_MEM_ADDR); | |
263 | } | |
264 | } | |
265 | ||
1895b967 XY |
266 | static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams) |
267 | { | |
268 | struct GPEXConfig cfg = { | |
269 | .mmio64.base = VIRT_PCI_MEM_BASE, | |
270 | .mmio64.size = VIRT_PCI_MEM_SIZE, | |
271 | .pio.base = VIRT_PCI_IO_BASE, | |
272 | .pio.size = VIRT_PCI_IO_SIZE, | |
273 | .ecam.base = VIRT_PCI_CFG_BASE, | |
274 | .ecam.size = VIRT_PCI_CFG_SIZE, | |
275 | .irq = PCH_PIC_IRQ_OFFSET + VIRT_DEVICE_IRQS, | |
276 | .bus = lams->pci_bus, | |
277 | }; | |
278 | ||
279 | acpi_dsdt_add_gpex(scope, &cfg); | |
280 | } | |
281 | ||
288431a1 XY |
282 | static void build_flash_aml(Aml *scope, LoongArchMachineState *lams) |
283 | { | |
284 | Aml *dev, *crs; | |
285 | ||
286 | hwaddr flash_base = VIRT_FLASH_BASE; | |
287 | hwaddr flash_size = VIRT_FLASH_SIZE; | |
288 | ||
289 | dev = aml_device("FLS0"); | |
290 | aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015"))); | |
291 | aml_append(dev, aml_name_decl("_UID", aml_int(0))); | |
292 | ||
293 | crs = aml_resource_template(); | |
294 | aml_append(crs, aml_memory32_fixed(flash_base, flash_size, AML_READ_WRITE)); | |
295 | aml_append(dev, aml_name_decl("_CRS", crs)); | |
296 | aml_append(scope, dev); | |
297 | } | |
298 | ||
3dfbb6de XY |
299 | #ifdef CONFIG_TPM |
300 | static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms) | |
301 | { | |
302 | PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev); | |
303 | hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS; | |
304 | SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find()); | |
305 | MemoryRegion *sbdev_mr; | |
306 | hwaddr tpm_base; | |
307 | ||
308 | if (!sbdev) { | |
309 | return; | |
310 | } | |
311 | ||
312 | tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); | |
313 | assert(tpm_base != -1); | |
314 | ||
315 | tpm_base += pbus_base; | |
316 | ||
317 | sbdev_mr = sysbus_mmio_get_region(sbdev, 0); | |
318 | ||
319 | Aml *dev = aml_device("TPM0"); | |
320 | aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101"))); | |
321 | aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device"))); | |
322 | aml_append(dev, aml_name_decl("_UID", aml_int(0))); | |
323 | ||
324 | Aml *crs = aml_resource_template(); | |
325 | aml_append(crs, | |
326 | aml_memory32_fixed(tpm_base, | |
327 | (uint32_t)memory_region_size(sbdev_mr), | |
328 | AML_READ_WRITE)); | |
329 | aml_append(dev, aml_name_decl("_CRS", crs)); | |
330 | aml_append(scope, dev); | |
331 | } | |
332 | #endif | |
333 | ||
735143f1 XY |
334 | /* build DSDT */ |
335 | static void | |
336 | build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) | |
337 | { | |
1895b967 | 338 | Aml *dsdt, *scope, *pkg; |
735143f1 XY |
339 | LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); |
340 | AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id, | |
341 | .oem_table_id = lams->oem_table_id }; | |
342 | ||
343 | acpi_table_begin(&table, table_data); | |
735143f1 | 344 | dsdt = init_aml_allocator(); |
735143f1 | 345 | build_uart_device_aml(dsdt); |
1895b967 | 346 | build_pci_device_aml(dsdt, lams); |
c3da26f3 | 347 | build_la_ged_aml(dsdt, machine); |
288431a1 | 348 | build_flash_aml(dsdt, lams); |
3dfbb6de XY |
349 | #ifdef CONFIG_TPM |
350 | acpi_dsdt_add_tpm(dsdt, lams); | |
351 | #endif | |
735143f1 XY |
352 | /* System State Package */ |
353 | scope = aml_scope("\\"); | |
354 | pkg = aml_package(4); | |
355 | aml_append(pkg, aml_int(ACPI_GED_SLP_TYP_S5)); | |
356 | aml_append(pkg, aml_int(0)); /* ignored */ | |
357 | aml_append(pkg, aml_int(0)); /* reserved */ | |
358 | aml_append(pkg, aml_int(0)); /* reserved */ | |
359 | aml_append(scope, aml_name_decl("_S5", pkg)); | |
360 | aml_append(dsdt, scope); | |
361 | /* Copy AML table into ACPI tables blob and patch header there */ | |
362 | g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); | |
363 | acpi_table_end(linker, &table); | |
364 | free_aml_allocator(); | |
365 | } | |
366 | ||
367 | static void acpi_build(AcpiBuildTables *tables, MachineState *machine) | |
368 | { | |
369 | LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); | |
370 | GArray *table_offsets; | |
371 | AcpiFadtData fadt_data; | |
4cbadc40 | 372 | unsigned facs, rsdt, dsdt; |
735143f1 | 373 | uint8_t *u; |
735143f1 XY |
374 | GArray *tables_blob = tables->table_data; |
375 | ||
376 | init_common_fadt_data(&fadt_data); | |
377 | ||
378 | table_offsets = g_array_new(false, true, sizeof(uint32_t)); | |
379 | ACPI_BUILD_DPRINTF("init ACPI tables\n"); | |
380 | ||
381 | bios_linker_loader_alloc(tables->linker, | |
382 | ACPI_BUILD_TABLE_FILE, tables_blob, | |
383 | 64, false); | |
384 | ||
385 | /* | |
386 | * FACS is pointed to by FADT. | |
387 | * We place it first since it's the only table that has alignment | |
388 | * requirements. | |
389 | */ | |
390 | facs = tables_blob->len; | |
391 | build_facs(tables_blob); | |
392 | ||
393 | /* DSDT is pointed to by FADT */ | |
394 | dsdt = tables_blob->len; | |
395 | build_dsdt(tables_blob, tables->linker, machine); | |
396 | ||
735143f1 | 397 | /* ACPI tables pointed to by RSDT */ |
735143f1 XY |
398 | acpi_add_table(table_offsets, tables_blob); |
399 | fadt_data.facs_tbl_offset = &facs; | |
400 | fadt_data.dsdt_tbl_offset = &dsdt; | |
401 | fadt_data.xdsdt_tbl_offset = &dsdt; | |
402 | build_fadt(tables_blob, tables->linker, &fadt_data, | |
403 | lams->oem_id, lams->oem_table_id); | |
735143f1 XY |
404 | |
405 | acpi_add_table(table_offsets, tables_blob); | |
406 | build_madt(tables_blob, tables->linker, lams); | |
407 | ||
408 | acpi_add_table(table_offsets, tables_blob); | |
409 | build_srat(tables_blob, tables->linker, machine); | |
410 | ||
411 | acpi_add_table(table_offsets, tables_blob); | |
412 | { | |
413 | AcpiMcfgInfo mcfg = { | |
74725231 XY |
414 | .base = cpu_to_le64(VIRT_PCI_CFG_BASE), |
415 | .size = cpu_to_le64(VIRT_PCI_CFG_SIZE), | |
735143f1 XY |
416 | }; |
417 | build_mcfg(tables_blob, tables->linker, &mcfg, lams->oem_id, | |
418 | lams->oem_table_id); | |
419 | } | |
420 | ||
3dfbb6de XY |
421 | #ifdef CONFIG_TPM |
422 | /* TPM info */ | |
423 | if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) { | |
424 | acpi_add_table(table_offsets, tables_blob); | |
425 | build_tpm2(tables_blob, tables->linker, | |
426 | tables->tcpalog, lams->oem_id, | |
427 | lams->oem_table_id); | |
428 | } | |
429 | #endif | |
735143f1 XY |
430 | /* Add tables supplied by user (if any) */ |
431 | for (u = acpi_table_first(); u; u = acpi_table_next(u)) { | |
432 | unsigned len = acpi_table_len(u); | |
433 | ||
434 | acpi_add_table(table_offsets, tables_blob); | |
435 | g_array_append_vals(tables_blob, u, len); | |
436 | } | |
437 | ||
438 | /* RSDT is pointed to by RSDP */ | |
439 | rsdt = tables_blob->len; | |
440 | build_rsdt(tables_blob, tables->linker, table_offsets, | |
441 | lams->oem_id, lams->oem_table_id); | |
442 | ||
443 | /* RSDP is in FSEG memory, so allocate it separately */ | |
444 | { | |
445 | AcpiRsdpData rsdp_data = { | |
446 | .revision = 0, | |
447 | .oem_id = lams->oem_id, | |
448 | .xsdt_tbl_offset = NULL, | |
449 | .rsdt_tbl_offset = &rsdt, | |
450 | }; | |
451 | build_rsdp(tables->rsdp, tables->linker, &rsdp_data); | |
452 | } | |
453 | ||
454 | /* | |
455 | * The align size is 128, warn if 64k is not enough therefore | |
456 | * the align size could be resized. | |
457 | */ | |
458 | if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) { | |
459 | warn_report("ACPI table size %u exceeds %d bytes," | |
460 | " migration may not work", | |
461 | tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2); | |
462 | error_printf("Try removing CPUs, NUMA nodes, memory slots" | |
463 | " or PCI bridges."); | |
464 | } | |
465 | ||
466 | acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE); | |
467 | ||
468 | /* Cleanup memory that's no longer used. */ | |
469 | g_array_free(table_offsets, true); | |
470 | } | |
471 | ||
472 | static void acpi_ram_update(MemoryRegion *mr, GArray *data) | |
473 | { | |
474 | uint32_t size = acpi_data_len(data); | |
475 | ||
476 | /* | |
477 | * Make sure RAM size is correct - in case it got changed | |
478 | * e.g. by migration | |
479 | */ | |
480 | memory_region_ram_resize(mr, size, &error_abort); | |
481 | ||
482 | memcpy(memory_region_get_ram_ptr(mr), data->data, size); | |
483 | memory_region_set_dirty(mr, 0, size); | |
484 | } | |
485 | ||
486 | static void acpi_build_update(void *build_opaque) | |
487 | { | |
488 | AcpiBuildState *build_state = build_opaque; | |
489 | AcpiBuildTables tables; | |
490 | ||
491 | /* No state to update or already patched? Nothing to do. */ | |
492 | if (!build_state || build_state->patched) { | |
493 | return; | |
494 | } | |
495 | build_state->patched = 1; | |
496 | ||
497 | acpi_build_tables_init(&tables); | |
498 | ||
499 | acpi_build(&tables, MACHINE(qdev_get_machine())); | |
500 | ||
501 | acpi_ram_update(build_state->table_mr, tables.table_data); | |
502 | acpi_ram_update(build_state->rsdp_mr, tables.rsdp); | |
503 | acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); | |
504 | ||
505 | acpi_build_tables_cleanup(&tables, true); | |
506 | } | |
507 | ||
508 | static void acpi_build_reset(void *build_opaque) | |
509 | { | |
510 | AcpiBuildState *build_state = build_opaque; | |
511 | build_state->patched = 0; | |
512 | } | |
513 | ||
514 | static const VMStateDescription vmstate_acpi_build = { | |
515 | .name = "acpi_build", | |
516 | .version_id = 1, | |
517 | .minimum_version_id = 1, | |
518 | .fields = (VMStateField[]) { | |
519 | VMSTATE_UINT8(patched, AcpiBuildState), | |
520 | VMSTATE_END_OF_LIST() | |
521 | }, | |
522 | }; | |
523 | ||
524 | void loongarch_acpi_setup(LoongArchMachineState *lams) | |
525 | { | |
526 | AcpiBuildTables tables; | |
527 | AcpiBuildState *build_state; | |
528 | ||
529 | if (!lams->fw_cfg) { | |
530 | ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); | |
531 | return; | |
532 | } | |
533 | ||
534 | if (!loongarch_is_acpi_enabled(lams)) { | |
535 | ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n"); | |
536 | return; | |
537 | } | |
538 | ||
539 | build_state = g_malloc0(sizeof *build_state); | |
540 | ||
541 | acpi_build_tables_init(&tables); | |
542 | acpi_build(&tables, MACHINE(lams)); | |
543 | ||
544 | /* Now expose it all to Guest */ | |
545 | build_state->table_mr = acpi_add_rom_blob(acpi_build_update, | |
546 | build_state, tables.table_data, | |
547 | ACPI_BUILD_TABLE_FILE); | |
548 | assert(build_state->table_mr != NULL); | |
549 | ||
550 | build_state->linker_mr = | |
551 | acpi_add_rom_blob(acpi_build_update, build_state, | |
552 | tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE); | |
553 | ||
554 | build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update, | |
555 | build_state, tables.rsdp, | |
556 | ACPI_BUILD_RSDP_FILE); | |
557 | ||
558 | qemu_register_reset(acpi_build_reset, build_state); | |
559 | acpi_build_reset(build_state); | |
560 | vmstate_register(NULL, 0, &vmstate_acpi_build, build_state); | |
561 | ||
562 | /* | |
563 | * Cleanup tables but don't free the memory: we track it | |
564 | * in build_state. | |
565 | */ | |
566 | acpi_build_tables_cleanup(&tables, false); | |
567 | } |