xref: /openbmc/qemu/hw/loongarch/acpi-build.c (revision 44602af8)
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/bitmap.h"
11 #include "hw/pci/pci.h"
12 #include "hw/core/cpu.h"
13 #include "target/loongarch/cpu.h"
14 #include "hw/acpi/acpi-defs.h"
15 #include "hw/acpi/acpi.h"
16 #include "hw/nvram/fw_cfg.h"
17 #include "hw/acpi/bios-linker-loader.h"
18 #include "migration/vmstate.h"
19 #include "hw/mem/memory-device.h"
20 #include "sysemu/reset.h"
21 
22 /* Supported chipsets: */
23 #include "hw/pci-host/ls7a.h"
24 #include "hw/loongarch/virt.h"
25 #include "hw/acpi/aml-build.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 
34 #define ACPI_BUILD_ALIGN_SIZE             0x1000
35 #define ACPI_BUILD_TABLE_SIZE             0x20000
36 
37 #ifdef DEBUG_ACPI_BUILD
38 #define ACPI_BUILD_DPRINTF(fmt, ...)        \
39     do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0)
40 #else
41 #define ACPI_BUILD_DPRINTF(fmt, ...)
42 #endif
43 
44 /* build FADT */
45 static void init_common_fadt_data(AcpiFadtData *data)
46 {
47     AcpiFadtData fadt = {
48         /* ACPI 5.0: 4.1 Hardware-Reduced ACPI */
49         .rev = 5,
50         .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) |
51                   (1 << ACPI_FADT_F_RESET_REG_SUP)),
52 
53         /* ACPI 5.0: 4.8.3.7 Sleep Control and Status Registers */
54         .sleep_ctl = {
55             .space_id = AML_AS_SYSTEM_MEMORY,
56             .bit_width = 8,
57             .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_CTL,
58         },
59         .sleep_sts = {
60             .space_id = AML_AS_SYSTEM_MEMORY,
61             .bit_width = 8,
62             .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_SLEEP_STS,
63         },
64 
65         /* ACPI 5.0: 4.8.3.6 Reset Register */
66         .reset_reg = {
67             .space_id = AML_AS_SYSTEM_MEMORY,
68             .bit_width = 8,
69             .address = VIRT_GED_REG_ADDR + ACPI_GED_REG_RESET,
70         },
71         .reset_val = ACPI_GED_RESET_VALUE,
72     };
73     *data = fadt;
74 }
75 
76 static void acpi_align_size(GArray *blob, unsigned align)
77 {
78     /*
79      * Align size to multiple of given size. This reduces the chance
80      * we need to change size in the future (breaking cross version migration).
81      */
82     g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
83 }
84 
85 /* build FACS */
86 static void
87 build_facs(GArray *table_data)
88 {
89     const char *sig = "FACS";
90     const uint8_t reserved[40] = {};
91 
92     g_array_append_vals(table_data, sig, 4); /* Signature */
93     build_append_int_noprefix(table_data, 64, 4); /* Length */
94     build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */
95     build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */
96     build_append_int_noprefix(table_data, 0, 4); /* Global Lock */
97     build_append_int_noprefix(table_data, 0, 4); /* Flags */
98     g_array_append_vals(table_data, reserved, 40); /* Reserved */
99 }
100 
101 /* build MADT */
102 static void
103 build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams)
104 {
105     MachineState *ms = MACHINE(lams);
106     int i;
107     AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id,
108                         .oem_table_id = lams->oem_table_id };
109 
110     acpi_table_begin(&table, table_data);
111 
112     /* Local APIC Address */
113     build_append_int_noprefix(table_data, 0, 4);
114     build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
115 
116     for (i = 0; i < ms->smp.cpus; i++) {
117         /* Processor Core Interrupt Controller Structure */
118         build_append_int_noprefix(table_data, 17, 1);    /* Type */
119         build_append_int_noprefix(table_data, 15, 1);    /* Length */
120         build_append_int_noprefix(table_data, 1, 1);     /* Version */
121         build_append_int_noprefix(table_data, i + 1, 4); /* ACPI Processor ID */
122         build_append_int_noprefix(table_data, i, 4);     /* Core ID */
123         build_append_int_noprefix(table_data, 1, 4);     /* Flags */
124     }
125 
126     /* Extend I/O Interrupt Controller Structure */
127     build_append_int_noprefix(table_data, 20, 1);        /* Type */
128     build_append_int_noprefix(table_data, 13, 1);        /* Length */
129     build_append_int_noprefix(table_data, 1, 1);         /* Version */
130     build_append_int_noprefix(table_data, 3, 1);         /* Cascade */
131     build_append_int_noprefix(table_data, 0, 1);         /* Node */
132     build_append_int_noprefix(table_data, 0xffff, 8);    /* Node map */
133 
134     /* MSI Interrupt Controller Structure */
135     build_append_int_noprefix(table_data, 21, 1);        /* Type */
136     build_append_int_noprefix(table_data, 19, 1);        /* Length */
137     build_append_int_noprefix(table_data, 1, 1);         /* Version */
138     build_append_int_noprefix(table_data, LS7A_PCH_MSI_ADDR_LOW, 8);/* Address */
139     build_append_int_noprefix(table_data, 0x40, 4);      /* Start */
140     build_append_int_noprefix(table_data, 0xc0, 4);      /* Count */
141 
142     /* Bridge I/O Interrupt Controller Structure */
143     build_append_int_noprefix(table_data, 22, 1);        /* Type */
144     build_append_int_noprefix(table_data, 17, 1);        /* Length */
145     build_append_int_noprefix(table_data, 1, 1);         /* Version */
146     build_append_int_noprefix(table_data, LS7A_PCH_REG_BASE, 8);/* Address */
147     build_append_int_noprefix(table_data, 0x1000, 2);    /* Size */
148     build_append_int_noprefix(table_data, 0, 2);         /* Id */
149     build_append_int_noprefix(table_data, 0x40, 2);      /* Base */
150 
151     acpi_table_end(linker, &table);
152 }
153 
154 /* build SRAT */
155 static void
156 build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
157 {
158     uint64_t i;
159     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
160     MachineState *ms = MACHINE(lams);
161     AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
162                         .oem_table_id = lams->oem_table_id };
163 
164     acpi_table_begin(&table, table_data);
165     build_append_int_noprefix(table_data, 1, 4); /* Reserved */
166     build_append_int_noprefix(table_data, 0, 8); /* Reserved */
167 
168     for (i = 0; i < ms->smp.cpus; ++i) {
169         /* Processor Local APIC/SAPIC Affinity Structure */
170         build_append_int_noprefix(table_data, 0, 1);  /* Type  */
171         build_append_int_noprefix(table_data, 16, 1); /* Length */
172         /* Proximity Domain [7:0] */
173         build_append_int_noprefix(table_data, 0, 1);
174         build_append_int_noprefix(table_data, i, 1); /* APIC ID */
175         /* Flags, Table 5-36 */
176         build_append_int_noprefix(table_data, 1, 4);
177         build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */
178         /* Proximity Domain [31:8] */
179         build_append_int_noprefix(table_data, 0, 3);
180         build_append_int_noprefix(table_data, 0, 4); /* Reserved */
181     }
182 
183     build_srat_memory(table_data, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE,
184                       0, MEM_AFFINITY_ENABLED);
185 
186     build_srat_memory(table_data, VIRT_HIGHMEM_BASE, machine->ram_size - VIRT_LOWMEM_SIZE,
187                       0, MEM_AFFINITY_ENABLED);
188 
189     acpi_table_end(linker, &table);
190 }
191 
192 typedef
193 struct AcpiBuildState {
194     /* Copy of table in RAM (for patching). */
195     MemoryRegion *table_mr;
196     /* Is table patched? */
197     uint8_t patched;
198     void *rsdp;
199     MemoryRegion *rsdp_mr;
200     MemoryRegion *linker_mr;
201 } AcpiBuildState;
202 
203 static void build_gpex_pci0_int(Aml *table)
204 {
205     Aml *sb_scope = aml_scope("_SB");
206     Aml *pci0_scope = aml_scope("PCI0");
207     Aml *prt_pkg = aml_varpackage(128);
208     int slot, pin;
209 
210     for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
211         for (pin = 0; pin < PCI_NUM_PINS; pin++) {
212             Aml *pkg = aml_package(4);
213             aml_append(pkg, aml_int((slot << 16) | 0xFFFF));
214             aml_append(pkg, aml_int(pin));
215             aml_append(pkg, aml_int(0));
216             aml_append(pkg, aml_int(80 + (slot + pin) % 4));
217             aml_append(prt_pkg, pkg);
218         }
219     }
220     aml_append(pci0_scope, aml_name_decl("_PRT", prt_pkg));
221     aml_append(sb_scope, pci0_scope);
222     aml_append(table, sb_scope);
223 }
224 
225 static void build_dbg_aml(Aml *table)
226 {
227     Aml *field;
228     Aml *method;
229     Aml *while_ctx;
230     Aml *scope = aml_scope("\\");
231     Aml *buf = aml_local(0);
232     Aml *len = aml_local(1);
233     Aml *idx = aml_local(2);
234 
235     aml_append(scope,
236        aml_operation_region("DBG", AML_SYSTEM_IO, aml_int(0x0402), 0x01));
237     field = aml_field("DBG", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
238     aml_append(field, aml_named_field("DBGB", 8));
239     aml_append(scope, field);
240 
241     method = aml_method("DBUG", 1, AML_NOTSERIALIZED);
242 
243     aml_append(method, aml_to_hexstring(aml_arg(0), buf));
244     aml_append(method, aml_to_buffer(buf, buf));
245     aml_append(method, aml_subtract(aml_sizeof(buf), aml_int(1), len));
246     aml_append(method, aml_store(aml_int(0), idx));
247 
248     while_ctx = aml_while(aml_lless(idx, len));
249     aml_append(while_ctx,
250         aml_store(aml_derefof(aml_index(buf, idx)), aml_name("DBGB")));
251     aml_append(while_ctx, aml_increment(idx));
252     aml_append(method, while_ctx);
253     aml_append(method, aml_store(aml_int(0x0A), aml_name("DBGB")));
254     aml_append(scope, method);
255     aml_append(table, scope);
256 }
257 
258 static Aml *build_osc_method(void)
259 {
260     Aml *if_ctx;
261     Aml *if_ctx2;
262     Aml *else_ctx;
263     Aml *method;
264     Aml *a_cwd1 = aml_name("CDW1");
265     Aml *a_ctrl = aml_local(0);
266 
267     method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
268     aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
269 
270     if_ctx = aml_if(aml_equal(
271         aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")));
272     aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
273     aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
274     aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl));
275 
276     /*
277      * Always allow native PME, AER (no dependencies)
278      * Allow SHPC (PCI bridges can have SHPC controller)
279      */
280     aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl));
281 
282     if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1))));
283     /* Unknown revision */
284     aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1));
285     aml_append(if_ctx, if_ctx2);
286 
287     if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl)));
288     /* Capabilities bits were masked */
289     aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1));
290     aml_append(if_ctx, if_ctx2);
291 
292     /* Update DWORD3 in the buffer */
293     aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3")));
294     aml_append(method, if_ctx);
295 
296     else_ctx = aml_else();
297     /* Unrecognized UUID */
298     aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1));
299     aml_append(method, else_ctx);
300 
301     aml_append(method, aml_return(aml_arg(3)));
302     return method;
303 }
304 
305 static void build_uart_device_aml(Aml *table)
306 {
307     Aml *dev;
308     Aml *crs;
309     Aml *pkg0, *pkg1, *pkg2;
310     uint32_t uart_irq = LS7A_UART_IRQ;
311 
312     Aml *scope = aml_scope("_SB");
313     dev = aml_device("COMA");
314     aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
315     aml_append(dev, aml_name_decl("_UID", aml_int(0)));
316     aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
317     crs = aml_resource_template();
318     aml_append(crs,
319         aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
320                          AML_NON_CACHEABLE, AML_READ_WRITE,
321                          0, 0x1FE001E0, 0x1FE001E7, 0, 0x8));
322     aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
323                                   AML_SHARED, &uart_irq, 1));
324     aml_append(dev, aml_name_decl("_CRS", crs));
325     pkg0 = aml_package(0x2);
326     aml_append(pkg0, aml_int(0x05F5E100));
327     aml_append(pkg0, aml_string("clock-frenquency"));
328     pkg1 = aml_package(0x1);
329     aml_append(pkg1, pkg0);
330     pkg2 = aml_package(0x2);
331     aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301"));
332     aml_append(pkg2, pkg1);
333     aml_append(dev, aml_name_decl("_DSD", pkg2));
334     aml_append(scope, dev);
335     aml_append(table, scope);
336 }
337 
338 /* build DSDT */
339 static void
340 build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
341 {
342     Aml *dsdt, *sb_scope, *scope, *dev, *crs, *pkg;
343     int root_bus_limit = 0x7F;
344     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
345     AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
346                         .oem_table_id = lams->oem_table_id };
347 
348     acpi_table_begin(&table, table_data);
349 
350     dsdt = init_aml_allocator();
351 
352     build_dbg_aml(dsdt);
353 
354     sb_scope = aml_scope("_SB");
355     dev = aml_device("PCI0");
356     aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
357     aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
358     aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
359     aml_append(dev, aml_name_decl("_BBN", aml_int(0)));
360     aml_append(dev, aml_name_decl("_UID", aml_int(1)));
361     aml_append(dev, build_osc_method());
362     aml_append(sb_scope, dev);
363     aml_append(dsdt, sb_scope);
364 
365     build_gpex_pci0_int(dsdt);
366     build_uart_device_aml(dsdt);
367     if (lams->acpi_ged) {
368         build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
369                       HOTPLUG_HANDLER(lams->acpi_ged),
370                       LS7A_SCI_IRQ - PCH_PIC_IRQ_OFFSET, AML_SYSTEM_MEMORY,
371                       VIRT_GED_EVT_ADDR);
372     }
373 
374     scope = aml_scope("\\_SB.PCI0");
375     /* Build PCI0._CRS */
376     crs = aml_resource_template();
377     aml_append(crs,
378         aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
379                             0x0000, 0x0, root_bus_limit,
380                             0x0000, root_bus_limit + 1));
381     aml_append(crs,
382         aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED,
383                     AML_POS_DECODE, AML_ENTIRE_RANGE,
384                     0x0000, 0x0000, 0xFFFF, 0x18000000, 0x10000));
385     aml_append(crs,
386         aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
387                          AML_CACHEABLE, AML_READ_WRITE,
388                          0, LS7A_PCI_MEM_BASE,
389                          LS7A_PCI_MEM_BASE + LS7A_PCI_MEM_SIZE - 1,
390                          0, LS7A_PCI_MEM_BASE));
391     aml_append(scope, aml_name_decl("_CRS", crs));
392     aml_append(dsdt, scope);
393 
394     /* System State Package */
395     scope = aml_scope("\\");
396     pkg = aml_package(4);
397     aml_append(pkg, aml_int(ACPI_GED_SLP_TYP_S5));
398     aml_append(pkg, aml_int(0)); /* ignored */
399     aml_append(pkg, aml_int(0)); /* reserved */
400     aml_append(pkg, aml_int(0)); /* reserved */
401     aml_append(scope, aml_name_decl("_S5", pkg));
402     aml_append(dsdt, scope);
403     /* Copy AML table into ACPI tables blob and patch header there */
404     g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
405     acpi_table_end(linker, &table);
406     free_aml_allocator();
407 }
408 
409 static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
410 {
411     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
412     GArray *table_offsets;
413     AcpiFadtData fadt_data;
414     unsigned facs, rsdt, fadt, dsdt;
415     uint8_t *u;
416     size_t aml_len = 0;
417     GArray *tables_blob = tables->table_data;
418 
419     init_common_fadt_data(&fadt_data);
420 
421     table_offsets = g_array_new(false, true, sizeof(uint32_t));
422     ACPI_BUILD_DPRINTF("init ACPI tables\n");
423 
424     bios_linker_loader_alloc(tables->linker,
425                              ACPI_BUILD_TABLE_FILE, tables_blob,
426                              64, false);
427 
428     /*
429      * FACS is pointed to by FADT.
430      * We place it first since it's the only table that has alignment
431      * requirements.
432      */
433     facs = tables_blob->len;
434     build_facs(tables_blob);
435 
436     /* DSDT is pointed to by FADT */
437     dsdt = tables_blob->len;
438     build_dsdt(tables_blob, tables->linker, machine);
439 
440     /*
441      * Count the size of the DSDT, we will need it for
442      * legacy sizing of ACPI tables.
443      */
444     aml_len += tables_blob->len - dsdt;
445 
446     /* ACPI tables pointed to by RSDT */
447     fadt = tables_blob->len;
448     acpi_add_table(table_offsets, tables_blob);
449     fadt_data.facs_tbl_offset = &facs;
450     fadt_data.dsdt_tbl_offset = &dsdt;
451     fadt_data.xdsdt_tbl_offset = &dsdt;
452     build_fadt(tables_blob, tables->linker, &fadt_data,
453                lams->oem_id, lams->oem_table_id);
454     aml_len += tables_blob->len - fadt;
455 
456     acpi_add_table(table_offsets, tables_blob);
457     build_madt(tables_blob, tables->linker, lams);
458 
459     acpi_add_table(table_offsets, tables_blob);
460     build_srat(tables_blob, tables->linker, machine);
461 
462     acpi_add_table(table_offsets, tables_blob);
463     {
464         AcpiMcfgInfo mcfg = {
465            .base = cpu_to_le64(LS_PCIECFG_BASE),
466            .size = cpu_to_le64(LS_PCIECFG_SIZE),
467         };
468         build_mcfg(tables_blob, tables->linker, &mcfg, lams->oem_id,
469                    lams->oem_table_id);
470     }
471 
472     /* Add tables supplied by user (if any) */
473     for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
474         unsigned len = acpi_table_len(u);
475 
476         acpi_add_table(table_offsets, tables_blob);
477         g_array_append_vals(tables_blob, u, len);
478     }
479 
480     /* RSDT is pointed to by RSDP */
481     rsdt = tables_blob->len;
482     build_rsdt(tables_blob, tables->linker, table_offsets,
483                lams->oem_id, lams->oem_table_id);
484 
485     /* RSDP is in FSEG memory, so allocate it separately */
486     {
487         AcpiRsdpData rsdp_data = {
488             .revision = 0,
489             .oem_id = lams->oem_id,
490             .xsdt_tbl_offset = NULL,
491             .rsdt_tbl_offset = &rsdt,
492         };
493         build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
494     }
495 
496     /*
497      * The align size is 128, warn if 64k is not enough therefore
498      * the align size could be resized.
499      */
500     if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
501         warn_report("ACPI table size %u exceeds %d bytes,"
502                     " migration may not work",
503                     tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
504         error_printf("Try removing CPUs, NUMA nodes, memory slots"
505                      " or PCI bridges.");
506     }
507 
508     acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE);
509 
510     /* Cleanup memory that's no longer used. */
511     g_array_free(table_offsets, true);
512 }
513 
514 static void acpi_ram_update(MemoryRegion *mr, GArray *data)
515 {
516     uint32_t size = acpi_data_len(data);
517 
518     /*
519      * Make sure RAM size is correct - in case it got changed
520      * e.g. by migration
521      */
522     memory_region_ram_resize(mr, size, &error_abort);
523 
524     memcpy(memory_region_get_ram_ptr(mr), data->data, size);
525     memory_region_set_dirty(mr, 0, size);
526 }
527 
528 static void acpi_build_update(void *build_opaque)
529 {
530     AcpiBuildState *build_state = build_opaque;
531     AcpiBuildTables tables;
532 
533     /* No state to update or already patched? Nothing to do. */
534     if (!build_state || build_state->patched) {
535         return;
536     }
537     build_state->patched = 1;
538 
539     acpi_build_tables_init(&tables);
540 
541     acpi_build(&tables, MACHINE(qdev_get_machine()));
542 
543     acpi_ram_update(build_state->table_mr, tables.table_data);
544     acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
545     acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
546 
547     acpi_build_tables_cleanup(&tables, true);
548 }
549 
550 static void acpi_build_reset(void *build_opaque)
551 {
552     AcpiBuildState *build_state = build_opaque;
553     build_state->patched = 0;
554 }
555 
556 static const VMStateDescription vmstate_acpi_build = {
557     .name = "acpi_build",
558     .version_id = 1,
559     .minimum_version_id = 1,
560     .fields = (VMStateField[]) {
561         VMSTATE_UINT8(patched, AcpiBuildState),
562         VMSTATE_END_OF_LIST()
563     },
564 };
565 
566 void loongarch_acpi_setup(LoongArchMachineState *lams)
567 {
568     AcpiBuildTables tables;
569     AcpiBuildState *build_state;
570 
571     if (!lams->fw_cfg) {
572         ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
573         return;
574     }
575 
576     if (!loongarch_is_acpi_enabled(lams)) {
577         ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
578         return;
579     }
580 
581     build_state = g_malloc0(sizeof *build_state);
582 
583     acpi_build_tables_init(&tables);
584     acpi_build(&tables, MACHINE(lams));
585 
586     /* Now expose it all to Guest */
587     build_state->table_mr = acpi_add_rom_blob(acpi_build_update,
588                                               build_state, tables.table_data,
589                                               ACPI_BUILD_TABLE_FILE);
590     assert(build_state->table_mr != NULL);
591 
592     build_state->linker_mr =
593         acpi_add_rom_blob(acpi_build_update, build_state,
594                           tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE);
595 
596     build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update,
597                                              build_state, tables.rsdp,
598                                              ACPI_BUILD_RSDP_FILE);
599 
600     qemu_register_reset(acpi_build_reset, build_state);
601     acpi_build_reset(build_state);
602     vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
603 
604     /*
605      * Cleanup tables but don't free the memory: we track it
606      * in build_state.
607      */
608     acpi_build_tables_cleanup(&tables, false);
609 }
610