xref: /qemu/hw/loongarch/acpi-build.c (revision 8f9abdf5)
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