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