xref: /openbmc/qemu/hw/loongarch/acpi-build.c (revision 63731c346f071a77e1bb1789bef1ac9d592b6d4f)
1735143f1SXiaojuan Yang /* SPDX-License-Identifier: GPL-2.0-or-later */
2735143f1SXiaojuan Yang /*
3735143f1SXiaojuan Yang  * Support for generating ACPI tables and passing them to Guests
4735143f1SXiaojuan Yang  *
5735143f1SXiaojuan Yang  * Copyright (C) 2021 Loongson Technology Corporation Limited
6735143f1SXiaojuan Yang  */
7735143f1SXiaojuan Yang 
8735143f1SXiaojuan Yang #include "qemu/osdep.h"
9735143f1SXiaojuan Yang #include "qapi/error.h"
10cc37d98bSRichard Henderson #include "qemu/error-report.h"
11735143f1SXiaojuan Yang #include "qemu/bitmap.h"
12735143f1SXiaojuan Yang #include "hw/pci/pci.h"
13735143f1SXiaojuan Yang #include "hw/core/cpu.h"
14735143f1SXiaojuan Yang #include "target/loongarch/cpu.h"
15735143f1SXiaojuan Yang #include "hw/acpi/acpi-defs.h"
16735143f1SXiaojuan Yang #include "hw/acpi/acpi.h"
17735143f1SXiaojuan Yang #include "hw/nvram/fw_cfg.h"
18735143f1SXiaojuan Yang #include "hw/acpi/bios-linker-loader.h"
19735143f1SXiaojuan Yang #include "migration/vmstate.h"
20735143f1SXiaojuan Yang #include "hw/mem/memory-device.h"
21735143f1SXiaojuan Yang #include "sysemu/reset.h"
22735143f1SXiaojuan Yang 
23735143f1SXiaojuan Yang /* Supported chipsets: */
24735143f1SXiaojuan Yang #include "hw/pci-host/ls7a.h"
25735143f1SXiaojuan Yang #include "hw/loongarch/virt.h"
26735143f1SXiaojuan Yang 
27735143f1SXiaojuan Yang #include "hw/acpi/utils.h"
28735143f1SXiaojuan Yang #include "hw/acpi/pci.h"
29735143f1SXiaojuan Yang 
30735143f1SXiaojuan Yang #include "qom/qom-qobject.h"
31735143f1SXiaojuan Yang 
32735143f1SXiaojuan Yang #include "hw/acpi/generic_event_device.h"
331895b967SXiaojuan Yang #include "hw/pci-host/gpex.h"
34b3d4ef83SJason A. Donenfeld #include "sysemu/sysemu.h"
353dfbb6deSXiaojuan Yang #include "sysemu/tpm.h"
363dfbb6deSXiaojuan Yang #include "hw/platform-bus.h"
373dfbb6deSXiaojuan Yang #include "hw/acpi/aml-build.h"
380cf1478dSTianrui Zhao #include "hw/acpi/hmat.h"
39735143f1SXiaojuan Yang 
40735143f1SXiaojuan Yang #define ACPI_BUILD_ALIGN_SIZE             0x1000
41735143f1SXiaojuan Yang #define ACPI_BUILD_TABLE_SIZE             0x20000
42735143f1SXiaojuan Yang 
43735143f1SXiaojuan Yang #ifdef DEBUG_ACPI_BUILD
44735143f1SXiaojuan Yang #define ACPI_BUILD_DPRINTF(fmt, ...)        \
45735143f1SXiaojuan Yang     do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0)
46735143f1SXiaojuan Yang #else
47735143f1SXiaojuan Yang #define ACPI_BUILD_DPRINTF(fmt, ...)
48735143f1SXiaojuan Yang #endif
49735143f1SXiaojuan Yang 
50735143f1SXiaojuan Yang /* build FADT */
init_common_fadt_data(AcpiFadtData * data)51735143f1SXiaojuan Yang static void init_common_fadt_data(AcpiFadtData *data)
52735143f1SXiaojuan Yang {
53735143f1SXiaojuan Yang     AcpiFadtData fadt = {
54735143f1SXiaojuan Yang         /* ACPI 5.0: 4.1 Hardware-Reduced ACPI */
55735143f1SXiaojuan Yang         .rev = 5,
56735143f1SXiaojuan Yang         .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) |
57735143f1SXiaojuan Yang                   (1 << ACPI_FADT_F_RESET_REG_SUP)),
58735143f1SXiaojuan Yang 
59735143f1SXiaojuan Yang         /* ACPI 5.0: 4.8.3.7 Sleep Control and Status Registers */
60735143f1SXiaojuan Yang         .sleep_ctl = {
61735143f1SXiaojuan Yang             .space_id = AML_AS_SYSTEM_MEMORY,
62735143f1SXiaojuan Yang             .bit_width = 8,
63735143f1SXiaojuan Yang             .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_CTL,
64735143f1SXiaojuan Yang         },
65735143f1SXiaojuan Yang         .sleep_sts = {
66735143f1SXiaojuan Yang             .space_id = AML_AS_SYSTEM_MEMORY,
67735143f1SXiaojuan Yang             .bit_width = 8,
68735143f1SXiaojuan Yang             .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_STS,
69735143f1SXiaojuan Yang         },
70735143f1SXiaojuan Yang 
71735143f1SXiaojuan Yang         /* ACPI 5.0: 4.8.3.6 Reset Register */
72735143f1SXiaojuan Yang         .reset_reg = {
73735143f1SXiaojuan Yang             .space_id = AML_AS_SYSTEM_MEMORY,
74735143f1SXiaojuan Yang             .bit_width = 8,
75735143f1SXiaojuan Yang             .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_RESET,
76735143f1SXiaojuan Yang         },
77735143f1SXiaojuan Yang         .reset_val = ACPI_GED_RESET_VALUE,
78735143f1SXiaojuan Yang     };
79735143f1SXiaojuan Yang     *data = fadt;
80735143f1SXiaojuan Yang }
81735143f1SXiaojuan Yang 
acpi_align_size(GArray * blob,unsigned align)82735143f1SXiaojuan Yang static void acpi_align_size(GArray *blob, unsigned align)
83735143f1SXiaojuan Yang {
84735143f1SXiaojuan Yang     /*
85735143f1SXiaojuan Yang      * Align size to multiple of given size. This reduces the chance
86735143f1SXiaojuan Yang      * we need to change size in the future (breaking cross version migration).
87735143f1SXiaojuan Yang      */
88735143f1SXiaojuan Yang     g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
89735143f1SXiaojuan Yang }
90735143f1SXiaojuan Yang 
91735143f1SXiaojuan Yang /* build FACS */
92735143f1SXiaojuan Yang static void
build_facs(GArray * table_data)93735143f1SXiaojuan Yang build_facs(GArray *table_data)
94735143f1SXiaojuan Yang {
95735143f1SXiaojuan Yang     const char *sig = "FACS";
96735143f1SXiaojuan Yang     const uint8_t reserved[40] = {};
97735143f1SXiaojuan Yang 
98735143f1SXiaojuan Yang     g_array_append_vals(table_data, sig, 4); /* Signature */
99735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 64, 4); /* Length */
100735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */
101735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */
102735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0, 4); /* Global Lock */
103735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0, 4); /* Flags */
104735143f1SXiaojuan Yang     g_array_append_vals(table_data, reserved, 40); /* Reserved */
105735143f1SXiaojuan Yang }
106735143f1SXiaojuan Yang 
107735143f1SXiaojuan Yang /* build MADT */
108735143f1SXiaojuan Yang static void
build_madt(GArray * table_data,BIOSLinker * linker,LoongArchVirtMachineState * lvms)109d804ad98SBibo Mao build_madt(GArray *table_data, BIOSLinker *linker,
110d804ad98SBibo Mao            LoongArchVirtMachineState *lvms)
111735143f1SXiaojuan Yang {
112d804ad98SBibo Mao     MachineState *ms = MACHINE(lvms);
1138f30771cSTianrui Zhao     MachineClass *mc = MACHINE_GET_CLASS(ms);
1148f30771cSTianrui Zhao     const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
1158f30771cSTianrui Zhao     int i, arch_id;
116d804ad98SBibo Mao     AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lvms->oem_id,
117d804ad98SBibo Mao                         .oem_table_id = lvms->oem_table_id };
118735143f1SXiaojuan Yang 
119735143f1SXiaojuan Yang     acpi_table_begin(&table, table_data);
120735143f1SXiaojuan Yang 
121735143f1SXiaojuan Yang     /* Local APIC Address */
122735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0, 4);
123735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
124735143f1SXiaojuan Yang 
1258f30771cSTianrui Zhao     for (i = 0; i < arch_ids->len; i++) {
126735143f1SXiaojuan Yang         /* Processor Core Interrupt Controller Structure */
1278f30771cSTianrui Zhao         arch_id = arch_ids->cpus[i].arch_id;
1288f30771cSTianrui Zhao 
129735143f1SXiaojuan Yang         build_append_int_noprefix(table_data, 17, 1);    /* Type */
130735143f1SXiaojuan Yang         build_append_int_noprefix(table_data, 15, 1);    /* Length */
131735143f1SXiaojuan Yang         build_append_int_noprefix(table_data, 1, 1);     /* Version */
1323f6bec4aSJiajie Chen         build_append_int_noprefix(table_data, i, 4);     /* ACPI Processor ID */
1338f30771cSTianrui Zhao         build_append_int_noprefix(table_data, arch_id, 4); /* Core ID */
134735143f1SXiaojuan Yang         build_append_int_noprefix(table_data, 1, 4);     /* Flags */
135735143f1SXiaojuan Yang     }
136735143f1SXiaojuan Yang 
137735143f1SXiaojuan Yang     /* Extend I/O Interrupt Controller Structure */
138735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 20, 1);        /* Type */
139735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 13, 1);        /* Length */
140735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 1, 1);         /* Version */
141735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 3, 1);         /* Cascade */
142735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0, 1);         /* Node */
143735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0xffff, 8);    /* Node map */
144735143f1SXiaojuan Yang 
145735143f1SXiaojuan Yang     /* MSI Interrupt Controller Structure */
146735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 21, 1);        /* Type */
147735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 19, 1);        /* Length */
148735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 1, 1);         /* Version */
14974725231SXiaojuan Yang     build_append_int_noprefix(table_data, VIRT_PCH_MSI_ADDR_LOW, 8);/* Address */
150735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0x40, 4);      /* Start */
151735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0xc0, 4);      /* Count */
152735143f1SXiaojuan Yang 
153735143f1SXiaojuan Yang     /* Bridge I/O Interrupt Controller Structure */
154735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 22, 1);        /* Type */
155735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 17, 1);        /* Length */
156735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 1, 1);         /* Version */
15774725231SXiaojuan Yang     build_append_int_noprefix(table_data, VIRT_PCH_REG_BASE, 8);/* Address */
158735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0x1000, 2);    /* Size */
159735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0, 2);         /* Id */
160735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0x40, 2);      /* Base */
161735143f1SXiaojuan Yang 
162735143f1SXiaojuan Yang     acpi_table_end(linker, &table);
163735143f1SXiaojuan Yang }
164735143f1SXiaojuan Yang 
165735143f1SXiaojuan Yang /* build SRAT */
166735143f1SXiaojuan Yang static void
build_srat(GArray * table_data,BIOSLinker * linker,MachineState * machine)167735143f1SXiaojuan Yang build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
168735143f1SXiaojuan Yang {
1690cf1478dSTianrui Zhao     int i, arch_id, node_id;
170fc100011SBibo Mao     hwaddr len, base, gap;
171fc100011SBibo Mao     NodeInfo *numa_info;
172fc100011SBibo Mao     int nodes, nb_numa_nodes = machine->numa_state->num_nodes;
173d804ad98SBibo Mao     LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
174d804ad98SBibo Mao     MachineClass *mc = MACHINE_GET_CLASS(lvms);
1750cf1478dSTianrui Zhao     const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
176d804ad98SBibo Mao     AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lvms->oem_id,
177d804ad98SBibo Mao                         .oem_table_id = lvms->oem_table_id };
178735143f1SXiaojuan Yang 
179735143f1SXiaojuan Yang     acpi_table_begin(&table, table_data);
180735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 1, 4); /* Reserved */
181735143f1SXiaojuan Yang     build_append_int_noprefix(table_data, 0, 8); /* Reserved */
182735143f1SXiaojuan Yang 
1838f30771cSTianrui Zhao     for (i = 0; i < arch_ids->len; ++i) {
1848f30771cSTianrui Zhao         arch_id = arch_ids->cpus[i].arch_id;
1850cf1478dSTianrui Zhao         node_id = arch_ids->cpus[i].props.node_id;
1868f30771cSTianrui Zhao 
187735143f1SXiaojuan Yang         /* Processor Local APIC/SAPIC Affinity Structure */
188735143f1SXiaojuan Yang         build_append_int_noprefix(table_data, 0, 1);  /* Type  */
189735143f1SXiaojuan Yang         build_append_int_noprefix(table_data, 16, 1); /* Length */
190735143f1SXiaojuan Yang         /* Proximity Domain [7:0] */
1910cf1478dSTianrui Zhao         build_append_int_noprefix(table_data, node_id, 1);
1928f30771cSTianrui Zhao         build_append_int_noprefix(table_data, arch_id, 1); /* APIC ID */
193735143f1SXiaojuan Yang         /* Flags, Table 5-36 */
194735143f1SXiaojuan Yang         build_append_int_noprefix(table_data, 1, 4);
195735143f1SXiaojuan Yang         build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */
196735143f1SXiaojuan Yang         /* Proximity Domain [31:8] */
197735143f1SXiaojuan Yang         build_append_int_noprefix(table_data, 0, 3);
198735143f1SXiaojuan Yang         build_append_int_noprefix(table_data, 0, 4); /* Reserved */
199735143f1SXiaojuan Yang     }
200735143f1SXiaojuan Yang 
201fc100011SBibo Mao     base = VIRT_LOWMEM_BASE;
202fc100011SBibo Mao     gap = VIRT_LOWMEM_SIZE;
203fc100011SBibo Mao     numa_info = machine->numa_state->nodes;
204fc100011SBibo Mao     nodes = nb_numa_nodes;
205fc100011SBibo Mao     if (!nodes) {
206fc100011SBibo Mao         nodes = 1;
2070cf1478dSTianrui Zhao     }
208735143f1SXiaojuan Yang 
209fc100011SBibo Mao     for (i = 0; i < nodes; i++) {
2100cf1478dSTianrui Zhao         if (nb_numa_nodes) {
211fc100011SBibo Mao             len = numa_info[i].node_mem;
212fc100011SBibo Mao         } else {
213fc100011SBibo Mao             len = machine->ram_size;
2140cf1478dSTianrui Zhao         }
215fc100011SBibo Mao 
216fc100011SBibo Mao         /*
217fc100011SBibo Mao          * memory for the node splited into two part
218fc100011SBibo Mao          *   lowram:  [base, +gap)
219fc100011SBibo Mao          *   highram: [VIRT_HIGHMEM_BASE, +(len - gap))
220fc100011SBibo Mao          */
221fc100011SBibo Mao         if (len >= gap) {
222d4f5e5afSJiaxun Yang             build_srat_memory(table_data, base, gap, i, MEM_AFFINITY_ENABLED);
223fc100011SBibo Mao             len -= gap;
224fc100011SBibo Mao             base = VIRT_HIGHMEM_BASE;
225fc100011SBibo Mao             gap = machine->ram_size - VIRT_LOWMEM_SIZE;
226fc100011SBibo Mao         }
227fc100011SBibo Mao 
228fc100011SBibo Mao         if (len) {
229fc100011SBibo Mao             build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
230fc100011SBibo Mao             base += len;
231fc100011SBibo Mao             gap  -= len;
2320cf1478dSTianrui Zhao         }
2330cf1478dSTianrui Zhao     }
234735143f1SXiaojuan Yang 
2350cf1478dSTianrui Zhao     if (machine->device_memory) {
2360cf1478dSTianrui Zhao         build_srat_memory(table_data, machine->device_memory->base,
2370cf1478dSTianrui Zhao                           memory_region_size(&machine->device_memory->mr),
238fc100011SBibo Mao                           nodes - 1,
2390cf1478dSTianrui Zhao                           MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
240c3da26f3SXiaojuan Yang     }
241c3da26f3SXiaojuan Yang 
242735143f1SXiaojuan Yang     acpi_table_end(linker, &table);
243735143f1SXiaojuan Yang }
244735143f1SXiaojuan Yang 
245*45d1fe46SBibo Mao /*
246*45d1fe46SBibo Mao  * Serial Port Console Redirection Table (SPCR)
247*45d1fe46SBibo Mao  * https://learn.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table
248*45d1fe46SBibo Mao  */
249*45d1fe46SBibo Mao static void
spcr_setup(GArray * table_data,BIOSLinker * linker,MachineState * machine)250*45d1fe46SBibo Mao spcr_setup(GArray *table_data, BIOSLinker *linker, MachineState *machine)
251*45d1fe46SBibo Mao {
252*45d1fe46SBibo Mao     LoongArchVirtMachineState *lvms;
253*45d1fe46SBibo Mao     AcpiSpcrData serial = {
254*45d1fe46SBibo Mao         .interface_type = 0,       /* 16550 compatible */
255*45d1fe46SBibo Mao         .base_addr.id = AML_AS_SYSTEM_MEMORY,
256*45d1fe46SBibo Mao         .base_addr.width = 32,
257*45d1fe46SBibo Mao         .base_addr.offset = 0,
258*45d1fe46SBibo Mao         .base_addr.size = 1,
259*45d1fe46SBibo Mao         .base_addr.addr = VIRT_UART_BASE,
260*45d1fe46SBibo Mao         .interrupt_type = 0,       /* Interrupt not supported */
261*45d1fe46SBibo Mao         .pc_interrupt = 0,
262*45d1fe46SBibo Mao         .interrupt = VIRT_UART_IRQ,
263*45d1fe46SBibo Mao         .baud_rate = 7,            /* 115200 */
264*45d1fe46SBibo Mao         .parity = 0,
265*45d1fe46SBibo Mao         .stop_bits = 1,
266*45d1fe46SBibo Mao         .flow_control = 0,
267*45d1fe46SBibo Mao         .terminal_type = 3,        /* ANSI */
268*45d1fe46SBibo Mao         .language = 0,             /* Language */
269*45d1fe46SBibo Mao         .pci_device_id = 0xffff,   /* not a PCI device*/
270*45d1fe46SBibo Mao         .pci_vendor_id = 0xffff,   /* not a PCI device*/
271*45d1fe46SBibo Mao         .pci_bus = 0,
272*45d1fe46SBibo Mao         .pci_device = 0,
273*45d1fe46SBibo Mao         .pci_function = 0,
274*45d1fe46SBibo Mao         .pci_flags = 0,
275*45d1fe46SBibo Mao         .pci_segment = 0,
276*45d1fe46SBibo Mao     };
277*45d1fe46SBibo Mao 
278*45d1fe46SBibo Mao     lvms = LOONGARCH_VIRT_MACHINE(machine);
279*45d1fe46SBibo Mao     build_spcr(table_data, linker, &serial, 2, lvms->oem_id,
280*45d1fe46SBibo Mao                lvms->oem_table_id);
281*45d1fe46SBibo Mao }
282*45d1fe46SBibo Mao 
283735143f1SXiaojuan Yang typedef
284735143f1SXiaojuan Yang struct AcpiBuildState {
285735143f1SXiaojuan Yang     /* Copy of table in RAM (for patching). */
286735143f1SXiaojuan Yang     MemoryRegion *table_mr;
287735143f1SXiaojuan Yang     /* Is table patched? */
288735143f1SXiaojuan Yang     uint8_t patched;
289735143f1SXiaojuan Yang     void *rsdp;
290735143f1SXiaojuan Yang     MemoryRegion *rsdp_mr;
291735143f1SXiaojuan Yang     MemoryRegion *linker_mr;
292735143f1SXiaojuan Yang } AcpiBuildState;
293735143f1SXiaojuan Yang 
build_uart_device_aml(Aml * table,int index)294b3d4ef83SJason A. Donenfeld static void build_uart_device_aml(Aml *table, int index)
295735143f1SXiaojuan Yang {
296735143f1SXiaojuan Yang     Aml *dev;
297735143f1SXiaojuan Yang     Aml *crs;
298735143f1SXiaojuan Yang     Aml *pkg0, *pkg1, *pkg2;
299b3d4ef83SJason A. Donenfeld     Aml *scope;
300b3d4ef83SJason A. Donenfeld     uint32_t uart_irq;
301b3d4ef83SJason A. Donenfeld     uint64_t base;
302735143f1SXiaojuan Yang 
303b3d4ef83SJason A. Donenfeld     uart_irq = VIRT_UART_IRQ + index;
304b3d4ef83SJason A. Donenfeld     base = VIRT_UART_BASE + index * VIRT_UART_SIZE;
305b3d4ef83SJason A. Donenfeld     scope = aml_scope("_SB");
306b3d4ef83SJason A. Donenfeld     dev = aml_device("COM%d", index);
307735143f1SXiaojuan Yang     aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
308b3d4ef83SJason A. Donenfeld     aml_append(dev, aml_name_decl("_UID", aml_int(index)));
309735143f1SXiaojuan Yang     aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
310735143f1SXiaojuan Yang     crs = aml_resource_template();
311735143f1SXiaojuan Yang     aml_append(crs,
312735143f1SXiaojuan Yang         aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
313735143f1SXiaojuan Yang                          AML_NON_CACHEABLE, AML_READ_WRITE,
314b3d4ef83SJason A. Donenfeld                          0, base, base + VIRT_UART_SIZE - 1,
3154451cc46SXiaojuan Yang                          0, VIRT_UART_SIZE));
316735143f1SXiaojuan Yang     aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
317735143f1SXiaojuan Yang                                   AML_SHARED, &uart_irq, 1));
318735143f1SXiaojuan Yang     aml_append(dev, aml_name_decl("_CRS", crs));
319735143f1SXiaojuan Yang     pkg0 = aml_package(0x2);
320735143f1SXiaojuan Yang     aml_append(pkg0, aml_int(0x05F5E100));
321735143f1SXiaojuan Yang     aml_append(pkg0, aml_string("clock-frenquency"));
322735143f1SXiaojuan Yang     pkg1 = aml_package(0x1);
323735143f1SXiaojuan Yang     aml_append(pkg1, pkg0);
324735143f1SXiaojuan Yang     pkg2 = aml_package(0x2);
325735143f1SXiaojuan Yang     aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301"));
326735143f1SXiaojuan Yang     aml_append(pkg2, pkg1);
327735143f1SXiaojuan Yang     aml_append(dev, aml_name_decl("_DSD", pkg2));
328735143f1SXiaojuan Yang     aml_append(scope, dev);
329735143f1SXiaojuan Yang     aml_append(table, scope);
330735143f1SXiaojuan Yang }
331735143f1SXiaojuan Yang 
332c3da26f3SXiaojuan Yang static void
build_la_ged_aml(Aml * dsdt,MachineState * machine)333c3da26f3SXiaojuan Yang build_la_ged_aml(Aml *dsdt, MachineState *machine)
334c3da26f3SXiaojuan Yang {
335c3da26f3SXiaojuan Yang     uint32_t event;
336d804ad98SBibo Mao     LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
337c3da26f3SXiaojuan Yang 
338c3da26f3SXiaojuan Yang     build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
339d804ad98SBibo Mao                   HOTPLUG_HANDLER(lvms->acpi_ged),
340c3da26f3SXiaojuan Yang                   VIRT_SCI_IRQ, AML_SYSTEM_MEMORY,
341c3da26f3SXiaojuan Yang                   VIRT_GED_EVT_ADDR);
342d804ad98SBibo Mao     event = object_property_get_uint(OBJECT(lvms->acpi_ged),
343c3da26f3SXiaojuan Yang                                      "ged-event", &error_abort);
344c3da26f3SXiaojuan Yang     if (event & ACPI_GED_MEM_HOTPLUG_EVT) {
345c3da26f3SXiaojuan Yang         build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL,
346c3da26f3SXiaojuan Yang                                  AML_SYSTEM_MEMORY,
347c3da26f3SXiaojuan Yang                                  VIRT_GED_MEM_ADDR);
348c3da26f3SXiaojuan Yang     }
3490d588c4fSSong Gao     acpi_dsdt_add_power_button(dsdt);
350c3da26f3SXiaojuan Yang }
351c3da26f3SXiaojuan Yang 
build_pci_device_aml(Aml * scope,LoongArchVirtMachineState * lvms)352d804ad98SBibo Mao static void build_pci_device_aml(Aml *scope, LoongArchVirtMachineState *lvms)
3531895b967SXiaojuan Yang {
3541895b967SXiaojuan Yang     struct GPEXConfig cfg = {
3551895b967SXiaojuan Yang         .mmio64.base = VIRT_PCI_MEM_BASE,
3561895b967SXiaojuan Yang         .mmio64.size = VIRT_PCI_MEM_SIZE,
3571895b967SXiaojuan Yang         .pio.base    = VIRT_PCI_IO_BASE,
3581895b967SXiaojuan Yang         .pio.size    = VIRT_PCI_IO_SIZE,
3591895b967SXiaojuan Yang         .ecam.base   = VIRT_PCI_CFG_BASE,
3601895b967SXiaojuan Yang         .ecam.size   = VIRT_PCI_CFG_SIZE,
361456eb81fSBibo Mao         .irq         = VIRT_GSI_BASE + VIRT_DEVICE_IRQS,
362d804ad98SBibo Mao         .bus         = lvms->pci_bus,
3631895b967SXiaojuan Yang     };
3641895b967SXiaojuan Yang 
3651895b967SXiaojuan Yang     acpi_dsdt_add_gpex(scope, &cfg);
3661895b967SXiaojuan Yang }
3671895b967SXiaojuan Yang 
build_flash_aml(Aml * scope,LoongArchVirtMachineState * lvms)368d804ad98SBibo Mao static void build_flash_aml(Aml *scope, LoongArchVirtMachineState *lvms)
369288431a1SXiaojuan Yang {
370288431a1SXiaojuan Yang     Aml *dev, *crs;
371c6e9847fSXianglai Li     MemoryRegion *flash_mem;
372288431a1SXiaojuan Yang 
373c6e9847fSXianglai Li     hwaddr flash0_base;
374c6e9847fSXianglai Li     hwaddr flash0_size;
375c6e9847fSXianglai Li 
376c6e9847fSXianglai Li     hwaddr flash1_base;
377c6e9847fSXianglai Li     hwaddr flash1_size;
378c6e9847fSXianglai Li 
379d804ad98SBibo Mao     flash_mem = pflash_cfi01_get_memory(lvms->flash[0]);
380c6e9847fSXianglai Li     flash0_base = flash_mem->addr;
381c6e9847fSXianglai Li     flash0_size = memory_region_size(flash_mem);
382c6e9847fSXianglai Li 
383d804ad98SBibo Mao     flash_mem = pflash_cfi01_get_memory(lvms->flash[1]);
384c6e9847fSXianglai Li     flash1_base = flash_mem->addr;
385c6e9847fSXianglai Li     flash1_size = memory_region_size(flash_mem);
386288431a1SXiaojuan Yang 
387288431a1SXiaojuan Yang     dev = aml_device("FLS0");
388288431a1SXiaojuan Yang     aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
389288431a1SXiaojuan Yang     aml_append(dev, aml_name_decl("_UID", aml_int(0)));
390288431a1SXiaojuan Yang 
391288431a1SXiaojuan Yang     crs = aml_resource_template();
392c6e9847fSXianglai Li     aml_append(crs, aml_memory32_fixed(flash0_base, flash0_size,
393c6e9847fSXianglai Li                                        AML_READ_WRITE));
394c6e9847fSXianglai Li     aml_append(dev, aml_name_decl("_CRS", crs));
395c6e9847fSXianglai Li     aml_append(scope, dev);
396c6e9847fSXianglai Li 
397c6e9847fSXianglai Li     dev = aml_device("FLS1");
398c6e9847fSXianglai Li     aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
399c6e9847fSXianglai Li     aml_append(dev, aml_name_decl("_UID", aml_int(1)));
400c6e9847fSXianglai Li 
401c6e9847fSXianglai Li     crs = aml_resource_template();
402c6e9847fSXianglai Li     aml_append(crs, aml_memory32_fixed(flash1_base, flash1_size,
403c6e9847fSXianglai Li                                        AML_READ_WRITE));
404288431a1SXiaojuan Yang     aml_append(dev, aml_name_decl("_CRS", crs));
405288431a1SXiaojuan Yang     aml_append(scope, dev);
406288431a1SXiaojuan Yang }
407288431a1SXiaojuan Yang 
4083dfbb6deSXiaojuan Yang #ifdef CONFIG_TPM
acpi_dsdt_add_tpm(Aml * scope,LoongArchVirtMachineState * vms)409d804ad98SBibo Mao static void acpi_dsdt_add_tpm(Aml *scope, LoongArchVirtMachineState *vms)
4103dfbb6deSXiaojuan Yang {
4113dfbb6deSXiaojuan Yang     PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
4123dfbb6deSXiaojuan Yang     hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS;
4133dfbb6deSXiaojuan Yang     SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find());
4143dfbb6deSXiaojuan Yang     MemoryRegion *sbdev_mr;
4153dfbb6deSXiaojuan Yang     hwaddr tpm_base;
4163dfbb6deSXiaojuan Yang 
4173dfbb6deSXiaojuan Yang     if (!sbdev) {
4183dfbb6deSXiaojuan Yang         return;
4193dfbb6deSXiaojuan Yang     }
4203dfbb6deSXiaojuan Yang 
4213dfbb6deSXiaojuan Yang     tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
4223dfbb6deSXiaojuan Yang     assert(tpm_base != -1);
4233dfbb6deSXiaojuan Yang 
4243dfbb6deSXiaojuan Yang     tpm_base += pbus_base;
4253dfbb6deSXiaojuan Yang 
4263dfbb6deSXiaojuan Yang     sbdev_mr = sysbus_mmio_get_region(sbdev, 0);
4273dfbb6deSXiaojuan Yang 
4283dfbb6deSXiaojuan Yang     Aml *dev = aml_device("TPM0");
4293dfbb6deSXiaojuan Yang     aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
4303dfbb6deSXiaojuan Yang     aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device")));
4313dfbb6deSXiaojuan Yang     aml_append(dev, aml_name_decl("_UID", aml_int(0)));
4323dfbb6deSXiaojuan Yang 
4333dfbb6deSXiaojuan Yang     Aml *crs = aml_resource_template();
4343dfbb6deSXiaojuan Yang     aml_append(crs,
4353dfbb6deSXiaojuan Yang                aml_memory32_fixed(tpm_base,
4363dfbb6deSXiaojuan Yang                                   (uint32_t)memory_region_size(sbdev_mr),
4373dfbb6deSXiaojuan Yang                                   AML_READ_WRITE));
4383dfbb6deSXiaojuan Yang     aml_append(dev, aml_name_decl("_CRS", crs));
4393dfbb6deSXiaojuan Yang     aml_append(scope, dev);
4403dfbb6deSXiaojuan Yang }
4413dfbb6deSXiaojuan Yang #endif
4423dfbb6deSXiaojuan Yang 
443735143f1SXiaojuan Yang /* build DSDT */
444735143f1SXiaojuan Yang static void
build_dsdt(GArray * table_data,BIOSLinker * linker,MachineState * machine)445735143f1SXiaojuan Yang build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
446735143f1SXiaojuan Yang {
447b3d4ef83SJason A. Donenfeld     int i;
4481895b967SXiaojuan Yang     Aml *dsdt, *scope, *pkg;
449d804ad98SBibo Mao     LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
450d804ad98SBibo Mao     AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lvms->oem_id,
451d804ad98SBibo Mao                         .oem_table_id = lvms->oem_table_id };
452735143f1SXiaojuan Yang 
453735143f1SXiaojuan Yang     acpi_table_begin(&table, table_data);
454735143f1SXiaojuan Yang     dsdt = init_aml_allocator();
455b3d4ef83SJason A. Donenfeld     for (i = 0; i < VIRT_UART_COUNT; i++)
456b3d4ef83SJason A. Donenfeld         build_uart_device_aml(dsdt, i);
457d804ad98SBibo Mao     build_pci_device_aml(dsdt, lvms);
458c3da26f3SXiaojuan Yang     build_la_ged_aml(dsdt, machine);
459d804ad98SBibo Mao     build_flash_aml(dsdt, lvms);
4603dfbb6deSXiaojuan Yang #ifdef CONFIG_TPM
461d804ad98SBibo Mao     acpi_dsdt_add_tpm(dsdt, lvms);
4623dfbb6deSXiaojuan Yang #endif
463735143f1SXiaojuan Yang     /* System State Package */
464735143f1SXiaojuan Yang     scope = aml_scope("\\");
465735143f1SXiaojuan Yang     pkg = aml_package(4);
466735143f1SXiaojuan Yang     aml_append(pkg, aml_int(ACPI_GED_SLP_TYP_S5));
467735143f1SXiaojuan Yang     aml_append(pkg, aml_int(0)); /* ignored */
468735143f1SXiaojuan Yang     aml_append(pkg, aml_int(0)); /* reserved */
469735143f1SXiaojuan Yang     aml_append(pkg, aml_int(0)); /* reserved */
470735143f1SXiaojuan Yang     aml_append(scope, aml_name_decl("_S5", pkg));
471735143f1SXiaojuan Yang     aml_append(dsdt, scope);
472735143f1SXiaojuan Yang     /* Copy AML table into ACPI tables blob and patch header there */
473735143f1SXiaojuan Yang     g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
474735143f1SXiaojuan Yang     acpi_table_end(linker, &table);
475735143f1SXiaojuan Yang     free_aml_allocator();
476735143f1SXiaojuan Yang }
477735143f1SXiaojuan Yang 
acpi_build(AcpiBuildTables * tables,MachineState * machine)478735143f1SXiaojuan Yang static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
479735143f1SXiaojuan Yang {
480d804ad98SBibo Mao     LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
481735143f1SXiaojuan Yang     GArray *table_offsets;
482735143f1SXiaojuan Yang     AcpiFadtData fadt_data;
4834cbadc40SSong Gao     unsigned facs, rsdt, dsdt;
484735143f1SXiaojuan Yang     uint8_t *u;
485735143f1SXiaojuan Yang     GArray *tables_blob = tables->table_data;
486735143f1SXiaojuan Yang 
487735143f1SXiaojuan Yang     init_common_fadt_data(&fadt_data);
488735143f1SXiaojuan Yang 
489735143f1SXiaojuan Yang     table_offsets = g_array_new(false, true, sizeof(uint32_t));
490735143f1SXiaojuan Yang     ACPI_BUILD_DPRINTF("init ACPI tables\n");
491735143f1SXiaojuan Yang 
492735143f1SXiaojuan Yang     bios_linker_loader_alloc(tables->linker,
493735143f1SXiaojuan Yang                              ACPI_BUILD_TABLE_FILE, tables_blob,
494735143f1SXiaojuan Yang                              64, false);
495735143f1SXiaojuan Yang 
496735143f1SXiaojuan Yang     /*
497735143f1SXiaojuan Yang      * FACS is pointed to by FADT.
498735143f1SXiaojuan Yang      * We place it first since it's the only table that has alignment
499735143f1SXiaojuan Yang      * requirements.
500735143f1SXiaojuan Yang      */
501735143f1SXiaojuan Yang     facs = tables_blob->len;
502735143f1SXiaojuan Yang     build_facs(tables_blob);
503735143f1SXiaojuan Yang 
504735143f1SXiaojuan Yang     /* DSDT is pointed to by FADT */
505735143f1SXiaojuan Yang     dsdt = tables_blob->len;
506735143f1SXiaojuan Yang     build_dsdt(tables_blob, tables->linker, machine);
507735143f1SXiaojuan Yang 
508735143f1SXiaojuan Yang     /* ACPI tables pointed to by RSDT */
509735143f1SXiaojuan Yang     acpi_add_table(table_offsets, tables_blob);
510735143f1SXiaojuan Yang     fadt_data.facs_tbl_offset = &facs;
511735143f1SXiaojuan Yang     fadt_data.dsdt_tbl_offset = &dsdt;
512735143f1SXiaojuan Yang     fadt_data.xdsdt_tbl_offset = &dsdt;
513735143f1SXiaojuan Yang     build_fadt(tables_blob, tables->linker, &fadt_data,
514d804ad98SBibo Mao                lvms->oem_id, lvms->oem_table_id);
515735143f1SXiaojuan Yang 
516735143f1SXiaojuan Yang     acpi_add_table(table_offsets, tables_blob);
517d804ad98SBibo Mao     build_madt(tables_blob, tables->linker, lvms);
518735143f1SXiaojuan Yang 
519735143f1SXiaojuan Yang     acpi_add_table(table_offsets, tables_blob);
520f3323883STianrui Zhao     build_pptt(tables_blob, tables->linker, machine,
521d804ad98SBibo Mao                lvms->oem_id, lvms->oem_table_id);
522f3323883STianrui Zhao 
523f3323883STianrui Zhao     acpi_add_table(table_offsets, tables_blob);
524735143f1SXiaojuan Yang     build_srat(tables_blob, tables->linker, machine);
525*45d1fe46SBibo Mao     acpi_add_table(table_offsets, tables_blob);
526*45d1fe46SBibo Mao     spcr_setup(tables_blob, tables->linker, machine);
527735143f1SXiaojuan Yang 
5280cf1478dSTianrui Zhao     if (machine->numa_state->num_nodes) {
5290cf1478dSTianrui Zhao         if (machine->numa_state->have_numa_distance) {
5300cf1478dSTianrui Zhao             acpi_add_table(table_offsets, tables_blob);
531d804ad98SBibo Mao             build_slit(tables_blob, tables->linker, machine, lvms->oem_id,
532d804ad98SBibo Mao                        lvms->oem_table_id);
5330cf1478dSTianrui Zhao         }
5340cf1478dSTianrui Zhao         if (machine->numa_state->hmat_enabled) {
5350cf1478dSTianrui Zhao             acpi_add_table(table_offsets, tables_blob);
5360cf1478dSTianrui Zhao             build_hmat(tables_blob, tables->linker, machine->numa_state,
537d804ad98SBibo Mao                        lvms->oem_id, lvms->oem_table_id);
5380cf1478dSTianrui Zhao         }
5390cf1478dSTianrui Zhao     }
5400cf1478dSTianrui Zhao 
541735143f1SXiaojuan Yang     acpi_add_table(table_offsets, tables_blob);
542735143f1SXiaojuan Yang     {
543735143f1SXiaojuan Yang         AcpiMcfgInfo mcfg = {
54474725231SXiaojuan Yang            .base = cpu_to_le64(VIRT_PCI_CFG_BASE),
54574725231SXiaojuan Yang            .size = cpu_to_le64(VIRT_PCI_CFG_SIZE),
546735143f1SXiaojuan Yang         };
547d804ad98SBibo Mao         build_mcfg(tables_blob, tables->linker, &mcfg, lvms->oem_id,
548d804ad98SBibo Mao                    lvms->oem_table_id);
549735143f1SXiaojuan Yang     }
550735143f1SXiaojuan Yang 
5513dfbb6deSXiaojuan Yang #ifdef CONFIG_TPM
5523dfbb6deSXiaojuan Yang     /* TPM info */
5533dfbb6deSXiaojuan Yang     if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) {
5543dfbb6deSXiaojuan Yang         acpi_add_table(table_offsets, tables_blob);
5553dfbb6deSXiaojuan Yang         build_tpm2(tables_blob, tables->linker,
556d804ad98SBibo Mao                    tables->tcpalog, lvms->oem_id,
557d804ad98SBibo Mao                    lvms->oem_table_id);
5583dfbb6deSXiaojuan Yang     }
5593dfbb6deSXiaojuan Yang #endif
560735143f1SXiaojuan Yang     /* Add tables supplied by user (if any) */
561735143f1SXiaojuan Yang     for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
562735143f1SXiaojuan Yang         unsigned len = acpi_table_len(u);
563735143f1SXiaojuan Yang 
564735143f1SXiaojuan Yang         acpi_add_table(table_offsets, tables_blob);
565735143f1SXiaojuan Yang         g_array_append_vals(tables_blob, u, len);
566735143f1SXiaojuan Yang     }
567735143f1SXiaojuan Yang 
568735143f1SXiaojuan Yang     /* RSDT is pointed to by RSDP */
569735143f1SXiaojuan Yang     rsdt = tables_blob->len;
570735143f1SXiaojuan Yang     build_rsdt(tables_blob, tables->linker, table_offsets,
571d804ad98SBibo Mao                lvms->oem_id, lvms->oem_table_id);
572735143f1SXiaojuan Yang 
573735143f1SXiaojuan Yang     /* RSDP is in FSEG memory, so allocate it separately */
574735143f1SXiaojuan Yang     {
575735143f1SXiaojuan Yang         AcpiRsdpData rsdp_data = {
576735143f1SXiaojuan Yang             .revision = 0,
577d804ad98SBibo Mao             .oem_id = lvms->oem_id,
578735143f1SXiaojuan Yang             .xsdt_tbl_offset = NULL,
579735143f1SXiaojuan Yang             .rsdt_tbl_offset = &rsdt,
580735143f1SXiaojuan Yang         };
581735143f1SXiaojuan Yang         build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
582735143f1SXiaojuan Yang     }
583735143f1SXiaojuan Yang 
584735143f1SXiaojuan Yang     /*
585735143f1SXiaojuan Yang      * The align size is 128, warn if 64k is not enough therefore
586735143f1SXiaojuan Yang      * the align size could be resized.
587735143f1SXiaojuan Yang      */
588735143f1SXiaojuan Yang     if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
589735143f1SXiaojuan Yang         warn_report("ACPI table size %u exceeds %d bytes,"
590735143f1SXiaojuan Yang                     " migration may not work",
591735143f1SXiaojuan Yang                     tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
592735143f1SXiaojuan Yang         error_printf("Try removing CPUs, NUMA nodes, memory slots"
5937e487d8cSGreg Kurz                      " or PCI bridges.\n");
594735143f1SXiaojuan Yang     }
595735143f1SXiaojuan Yang 
596735143f1SXiaojuan Yang     acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE);
597735143f1SXiaojuan Yang 
598735143f1SXiaojuan Yang     /* Cleanup memory that's no longer used. */
599735143f1SXiaojuan Yang     g_array_free(table_offsets, true);
600735143f1SXiaojuan Yang }
601735143f1SXiaojuan Yang 
acpi_ram_update(MemoryRegion * mr,GArray * data)602735143f1SXiaojuan Yang static void acpi_ram_update(MemoryRegion *mr, GArray *data)
603735143f1SXiaojuan Yang {
604735143f1SXiaojuan Yang     uint32_t size = acpi_data_len(data);
605735143f1SXiaojuan Yang 
606735143f1SXiaojuan Yang     /*
607735143f1SXiaojuan Yang      * Make sure RAM size is correct - in case it got changed
608735143f1SXiaojuan Yang      * e.g. by migration
609735143f1SXiaojuan Yang      */
610735143f1SXiaojuan Yang     memory_region_ram_resize(mr, size, &error_abort);
611735143f1SXiaojuan Yang 
612735143f1SXiaojuan Yang     memcpy(memory_region_get_ram_ptr(mr), data->data, size);
613735143f1SXiaojuan Yang     memory_region_set_dirty(mr, 0, size);
614735143f1SXiaojuan Yang }
615735143f1SXiaojuan Yang 
acpi_build_update(void * build_opaque)616735143f1SXiaojuan Yang static void acpi_build_update(void *build_opaque)
617735143f1SXiaojuan Yang {
618735143f1SXiaojuan Yang     AcpiBuildState *build_state = build_opaque;
619735143f1SXiaojuan Yang     AcpiBuildTables tables;
620735143f1SXiaojuan Yang 
621735143f1SXiaojuan Yang     /* No state to update or already patched? Nothing to do. */
622735143f1SXiaojuan Yang     if (!build_state || build_state->patched) {
623735143f1SXiaojuan Yang         return;
624735143f1SXiaojuan Yang     }
625735143f1SXiaojuan Yang     build_state->patched = 1;
626735143f1SXiaojuan Yang 
627735143f1SXiaojuan Yang     acpi_build_tables_init(&tables);
628735143f1SXiaojuan Yang 
629735143f1SXiaojuan Yang     acpi_build(&tables, MACHINE(qdev_get_machine()));
630735143f1SXiaojuan Yang 
631735143f1SXiaojuan Yang     acpi_ram_update(build_state->table_mr, tables.table_data);
632735143f1SXiaojuan Yang     acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
633735143f1SXiaojuan Yang     acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
634735143f1SXiaojuan Yang 
635735143f1SXiaojuan Yang     acpi_build_tables_cleanup(&tables, true);
636735143f1SXiaojuan Yang }
637735143f1SXiaojuan Yang 
acpi_build_reset(void * build_opaque)638735143f1SXiaojuan Yang static void acpi_build_reset(void *build_opaque)
639735143f1SXiaojuan Yang {
640735143f1SXiaojuan Yang     AcpiBuildState *build_state = build_opaque;
641735143f1SXiaojuan Yang     build_state->patched = 0;
642735143f1SXiaojuan Yang }
643735143f1SXiaojuan Yang 
644735143f1SXiaojuan Yang static const VMStateDescription vmstate_acpi_build = {
645735143f1SXiaojuan Yang     .name = "acpi_build",
646735143f1SXiaojuan Yang     .version_id = 1,
647735143f1SXiaojuan Yang     .minimum_version_id = 1,
648aa4941bbSRichard Henderson     .fields = (const VMStateField[]) {
649735143f1SXiaojuan Yang         VMSTATE_UINT8(patched, AcpiBuildState),
650735143f1SXiaojuan Yang         VMSTATE_END_OF_LIST()
651735143f1SXiaojuan Yang     },
652735143f1SXiaojuan Yang };
653735143f1SXiaojuan Yang 
loongarch_is_acpi_enabled(LoongArchVirtMachineState * lvms)654d804ad98SBibo Mao static bool loongarch_is_acpi_enabled(LoongArchVirtMachineState *lvms)
655d804ad98SBibo Mao {
656d804ad98SBibo Mao     if (lvms->acpi == ON_OFF_AUTO_OFF) {
657d804ad98SBibo Mao         return false;
658d804ad98SBibo Mao     }
659d804ad98SBibo Mao     return true;
660d804ad98SBibo Mao }
661d804ad98SBibo Mao 
loongarch_acpi_setup(LoongArchVirtMachineState * lvms)662d804ad98SBibo Mao void loongarch_acpi_setup(LoongArchVirtMachineState *lvms)
663735143f1SXiaojuan Yang {
664735143f1SXiaojuan Yang     AcpiBuildTables tables;
665735143f1SXiaojuan Yang     AcpiBuildState *build_state;
666735143f1SXiaojuan Yang 
667d804ad98SBibo Mao     if (!lvms->fw_cfg) {
668735143f1SXiaojuan Yang         ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
669735143f1SXiaojuan Yang         return;
670735143f1SXiaojuan Yang     }
671735143f1SXiaojuan Yang 
672d804ad98SBibo Mao     if (!loongarch_is_acpi_enabled(lvms)) {
673735143f1SXiaojuan Yang         ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
674735143f1SXiaojuan Yang         return;
675735143f1SXiaojuan Yang     }
676735143f1SXiaojuan Yang 
677735143f1SXiaojuan Yang     build_state = g_malloc0(sizeof *build_state);
678735143f1SXiaojuan Yang 
679735143f1SXiaojuan Yang     acpi_build_tables_init(&tables);
680d804ad98SBibo Mao     acpi_build(&tables, MACHINE(lvms));
681735143f1SXiaojuan Yang 
682735143f1SXiaojuan Yang     /* Now expose it all to Guest */
683735143f1SXiaojuan Yang     build_state->table_mr = acpi_add_rom_blob(acpi_build_update,
684735143f1SXiaojuan Yang                                               build_state, tables.table_data,
685735143f1SXiaojuan Yang                                               ACPI_BUILD_TABLE_FILE);
686735143f1SXiaojuan Yang     assert(build_state->table_mr != NULL);
687735143f1SXiaojuan Yang 
688735143f1SXiaojuan Yang     build_state->linker_mr =
689735143f1SXiaojuan Yang         acpi_add_rom_blob(acpi_build_update, build_state,
690735143f1SXiaojuan Yang                           tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE);
691735143f1SXiaojuan Yang 
692735143f1SXiaojuan Yang     build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update,
693735143f1SXiaojuan Yang                                              build_state, tables.rsdp,
694735143f1SXiaojuan Yang                                              ACPI_BUILD_RSDP_FILE);
695735143f1SXiaojuan Yang 
6960aca7364SXianglai Li     fw_cfg_add_file(lvms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data,
6970aca7364SXianglai Li                     acpi_data_len(tables.tcpalog));
6980aca7364SXianglai Li 
699735143f1SXiaojuan Yang     qemu_register_reset(acpi_build_reset, build_state);
700735143f1SXiaojuan Yang     acpi_build_reset(build_state);
701735143f1SXiaojuan Yang     vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
702735143f1SXiaojuan Yang 
703735143f1SXiaojuan Yang     /*
704735143f1SXiaojuan Yang      * Cleanup tables but don't free the memory: we track it
705735143f1SXiaojuan Yang      * in build_state.
706735143f1SXiaojuan Yang      */
707735143f1SXiaojuan Yang     acpi_build_tables_cleanup(&tables, false);
708735143f1SXiaojuan Yang }
709