xref: /qemu/hw/loongarch/acpi-build.c (revision 370ed600)
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 "sysemu/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 "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     acpi_dsdt_add_power_button(dsdt);
265 }
266 
267 static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams)
268 {
269     struct GPEXConfig cfg = {
270         .mmio64.base = VIRT_PCI_MEM_BASE,
271         .mmio64.size = VIRT_PCI_MEM_SIZE,
272         .pio.base    = VIRT_PCI_IO_BASE,
273         .pio.size    = VIRT_PCI_IO_SIZE,
274         .ecam.base   = VIRT_PCI_CFG_BASE,
275         .ecam.size   = VIRT_PCI_CFG_SIZE,
276         .irq         = VIRT_GSI_BASE + VIRT_DEVICE_IRQS,
277         .bus         = lams->pci_bus,
278     };
279 
280     acpi_dsdt_add_gpex(scope, &cfg);
281 }
282 
283 static void build_flash_aml(Aml *scope, LoongArchMachineState *lams)
284 {
285     Aml *dev, *crs;
286 
287     hwaddr flash_base = VIRT_FLASH_BASE;
288     hwaddr flash_size = VIRT_FLASH_SIZE;
289 
290     dev = aml_device("FLS0");
291     aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015")));
292     aml_append(dev, aml_name_decl("_UID", aml_int(0)));
293 
294     crs = aml_resource_template();
295     aml_append(crs, aml_memory32_fixed(flash_base, flash_size, AML_READ_WRITE));
296     aml_append(dev, aml_name_decl("_CRS", crs));
297     aml_append(scope, dev);
298 }
299 
300 #ifdef CONFIG_TPM
301 static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms)
302 {
303     PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
304     hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS;
305     SysBusDevice *sbdev = SYS_BUS_DEVICE(tpm_find());
306     MemoryRegion *sbdev_mr;
307     hwaddr tpm_base;
308 
309     if (!sbdev) {
310         return;
311     }
312 
313     tpm_base = platform_bus_get_mmio_addr(pbus, sbdev, 0);
314     assert(tpm_base != -1);
315 
316     tpm_base += pbus_base;
317 
318     sbdev_mr = sysbus_mmio_get_region(sbdev, 0);
319 
320     Aml *dev = aml_device("TPM0");
321     aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
322     aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device")));
323     aml_append(dev, aml_name_decl("_UID", aml_int(0)));
324 
325     Aml *crs = aml_resource_template();
326     aml_append(crs,
327                aml_memory32_fixed(tpm_base,
328                                   (uint32_t)memory_region_size(sbdev_mr),
329                                   AML_READ_WRITE));
330     aml_append(dev, aml_name_decl("_CRS", crs));
331     aml_append(scope, dev);
332 }
333 #endif
334 
335 /* build DSDT */
336 static void
337 build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
338 {
339     Aml *dsdt, *scope, *pkg;
340     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
341     AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
342                         .oem_table_id = lams->oem_table_id };
343 
344     acpi_table_begin(&table, table_data);
345     dsdt = init_aml_allocator();
346     build_uart_device_aml(dsdt);
347     build_pci_device_aml(dsdt, lams);
348     build_la_ged_aml(dsdt, machine);
349     build_flash_aml(dsdt, lams);
350 #ifdef CONFIG_TPM
351     acpi_dsdt_add_tpm(dsdt, lams);
352 #endif
353     /* System State Package */
354     scope = aml_scope("\\");
355     pkg = aml_package(4);
356     aml_append(pkg, aml_int(ACPI_GED_SLP_TYP_S5));
357     aml_append(pkg, aml_int(0)); /* ignored */
358     aml_append(pkg, aml_int(0)); /* reserved */
359     aml_append(pkg, aml_int(0)); /* reserved */
360     aml_append(scope, aml_name_decl("_S5", pkg));
361     aml_append(dsdt, scope);
362     /* Copy AML table into ACPI tables blob and patch header there */
363     g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
364     acpi_table_end(linker, &table);
365     free_aml_allocator();
366 }
367 
368 static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
369 {
370     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
371     GArray *table_offsets;
372     AcpiFadtData fadt_data;
373     unsigned facs, rsdt, dsdt;
374     uint8_t *u;
375     GArray *tables_blob = tables->table_data;
376 
377     init_common_fadt_data(&fadt_data);
378 
379     table_offsets = g_array_new(false, true, sizeof(uint32_t));
380     ACPI_BUILD_DPRINTF("init ACPI tables\n");
381 
382     bios_linker_loader_alloc(tables->linker,
383                              ACPI_BUILD_TABLE_FILE, tables_blob,
384                              64, false);
385 
386     /*
387      * FACS is pointed to by FADT.
388      * We place it first since it's the only table that has alignment
389      * requirements.
390      */
391     facs = tables_blob->len;
392     build_facs(tables_blob);
393 
394     /* DSDT is pointed to by FADT */
395     dsdt = tables_blob->len;
396     build_dsdt(tables_blob, tables->linker, machine);
397 
398     /* ACPI tables pointed to by RSDT */
399     acpi_add_table(table_offsets, tables_blob);
400     fadt_data.facs_tbl_offset = &facs;
401     fadt_data.dsdt_tbl_offset = &dsdt;
402     fadt_data.xdsdt_tbl_offset = &dsdt;
403     build_fadt(tables_blob, tables->linker, &fadt_data,
404                lams->oem_id, lams->oem_table_id);
405 
406     acpi_add_table(table_offsets, tables_blob);
407     build_madt(tables_blob, tables->linker, lams);
408 
409     acpi_add_table(table_offsets, tables_blob);
410     build_srat(tables_blob, tables->linker, machine);
411 
412     acpi_add_table(table_offsets, tables_blob);
413     {
414         AcpiMcfgInfo mcfg = {
415            .base = cpu_to_le64(VIRT_PCI_CFG_BASE),
416            .size = cpu_to_le64(VIRT_PCI_CFG_SIZE),
417         };
418         build_mcfg(tables_blob, tables->linker, &mcfg, lams->oem_id,
419                    lams->oem_table_id);
420     }
421 
422 #ifdef CONFIG_TPM
423     /* TPM info */
424     if (tpm_get_version(tpm_find()) == TPM_VERSION_2_0) {
425         acpi_add_table(table_offsets, tables_blob);
426         build_tpm2(tables_blob, tables->linker,
427                    tables->tcpalog, lams->oem_id,
428                    lams->oem_table_id);
429     }
430 #endif
431     /* Add tables supplied by user (if any) */
432     for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
433         unsigned len = acpi_table_len(u);
434 
435         acpi_add_table(table_offsets, tables_blob);
436         g_array_append_vals(tables_blob, u, len);
437     }
438 
439     /* RSDT is pointed to by RSDP */
440     rsdt = tables_blob->len;
441     build_rsdt(tables_blob, tables->linker, table_offsets,
442                lams->oem_id, lams->oem_table_id);
443 
444     /* RSDP is in FSEG memory, so allocate it separately */
445     {
446         AcpiRsdpData rsdp_data = {
447             .revision = 0,
448             .oem_id = lams->oem_id,
449             .xsdt_tbl_offset = NULL,
450             .rsdt_tbl_offset = &rsdt,
451         };
452         build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
453     }
454 
455     /*
456      * The align size is 128, warn if 64k is not enough therefore
457      * the align size could be resized.
458      */
459     if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
460         warn_report("ACPI table size %u exceeds %d bytes,"
461                     " migration may not work",
462                     tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
463         error_printf("Try removing CPUs, NUMA nodes, memory slots"
464                      " or PCI bridges.");
465     }
466 
467     acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE);
468 
469     /* Cleanup memory that's no longer used. */
470     g_array_free(table_offsets, true);
471 }
472 
473 static void acpi_ram_update(MemoryRegion *mr, GArray *data)
474 {
475     uint32_t size = acpi_data_len(data);
476 
477     /*
478      * Make sure RAM size is correct - in case it got changed
479      * e.g. by migration
480      */
481     memory_region_ram_resize(mr, size, &error_abort);
482 
483     memcpy(memory_region_get_ram_ptr(mr), data->data, size);
484     memory_region_set_dirty(mr, 0, size);
485 }
486 
487 static void acpi_build_update(void *build_opaque)
488 {
489     AcpiBuildState *build_state = build_opaque;
490     AcpiBuildTables tables;
491 
492     /* No state to update or already patched? Nothing to do. */
493     if (!build_state || build_state->patched) {
494         return;
495     }
496     build_state->patched = 1;
497 
498     acpi_build_tables_init(&tables);
499 
500     acpi_build(&tables, MACHINE(qdev_get_machine()));
501 
502     acpi_ram_update(build_state->table_mr, tables.table_data);
503     acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
504     acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
505 
506     acpi_build_tables_cleanup(&tables, true);
507 }
508 
509 static void acpi_build_reset(void *build_opaque)
510 {
511     AcpiBuildState *build_state = build_opaque;
512     build_state->patched = 0;
513 }
514 
515 static const VMStateDescription vmstate_acpi_build = {
516     .name = "acpi_build",
517     .version_id = 1,
518     .minimum_version_id = 1,
519     .fields = (VMStateField[]) {
520         VMSTATE_UINT8(patched, AcpiBuildState),
521         VMSTATE_END_OF_LIST()
522     },
523 };
524 
525 void loongarch_acpi_setup(LoongArchMachineState *lams)
526 {
527     AcpiBuildTables tables;
528     AcpiBuildState *build_state;
529 
530     if (!lams->fw_cfg) {
531         ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
532         return;
533     }
534 
535     if (!loongarch_is_acpi_enabled(lams)) {
536         ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
537         return;
538     }
539 
540     build_state = g_malloc0(sizeof *build_state);
541 
542     acpi_build_tables_init(&tables);
543     acpi_build(&tables, MACHINE(lams));
544 
545     /* Now expose it all to Guest */
546     build_state->table_mr = acpi_add_rom_blob(acpi_build_update,
547                                               build_state, tables.table_data,
548                                               ACPI_BUILD_TABLE_FILE);
549     assert(build_state->table_mr != NULL);
550 
551     build_state->linker_mr =
552         acpi_add_rom_blob(acpi_build_update, build_state,
553                           tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE);
554 
555     build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update,
556                                              build_state, tables.rsdp,
557                                              ACPI_BUILD_RSDP_FILE);
558 
559     qemu_register_reset(acpi_build_reset, build_state);
560     acpi_build_reset(build_state);
561     vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
562 
563     /*
564      * Cleanup tables but don't free the memory: we track it
565      * in build_state.
566      */
567     acpi_build_tables_cleanup(&tables, false);
568 }
569