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