1 /* 2 * Support for generating ACPI tables and passing them to Guests 3 * 4 * RISC-V virt ACPI generation 5 * 6 * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net> 7 * Copyright (C) 2006 Fabrice Bellard 8 * Copyright (C) 2013 Red Hat Inc 9 * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD. 10 * Copyright (C) 2021-2023 Ventana Micro Systems Inc 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 22 * You should have received a copy of the GNU General Public License along 23 * with this program; if not, see <http://www.gnu.org/licenses/>. 24 */ 25 26 #include "qemu/osdep.h" 27 #include "hw/acpi/acpi-defs.h" 28 #include "hw/acpi/acpi.h" 29 #include "hw/acpi/aml-build.h" 30 #include "hw/acpi/utils.h" 31 #include "qapi/error.h" 32 #include "qemu/error-report.h" 33 #include "sysemu/reset.h" 34 #include "migration/vmstate.h" 35 #include "hw/riscv/virt.h" 36 #include "hw/riscv/numa.h" 37 #include "hw/intc/riscv_aclint.h" 38 39 #define ACPI_BUILD_TABLE_SIZE 0x20000 40 41 typedef struct AcpiBuildState { 42 /* Copy of table in RAM (for patching) */ 43 MemoryRegion *table_mr; 44 MemoryRegion *rsdp_mr; 45 MemoryRegion *linker_mr; 46 /* Is table patched? */ 47 bool patched; 48 } AcpiBuildState; 49 50 static void acpi_align_size(GArray *blob, unsigned align) 51 { 52 /* 53 * Align size to multiple of given size. This reduces the chance 54 * we need to change size in the future (breaking cross version migration). 55 */ 56 g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); 57 } 58 59 static void riscv_acpi_madt_add_rintc(uint32_t uid, 60 const CPUArchIdList *arch_ids, 61 GArray *entry) 62 { 63 uint64_t hart_id = arch_ids->cpus[uid].arch_id; 64 65 build_append_int_noprefix(entry, 0x18, 1); /* Type */ 66 build_append_int_noprefix(entry, 20, 1); /* Length */ 67 build_append_int_noprefix(entry, 1, 1); /* Version */ 68 build_append_int_noprefix(entry, 0, 1); /* Reserved */ 69 build_append_int_noprefix(entry, 0x1, 4); /* Flags */ 70 build_append_int_noprefix(entry, hart_id, 8); /* Hart ID */ 71 build_append_int_noprefix(entry, uid, 4); /* ACPI Processor UID */ 72 } 73 74 static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s) 75 { 76 MachineClass *mc = MACHINE_GET_CLASS(s); 77 MachineState *ms = MACHINE(s); 78 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms); 79 80 for (int i = 0; i < arch_ids->len; i++) { 81 Aml *dev; 82 GArray *madt_buf = g_array_new(0, 1, 1); 83 84 dev = aml_device("C%.03X", i); 85 aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007"))); 86 aml_append(dev, aml_name_decl("_UID", 87 aml_int(arch_ids->cpus[i].arch_id))); 88 89 /* build _MAT object */ 90 riscv_acpi_madt_add_rintc(i, arch_ids, madt_buf); 91 aml_append(dev, aml_name_decl("_MAT", 92 aml_buffer(madt_buf->len, 93 (uint8_t *)madt_buf->data))); 94 g_array_free(madt_buf, true); 95 96 aml_append(scope, dev); 97 } 98 } 99 100 static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap) 101 { 102 Aml *dev = aml_device("FWCF"); 103 aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002"))); 104 105 /* device present, functioning, decoding, not shown in UI */ 106 aml_append(dev, aml_name_decl("_STA", aml_int(0xB))); 107 aml_append(dev, aml_name_decl("_CCA", aml_int(1))); 108 109 Aml *crs = aml_resource_template(); 110 aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base, 111 fw_cfg_memmap->size, AML_READ_WRITE)); 112 aml_append(dev, aml_name_decl("_CRS", crs)); 113 aml_append(scope, dev); 114 } 115 116 /* RHCT Node[N] starts at offset 56 */ 117 #define RHCT_NODE_ARRAY_OFFSET 56 118 119 /* 120 * ACPI spec, Revision 6.5+ 121 * 5.2.36 RISC-V Hart Capabilities Table (RHCT) 122 * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/16 123 * https://drive.google.com/file/d/1nP3nFiH4jkPMp6COOxP6123DCZKR-tia/view 124 */ 125 static void build_rhct(GArray *table_data, 126 BIOSLinker *linker, 127 RISCVVirtState *s) 128 { 129 MachineClass *mc = MACHINE_GET_CLASS(s); 130 MachineState *ms = MACHINE(s); 131 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms); 132 size_t len, aligned_len; 133 uint32_t isa_offset, num_rhct_nodes; 134 RISCVCPU *cpu; 135 char *isa; 136 137 AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id, 138 .oem_table_id = s->oem_table_id }; 139 140 acpi_table_begin(&table, table_data); 141 142 build_append_int_noprefix(table_data, 0x0, 4); /* Reserved */ 143 144 /* Time Base Frequency */ 145 build_append_int_noprefix(table_data, 146 RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, 8); 147 148 /* ISA + N hart info */ 149 num_rhct_nodes = 1 + ms->smp.cpus; 150 151 /* Number of RHCT nodes*/ 152 build_append_int_noprefix(table_data, num_rhct_nodes, 4); 153 154 /* Offset to the RHCT node array */ 155 build_append_int_noprefix(table_data, RHCT_NODE_ARRAY_OFFSET, 4); 156 157 /* ISA String Node */ 158 isa_offset = table_data->len - table.table_offset; 159 build_append_int_noprefix(table_data, 0, 2); /* Type 0 */ 160 161 cpu = &s->soc[0].harts[0]; 162 isa = riscv_isa_string(cpu); 163 len = 8 + strlen(isa) + 1; 164 aligned_len = (len % 2) ? (len + 1) : len; 165 166 build_append_int_noprefix(table_data, aligned_len, 2); /* Length */ 167 build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ 168 169 /* ISA string length including NUL */ 170 build_append_int_noprefix(table_data, strlen(isa) + 1, 2); 171 g_array_append_vals(table_data, isa, strlen(isa) + 1); /* ISA string */ 172 173 if (aligned_len != len) { 174 build_append_int_noprefix(table_data, 0x0, 1); /* Optional Padding */ 175 } 176 177 /* Hart Info Node */ 178 for (int i = 0; i < arch_ids->len; i++) { 179 build_append_int_noprefix(table_data, 0xFFFF, 2); /* Type */ 180 build_append_int_noprefix(table_data, 16, 2); /* Length */ 181 build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ 182 build_append_int_noprefix(table_data, 1, 2); /* Number of offsets */ 183 build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */ 184 build_append_int_noprefix(table_data, isa_offset, 4); /* Offsets[0] */ 185 } 186 187 acpi_table_end(linker, &table); 188 } 189 190 /* FADT */ 191 static void build_fadt_rev6(GArray *table_data, 192 BIOSLinker *linker, 193 RISCVVirtState *s, 194 unsigned dsdt_tbl_offset) 195 { 196 AcpiFadtData fadt = { 197 .rev = 6, 198 .minor_ver = 5, 199 .flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI, 200 .xdsdt_tbl_offset = &dsdt_tbl_offset, 201 }; 202 203 build_fadt(table_data, linker, &fadt, s->oem_id, s->oem_table_id); 204 } 205 206 /* DSDT */ 207 static void build_dsdt(GArray *table_data, 208 BIOSLinker *linker, 209 RISCVVirtState *s) 210 { 211 Aml *scope, *dsdt; 212 const MemMapEntry *memmap = s->memmap; 213 AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = s->oem_id, 214 .oem_table_id = s->oem_table_id }; 215 216 217 acpi_table_begin(&table, table_data); 218 dsdt = init_aml_allocator(); 219 220 /* 221 * When booting the VM with UEFI, UEFI takes ownership of the RTC hardware. 222 * While UEFI can use libfdt to disable the RTC device node in the DTB that 223 * it passes to the OS, it cannot modify AML. Therefore, we won't generate 224 * the RTC ACPI device at all when using UEFI. 225 */ 226 scope = aml_scope("\\_SB"); 227 acpi_dsdt_add_cpus(scope, s); 228 229 acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]); 230 231 aml_append(dsdt, scope); 232 233 /* copy AML table into ACPI tables blob and patch header there */ 234 g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); 235 236 acpi_table_end(linker, &table); 237 free_aml_allocator(); 238 } 239 240 /* 241 * ACPI spec, Revision 6.5+ 242 * 5.2.12 Multiple APIC Description Table (MADT) 243 * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/15 244 * https://drive.google.com/file/d/1R6k4MshhN3WTT-hwqAquu5nX6xSEqK2l/view 245 */ 246 static void build_madt(GArray *table_data, 247 BIOSLinker *linker, 248 RISCVVirtState *s) 249 { 250 MachineClass *mc = MACHINE_GET_CLASS(s); 251 MachineState *ms = MACHINE(s); 252 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms); 253 254 AcpiTable table = { .sig = "APIC", .rev = 6, .oem_id = s->oem_id, 255 .oem_table_id = s->oem_table_id }; 256 257 acpi_table_begin(&table, table_data); 258 /* Local Interrupt Controller Address */ 259 build_append_int_noprefix(table_data, 0, 4); 260 build_append_int_noprefix(table_data, 0, 4); /* MADT Flags */ 261 262 /* RISC-V Local INTC structures per HART */ 263 for (int i = 0; i < arch_ids->len; i++) { 264 riscv_acpi_madt_add_rintc(i, arch_ids, table_data); 265 } 266 267 acpi_table_end(linker, &table); 268 } 269 270 static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables) 271 { 272 GArray *table_offsets; 273 unsigned dsdt, xsdt; 274 GArray *tables_blob = tables->table_data; 275 276 table_offsets = g_array_new(false, true, 277 sizeof(uint32_t)); 278 279 bios_linker_loader_alloc(tables->linker, 280 ACPI_BUILD_TABLE_FILE, tables_blob, 281 64, false); 282 283 /* DSDT is pointed to by FADT */ 284 dsdt = tables_blob->len; 285 build_dsdt(tables_blob, tables->linker, s); 286 287 /* FADT and others pointed to by XSDT */ 288 acpi_add_table(table_offsets, tables_blob); 289 build_fadt_rev6(tables_blob, tables->linker, s, dsdt); 290 291 acpi_add_table(table_offsets, tables_blob); 292 build_madt(tables_blob, tables->linker, s); 293 294 acpi_add_table(table_offsets, tables_blob); 295 build_rhct(tables_blob, tables->linker, s); 296 297 /* XSDT is pointed to by RSDP */ 298 xsdt = tables_blob->len; 299 build_xsdt(tables_blob, tables->linker, table_offsets, s->oem_id, 300 s->oem_table_id); 301 302 /* RSDP is in FSEG memory, so allocate it separately */ 303 { 304 AcpiRsdpData rsdp_data = { 305 .revision = 2, 306 .oem_id = s->oem_id, 307 .xsdt_tbl_offset = &xsdt, 308 .rsdt_tbl_offset = NULL, 309 }; 310 build_rsdp(tables->rsdp, tables->linker, &rsdp_data); 311 } 312 313 /* 314 * The align size is 128, warn if 64k is not enough therefore 315 * the align size could be resized. 316 */ 317 if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) { 318 warn_report("ACPI table size %u exceeds %d bytes," 319 " migration may not work", 320 tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2); 321 error_printf("Try removing some objects."); 322 } 323 324 acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE); 325 326 /* Clean up memory that's no longer used */ 327 g_array_free(table_offsets, true); 328 } 329 330 static void acpi_ram_update(MemoryRegion *mr, GArray *data) 331 { 332 uint32_t size = acpi_data_len(data); 333 334 /* 335 * Make sure RAM size is correct - in case it got changed 336 * e.g. by migration 337 */ 338 memory_region_ram_resize(mr, size, &error_abort); 339 340 memcpy(memory_region_get_ram_ptr(mr), data->data, size); 341 memory_region_set_dirty(mr, 0, size); 342 } 343 344 static void virt_acpi_build_update(void *build_opaque) 345 { 346 AcpiBuildState *build_state = build_opaque; 347 AcpiBuildTables tables; 348 349 /* No state to update or already patched? Nothing to do. */ 350 if (!build_state || build_state->patched) { 351 return; 352 } 353 354 build_state->patched = true; 355 356 acpi_build_tables_init(&tables); 357 358 virt_acpi_build(RISCV_VIRT_MACHINE(qdev_get_machine()), &tables); 359 360 acpi_ram_update(build_state->table_mr, tables.table_data); 361 acpi_ram_update(build_state->rsdp_mr, tables.rsdp); 362 acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob); 363 364 acpi_build_tables_cleanup(&tables, true); 365 } 366 367 static void virt_acpi_build_reset(void *build_opaque) 368 { 369 AcpiBuildState *build_state = build_opaque; 370 build_state->patched = false; 371 } 372 373 static const VMStateDescription vmstate_virt_acpi_build = { 374 .name = "virt_acpi_build", 375 .version_id = 1, 376 .minimum_version_id = 1, 377 .fields = (VMStateField[]) { 378 VMSTATE_BOOL(patched, AcpiBuildState), 379 VMSTATE_END_OF_LIST() 380 }, 381 }; 382 383 void virt_acpi_setup(RISCVVirtState *s) 384 { 385 AcpiBuildTables tables; 386 AcpiBuildState *build_state; 387 388 build_state = g_malloc0(sizeof *build_state); 389 390 acpi_build_tables_init(&tables); 391 virt_acpi_build(s, &tables); 392 393 /* Now expose it all to Guest */ 394 build_state->table_mr = acpi_add_rom_blob(virt_acpi_build_update, 395 build_state, tables.table_data, 396 ACPI_BUILD_TABLE_FILE); 397 assert(build_state->table_mr != NULL); 398 399 build_state->linker_mr = acpi_add_rom_blob(virt_acpi_build_update, 400 build_state, 401 tables.linker->cmd_blob, 402 ACPI_BUILD_LOADER_FILE); 403 404 build_state->rsdp_mr = acpi_add_rom_blob(virt_acpi_build_update, 405 build_state, tables.rsdp, 406 ACPI_BUILD_RSDP_FILE); 407 408 qemu_register_reset(virt_acpi_build_reset, build_state); 409 virt_acpi_build_reset(build_state); 410 vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state); 411 412 /* 413 * Clean up tables but don't free the memory: we track it 414 * in build_state. 415 */ 416 acpi_build_tables_cleanup(&tables, false); 417 } 418