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