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