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