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