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