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