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