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