qemu/hw/loongarch/acpi-build.c
<<
>>
Prefs
   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 */
  45static 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
  76static 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 */
  86static void
  87build_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 */
 102static void
 103build_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, VIRT_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, VIRT_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 */
 155static void
 156build_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
 192typedef
 193struct 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
 203static 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
 225static 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
 258static 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
 305static void build_uart_device_aml(Aml *table)
 306{
 307    Aml *dev;
 308    Aml *crs;
 309    Aml *pkg0, *pkg1, *pkg2;
 310    uint32_t uart_irq = VIRT_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 */
 339static void
 340build_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                      VIRT_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, VIRT_PCI_MEM_BASE,
 389                         VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1,
 390                         0, VIRT_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
 409static 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, dsdt;
 415    uint8_t *u;
 416    GArray *tables_blob = tables->table_data;
 417
 418    init_common_fadt_data(&fadt_data);
 419
 420    table_offsets = g_array_new(false, true, sizeof(uint32_t));
 421    ACPI_BUILD_DPRINTF("init ACPI tables\n");
 422
 423    bios_linker_loader_alloc(tables->linker,
 424                             ACPI_BUILD_TABLE_FILE, tables_blob,
 425                             64, false);
 426
 427    /*
 428     * FACS is pointed to by FADT.
 429     * We place it first since it's the only table that has alignment
 430     * requirements.
 431     */
 432    facs = tables_blob->len;
 433    build_facs(tables_blob);
 434
 435    /* DSDT is pointed to by FADT */
 436    dsdt = tables_blob->len;
 437    build_dsdt(tables_blob, tables->linker, machine);
 438
 439    /* ACPI tables pointed to by RSDT */
 440    acpi_add_table(table_offsets, tables_blob);
 441    fadt_data.facs_tbl_offset = &facs;
 442    fadt_data.dsdt_tbl_offset = &dsdt;
 443    fadt_data.xdsdt_tbl_offset = &dsdt;
 444    build_fadt(tables_blob, tables->linker, &fadt_data,
 445               lams->oem_id, lams->oem_table_id);
 446
 447    acpi_add_table(table_offsets, tables_blob);
 448    build_madt(tables_blob, tables->linker, lams);
 449
 450    acpi_add_table(table_offsets, tables_blob);
 451    build_srat(tables_blob, tables->linker, machine);
 452
 453    acpi_add_table(table_offsets, tables_blob);
 454    {
 455        AcpiMcfgInfo mcfg = {
 456           .base = cpu_to_le64(VIRT_PCI_CFG_BASE),
 457           .size = cpu_to_le64(VIRT_PCI_CFG_SIZE),
 458        };
 459        build_mcfg(tables_blob, tables->linker, &mcfg, lams->oem_id,
 460                   lams->oem_table_id);
 461    }
 462
 463    /* Add tables supplied by user (if any) */
 464    for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
 465        unsigned len = acpi_table_len(u);
 466
 467        acpi_add_table(table_offsets, tables_blob);
 468        g_array_append_vals(tables_blob, u, len);
 469    }
 470
 471    /* RSDT is pointed to by RSDP */
 472    rsdt = tables_blob->len;
 473    build_rsdt(tables_blob, tables->linker, table_offsets,
 474               lams->oem_id, lams->oem_table_id);
 475
 476    /* RSDP is in FSEG memory, so allocate it separately */
 477    {
 478        AcpiRsdpData rsdp_data = {
 479            .revision = 0,
 480            .oem_id = lams->oem_id,
 481            .xsdt_tbl_offset = NULL,
 482            .rsdt_tbl_offset = &rsdt,
 483        };
 484        build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
 485    }
 486
 487    /*
 488     * The align size is 128, warn if 64k is not enough therefore
 489     * the align size could be resized.
 490     */
 491    if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
 492        warn_report("ACPI table size %u exceeds %d bytes,"
 493                    " migration may not work",
 494                    tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
 495        error_printf("Try removing CPUs, NUMA nodes, memory slots"
 496                     " or PCI bridges.");
 497    }
 498
 499    acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE);
 500
 501    /* Cleanup memory that's no longer used. */
 502    g_array_free(table_offsets, true);
 503}
 504
 505static void acpi_ram_update(MemoryRegion *mr, GArray *data)
 506{
 507    uint32_t size = acpi_data_len(data);
 508
 509    /*
 510     * Make sure RAM size is correct - in case it got changed
 511     * e.g. by migration
 512     */
 513    memory_region_ram_resize(mr, size, &error_abort);
 514
 515    memcpy(memory_region_get_ram_ptr(mr), data->data, size);
 516    memory_region_set_dirty(mr, 0, size);
 517}
 518
 519static void acpi_build_update(void *build_opaque)
 520{
 521    AcpiBuildState *build_state = build_opaque;
 522    AcpiBuildTables tables;
 523
 524    /* No state to update or already patched? Nothing to do. */
 525    if (!build_state || build_state->patched) {
 526        return;
 527    }
 528    build_state->patched = 1;
 529
 530    acpi_build_tables_init(&tables);
 531
 532    acpi_build(&tables, MACHINE(qdev_get_machine()));
 533
 534    acpi_ram_update(build_state->table_mr, tables.table_data);
 535    acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
 536    acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
 537
 538    acpi_build_tables_cleanup(&tables, true);
 539}
 540
 541static void acpi_build_reset(void *build_opaque)
 542{
 543    AcpiBuildState *build_state = build_opaque;
 544    build_state->patched = 0;
 545}
 546
 547static const VMStateDescription vmstate_acpi_build = {
 548    .name = "acpi_build",
 549    .version_id = 1,
 550    .minimum_version_id = 1,
 551    .fields = (VMStateField[]) {
 552        VMSTATE_UINT8(patched, AcpiBuildState),
 553        VMSTATE_END_OF_LIST()
 554    },
 555};
 556
 557void loongarch_acpi_setup(LoongArchMachineState *lams)
 558{
 559    AcpiBuildTables tables;
 560    AcpiBuildState *build_state;
 561
 562    if (!lams->fw_cfg) {
 563        ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
 564        return;
 565    }
 566
 567    if (!loongarch_is_acpi_enabled(lams)) {
 568        ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
 569        return;
 570    }
 571
 572    build_state = g_malloc0(sizeof *build_state);
 573
 574    acpi_build_tables_init(&tables);
 575    acpi_build(&tables, MACHINE(lams));
 576
 577    /* Now expose it all to Guest */
 578    build_state->table_mr = acpi_add_rom_blob(acpi_build_update,
 579                                              build_state, tables.table_data,
 580                                              ACPI_BUILD_TABLE_FILE);
 581    assert(build_state->table_mr != NULL);
 582
 583    build_state->linker_mr =
 584        acpi_add_rom_blob(acpi_build_update, build_state,
 585                          tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE);
 586
 587    build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update,
 588                                             build_state, tables.rsdp,
 589                                             ACPI_BUILD_RSDP_FILE);
 590
 591    qemu_register_reset(acpi_build_reset, build_state);
 592    acpi_build_reset(build_state);
 593    vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
 594
 595    /*
 596     * Cleanup tables but don't free the memory: we track it
 597     * in build_state.
 598     */
 599    acpi_build_tables_cleanup(&tables, false);
 600}
 601