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