xref: /qemu/hw/loongarch/virt-acpi-build.c (revision d0897c6970b3717fe707c8d5a807fe2baf836ddd)
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     spcr_setup(tables_blob, tables->linker, machine);
561 
562     if (machine->numa_state->num_nodes) {
563         if (machine->numa_state->have_numa_distance) {
564             acpi_add_table(table_offsets, tables_blob);
565             build_slit(tables_blob, tables->linker, machine, lvms->oem_id,
566                        lvms->oem_table_id);
567         }
568         if (machine->numa_state->hmat_enabled) {
569             acpi_add_table(table_offsets, tables_blob);
570             build_hmat(tables_blob, tables->linker, machine->numa_state,
571                        lvms->oem_id, lvms->oem_table_id);
572         }
573     }
574 
575     acpi_add_table(table_offsets, tables_blob);
576     {
577         AcpiMcfgInfo mcfg = {
578            .base = cpu_to_le64(VIRT_PCI_CFG_BASE),
579            .size = cpu_to_le64(VIRT_PCI_CFG_SIZE),
580         };
581         build_mcfg(tables_blob, tables->linker, &mcfg, lvms->oem_id,
582                    lvms->oem_table_id);
583     }
584 
585 #ifdef CONFIG_TPM
586     /* TPM info */
587     if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) {
588         acpi_add_table(table_offsets, tables_blob);
589         build_tpm2(tables_blob, tables->linker,
590                    tables->tcpalog, lvms->oem_id,
591                    lvms->oem_table_id);
592     }
593 #endif
594     /* Add tables supplied by user (if any) */
595     for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
596         unsigned len = acpi_table_len(u);
597 
598         acpi_add_table(table_offsets, tables_blob);
599         g_array_append_vals(tables_blob, u, len);
600     }
601 
602     /* RSDT is pointed to by RSDP */
603     xsdt = tables_blob->len;
604     build_xsdt(tables_blob, tables->linker, table_offsets,
605                lvms->oem_id, lvms->oem_table_id);
606 
607     /* RSDP is in FSEG memory, so allocate it separately */
608     {
609         AcpiRsdpData rsdp_data = {
610             .revision = 2,
611             .oem_id = lvms->oem_id,
612             .xsdt_tbl_offset = &xsdt,
613             .rsdt_tbl_offset = NULL,
614         };
615         build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
616     }
617 
618     /*
619      * The align size is 128, warn if 64k is not enough therefore
620      * the align size could be resized.
621      */
622     if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
623         warn_report("ACPI table size %u exceeds %d bytes,"
624                     " migration may not work",
625                     tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
626         error_printf("Try removing CPUs, NUMA nodes, memory slots"
627                      " or PCI bridges.\n");
628     }
629 
630     acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE);
631 
632     /* Cleanup memory that's no longer used. */
633     g_array_free(table_offsets, true);
634 }
635 
acpi_ram_update(MemoryRegion * mr,GArray * data)636 static void acpi_ram_update(MemoryRegion *mr, GArray *data)
637 {
638     uint32_t size = acpi_data_len(data);
639 
640     /*
641      * Make sure RAM size is correct - in case it got changed
642      * e.g. by migration
643      */
644     memory_region_ram_resize(mr, size, &error_abort);
645 
646     memcpy(memory_region_get_ram_ptr(mr), data->data, size);
647     memory_region_set_dirty(mr, 0, size);
648 }
649 
acpi_build_update(void * build_opaque)650 static void acpi_build_update(void *build_opaque)
651 {
652     AcpiBuildState *build_state = build_opaque;
653     AcpiBuildTables tables;
654 
655     /* No state to update or already patched? Nothing to do. */
656     if (!build_state || build_state->patched) {
657         return;
658     }
659     build_state->patched = 1;
660 
661     acpi_build_tables_init(&tables);
662 
663     acpi_build(&tables, MACHINE(qdev_get_machine()));
664 
665     acpi_ram_update(build_state->table_mr, tables.table_data);
666     acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
667     acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
668 
669     acpi_build_tables_cleanup(&tables, true);
670 }
671 
acpi_build_reset(void * build_opaque)672 static void acpi_build_reset(void *build_opaque)
673 {
674     AcpiBuildState *build_state = build_opaque;
675     build_state->patched = 0;
676 }
677 
678 static const VMStateDescription vmstate_acpi_build = {
679     .name = "acpi_build",
680     .version_id = 1,
681     .minimum_version_id = 1,
682     .fields = (const VMStateField[]) {
683         VMSTATE_UINT8(patched, AcpiBuildState),
684         VMSTATE_END_OF_LIST()
685     },
686 };
687 
virt_is_acpi_enabled(LoongArchVirtMachineState * lvms)688 static bool virt_is_acpi_enabled(LoongArchVirtMachineState *lvms)
689 {
690     if (lvms->acpi == ON_OFF_AUTO_OFF) {
691         return false;
692     }
693     return true;
694 }
695 
virt_acpi_setup(LoongArchVirtMachineState * lvms)696 void virt_acpi_setup(LoongArchVirtMachineState *lvms)
697 {
698     AcpiBuildTables tables;
699     AcpiBuildState *build_state;
700 
701     if (!lvms->fw_cfg) {
702         ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
703         return;
704     }
705 
706     if (!virt_is_acpi_enabled(lvms)) {
707         ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
708         return;
709     }
710 
711     build_state = g_malloc0(sizeof *build_state);
712 
713     acpi_build_tables_init(&tables);
714     acpi_build(&tables, MACHINE(lvms));
715 
716     /* Now expose it all to Guest */
717     build_state->table_mr = acpi_add_rom_blob(acpi_build_update,
718                                               build_state, tables.table_data,
719                                               ACPI_BUILD_TABLE_FILE);
720     assert(build_state->table_mr != NULL);
721 
722     build_state->linker_mr =
723         acpi_add_rom_blob(acpi_build_update, build_state,
724                           tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE);
725 
726     build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update,
727                                              build_state, tables.rsdp,
728                                              ACPI_BUILD_RSDP_FILE);
729 
730     fw_cfg_add_file(lvms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data,
731                     acpi_data_len(tables.tcpalog));
732 
733     qemu_register_reset(acpi_build_reset, build_state);
734     acpi_build_reset(build_state);
735     vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
736 
737     /*
738      * Cleanup tables but don't free the memory: we track it
739      * in build_state.
740      */
741     acpi_build_tables_cleanup(&tables, false);
742 }
743