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