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