1 /*
2 * Support for generating ACPI tables and passing them to Guests
3 *
4 * RISC-V virt ACPI generation
5 *
6 * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
7 * Copyright (C) 2006 Fabrice Bellard
8 * Copyright (C) 2013 Red Hat Inc
9 * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD.
10 * Copyright (C) 2021-2023 Ventana Micro Systems Inc
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "qemu/osdep.h"
27 #include "hw/acpi/acpi-defs.h"
28 #include "hw/acpi/acpi.h"
29 #include "hw/acpi/aml-build.h"
30 #include "hw/acpi/pci.h"
31 #include "hw/acpi/utils.h"
32 #include "hw/intc/riscv_aclint.h"
33 #include "hw/nvram/fw_cfg_acpi.h"
34 #include "hw/pci-host/gpex.h"
35 #include "hw/riscv/virt.h"
36 #include "hw/riscv/numa.h"
37 #include "hw/virtio/virtio-acpi.h"
38 #include "migration/vmstate.h"
39 #include "qapi/error.h"
40 #include "qemu/error-report.h"
41 #include "system/reset.h"
42
43 #define ACPI_BUILD_TABLE_SIZE 0x20000
44 #define ACPI_BUILD_INTC_ID(socket, index) ((socket << 24) | (index))
45
46 typedef struct AcpiBuildState {
47 /* Copy of table in RAM (for patching) */
48 MemoryRegion *table_mr;
49 MemoryRegion *rsdp_mr;
50 MemoryRegion *linker_mr;
51 /* Is table patched? */
52 bool patched;
53 } AcpiBuildState;
54
acpi_align_size(GArray * blob,unsigned align)55 static void acpi_align_size(GArray *blob, unsigned align)
56 {
57 /*
58 * Align size to multiple of given size. This reduces the chance
59 * we need to change size in the future (breaking cross version migration).
60 */
61 g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
62 }
63
riscv_acpi_madt_add_rintc(uint32_t uid,const CPUArchIdList * arch_ids,GArray * entry,RISCVVirtState * s)64 static void riscv_acpi_madt_add_rintc(uint32_t uid,
65 const CPUArchIdList *arch_ids,
66 GArray *entry,
67 RISCVVirtState *s)
68 {
69 uint8_t guest_index_bits = imsic_num_bits(s->aia_guests + 1);
70 uint64_t hart_id = arch_ids->cpus[uid].arch_id;
71 uint32_t imsic_size, local_cpu_id, socket_id;
72 uint64_t imsic_socket_addr, imsic_addr;
73 MachineState *ms = MACHINE(s);
74
75 socket_id = arch_ids->cpus[uid].props.node_id;
76 local_cpu_id = (arch_ids->cpus[uid].arch_id -
77 riscv_socket_first_hartid(ms, socket_id)) %
78 riscv_socket_hart_count(ms, socket_id);
79 imsic_socket_addr = s->memmap[VIRT_IMSIC_S].base +
80 (socket_id * VIRT_IMSIC_GROUP_MAX_SIZE);
81 imsic_size = IMSIC_HART_SIZE(guest_index_bits);
82 imsic_addr = imsic_socket_addr + local_cpu_id * imsic_size;
83 build_append_int_noprefix(entry, 0x18, 1); /* Type */
84 build_append_int_noprefix(entry, 36, 1); /* Length */
85 build_append_int_noprefix(entry, 1, 1); /* Version */
86 build_append_int_noprefix(entry, 0, 1); /* Reserved */
87 build_append_int_noprefix(entry, 0x1, 4); /* Flags */
88 build_append_int_noprefix(entry, hart_id, 8); /* Hart ID */
89 build_append_int_noprefix(entry, uid, 4); /* ACPI Processor UID */
90 /* External Interrupt Controller ID */
91 if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
92 build_append_int_noprefix(entry,
93 ACPI_BUILD_INTC_ID(
94 arch_ids->cpus[uid].props.node_id,
95 local_cpu_id),
96 4);
97 } else if (s->aia_type == VIRT_AIA_TYPE_NONE) {
98 build_append_int_noprefix(entry,
99 ACPI_BUILD_INTC_ID(
100 arch_ids->cpus[uid].props.node_id,
101 2 * local_cpu_id + 1),
102 4);
103 } else {
104 build_append_int_noprefix(entry, 0, 4);
105 }
106
107 if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
108 /* IMSIC Base address */
109 build_append_int_noprefix(entry, imsic_addr, 8);
110 /* IMSIC Size */
111 build_append_int_noprefix(entry, imsic_size, 4);
112 } else {
113 build_append_int_noprefix(entry, 0, 8);
114 build_append_int_noprefix(entry, 0, 4);
115 }
116 }
117
acpi_dsdt_add_cpus(Aml * scope,RISCVVirtState * s)118 static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s)
119 {
120 MachineClass *mc = MACHINE_GET_CLASS(s);
121 MachineState *ms = MACHINE(s);
122 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
123
124 for (int i = 0; i < arch_ids->len; i++) {
125 Aml *dev;
126 GArray *madt_buf = g_array_new(0, 1, 1);
127
128 dev = aml_device("C%.03X", i);
129 aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
130 aml_append(dev, aml_name_decl("_UID",
131 aml_int(arch_ids->cpus[i].arch_id)));
132
133 /* build _MAT object */
134 riscv_acpi_madt_add_rintc(i, arch_ids, madt_buf, s);
135 aml_append(dev, aml_name_decl("_MAT",
136 aml_buffer(madt_buf->len,
137 (uint8_t *)madt_buf->data)));
138 g_array_free(madt_buf, true);
139
140 aml_append(scope, dev);
141 }
142 }
143
acpi_dsdt_add_plic_aplic(Aml * scope,uint8_t socket_count,uint64_t mmio_base,uint64_t mmio_size,const char * hid)144 static void acpi_dsdt_add_plic_aplic(Aml *scope, uint8_t socket_count,
145 uint64_t mmio_base, uint64_t mmio_size,
146 const char *hid)
147 {
148 uint64_t plic_aplic_addr;
149 uint32_t gsi_base;
150 uint8_t socket;
151
152 for (socket = 0; socket < socket_count; socket++) {
153 plic_aplic_addr = mmio_base + mmio_size * socket;
154 gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
155 Aml *dev = aml_device("IC%.02X", socket);
156 aml_append(dev, aml_name_decl("_HID", aml_string("%s", hid)));
157 aml_append(dev, aml_name_decl("_UID", aml_int(socket)));
158 aml_append(dev, aml_name_decl("_GSB", aml_int(gsi_base)));
159
160 Aml *crs = aml_resource_template();
161 aml_append(crs, aml_memory32_fixed(plic_aplic_addr, mmio_size,
162 AML_READ_WRITE));
163 aml_append(dev, aml_name_decl("_CRS", crs));
164 aml_append(scope, dev);
165 }
166 }
167
168 static void
acpi_dsdt_add_uart(Aml * scope,const MemMapEntry * uart_memmap,uint32_t uart_irq)169 acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
170 uint32_t uart_irq)
171 {
172 Aml *dev = aml_device("COM0");
173 aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0003")));
174 aml_append(dev, aml_name_decl("_UID", aml_int(0)));
175
176 Aml *crs = aml_resource_template();
177 aml_append(crs, aml_memory32_fixed(uart_memmap->base,
178 uart_memmap->size, AML_READ_WRITE));
179 aml_append(crs,
180 aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
181 AML_EXCLUSIVE, &uart_irq, 1));
182 aml_append(dev, aml_name_decl("_CRS", crs));
183
184 Aml *pkg = aml_package(2);
185 aml_append(pkg, aml_string("clock-frequency"));
186 aml_append(pkg, aml_int(3686400));
187
188 Aml *UUID = aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301");
189
190 Aml *pkg1 = aml_package(1);
191 aml_append(pkg1, pkg);
192
193 Aml *package = aml_package(2);
194 aml_append(package, UUID);
195 aml_append(package, pkg1);
196
197 aml_append(dev, aml_name_decl("_DSD", package));
198 aml_append(scope, dev);
199 }
200
201 /*
202 * Add DSDT entry for the IOMMU platform device.
203 * ACPI ID for IOMMU is defined in the section 6.2 of RISC-V BRS spec.
204 * https://github.com/riscv-non-isa/riscv-brs/releases/download/v0.8/riscv-brs-spec.pdf
205 */
acpi_dsdt_add_iommu_sys(Aml * scope,const MemMapEntry * iommu_memmap,uint32_t iommu_irq)206 static void acpi_dsdt_add_iommu_sys(Aml *scope, const MemMapEntry *iommu_memmap,
207 uint32_t iommu_irq)
208 {
209 uint32_t i;
210
211 Aml *dev = aml_device("IMU0");
212 aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0004")));
213 aml_append(dev, aml_name_decl("_UID", aml_int(0)));
214
215 Aml *crs = aml_resource_template();
216 aml_append(crs, aml_memory32_fixed(iommu_memmap->base,
217 iommu_memmap->size, AML_READ_WRITE));
218 for (i = iommu_irq; i < iommu_irq + 4; i++) {
219 aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_LOW,
220 AML_EXCLUSIVE, &i, 1));
221 }
222
223 aml_append(dev, aml_name_decl("_CRS", crs));
224 aml_append(scope, dev);
225 }
226
227 /*
228 * Serial Port Console Redirection Table (SPCR)
229 * Rev: 1.10
230 */
231
232 static void
spcr_setup(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)233 spcr_setup(GArray *table_data, BIOSLinker *linker, RISCVVirtState *s)
234 {
235 const char name[] = ".";
236 AcpiSpcrData serial = {
237 .interface_type = 0x12, /* 16550 compatible */
238 .base_addr.id = AML_AS_SYSTEM_MEMORY,
239 .base_addr.width = 32,
240 .base_addr.offset = 0,
241 .base_addr.size = 1,
242 .base_addr.addr = s->memmap[VIRT_UART0].base,
243 .interrupt_type = (1 << 4),/* Bit[4] RISC-V PLIC/APLIC */
244 .pc_interrupt = 0,
245 .interrupt = UART0_IRQ,
246 .baud_rate = 7, /* 15200 */
247 .parity = 0,
248 .stop_bits = 1,
249 .flow_control = 0,
250 .terminal_type = 3, /* ANSI */
251 .language = 0, /* Language */
252 .pci_device_id = 0xffff, /* not a PCI device*/
253 .pci_vendor_id = 0xffff, /* not a PCI device*/
254 .pci_bus = 0,
255 .pci_device = 0,
256 .pci_function = 0,
257 .pci_flags = 0,
258 .pci_segment = 0,
259 .uart_clk_freq = 0,
260 .precise_baudrate = 0,
261 .namespace_string_length = sizeof(name),
262 .namespace_string_offset = 88,
263 };
264
265 build_spcr(table_data, linker, &serial, 4, s->oem_id, s->oem_table_id,
266 name);
267 }
268
269 /* RHCT Node[N] starts at offset 56 */
270 #define RHCT_NODE_ARRAY_OFFSET 56
271
272 /*
273 * ACPI spec, Revision 6.6
274 * 5.2.37 RISC-V Hart Capabilities Table (RHCT)
275 */
build_rhct(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)276 static void build_rhct(GArray *table_data,
277 BIOSLinker *linker,
278 RISCVVirtState *s)
279 {
280 MachineClass *mc = MACHINE_GET_CLASS(s);
281 MachineState *ms = MACHINE(s);
282 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
283 size_t len, aligned_len;
284 uint32_t isa_offset, num_rhct_nodes, cmo_offset = 0;
285 RISCVCPU *cpu = &s->soc[0].harts[0];
286 uint32_t mmu_offset = 0;
287 bool rv32 = riscv_cpu_is_32bit(cpu);
288 g_autofree char *isa = NULL;
289
290 AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id,
291 .oem_table_id = s->oem_table_id };
292
293 acpi_table_begin(&table, table_data);
294
295 build_append_int_noprefix(table_data, 0x0, 4); /* Reserved */
296
297 /* Time Base Frequency */
298 build_append_int_noprefix(table_data,
299 RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, 8);
300
301 /* ISA + N hart info */
302 num_rhct_nodes = 1 + ms->smp.cpus;
303 if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) {
304 num_rhct_nodes++;
305 }
306
307 if (!rv32 && cpu->cfg.max_satp_mode >= VM_1_10_SV39) {
308 num_rhct_nodes++;
309 }
310
311 /* Number of RHCT nodes*/
312 build_append_int_noprefix(table_data, num_rhct_nodes, 4);
313
314 /* Offset to the RHCT node array */
315 build_append_int_noprefix(table_data, RHCT_NODE_ARRAY_OFFSET, 4);
316
317 /* ISA String Node */
318 isa_offset = table_data->len - table.table_offset;
319 build_append_int_noprefix(table_data, 0, 2); /* Type 0 */
320
321 isa = riscv_isa_string(cpu);
322 len = 8 + strlen(isa) + 1;
323 aligned_len = (len % 2) ? (len + 1) : len;
324
325 build_append_int_noprefix(table_data, aligned_len, 2); /* Length */
326 build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
327
328 /* ISA string length including NUL */
329 build_append_int_noprefix(table_data, strlen(isa) + 1, 2);
330 g_array_append_vals(table_data, isa, strlen(isa) + 1); /* ISA string */
331
332 if (aligned_len != len) {
333 build_append_int_noprefix(table_data, 0x0, 1); /* Optional Padding */
334 }
335
336 /* CMO node */
337 if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) {
338 cmo_offset = table_data->len - table.table_offset;
339 build_append_int_noprefix(table_data, 1, 2); /* Type */
340 build_append_int_noprefix(table_data, 10, 2); /* Length */
341 build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
342 build_append_int_noprefix(table_data, 0, 1); /* Reserved */
343
344 /* CBOM block size */
345 if (cpu->cfg.cbom_blocksize) {
346 build_append_int_noprefix(table_data,
347 __builtin_ctz(cpu->cfg.cbom_blocksize),
348 1);
349 } else {
350 build_append_int_noprefix(table_data, 0, 1);
351 }
352
353 /* CBOP block size */
354 build_append_int_noprefix(table_data, 0, 1);
355
356 /* CBOZ block size */
357 if (cpu->cfg.cboz_blocksize) {
358 build_append_int_noprefix(table_data,
359 __builtin_ctz(cpu->cfg.cboz_blocksize),
360 1);
361 } else {
362 build_append_int_noprefix(table_data, 0, 1);
363 }
364 }
365
366 /* MMU node structure */
367 if (!rv32 && cpu->cfg.max_satp_mode >= VM_1_10_SV39) {
368 mmu_offset = table_data->len - table.table_offset;
369 build_append_int_noprefix(table_data, 2, 2); /* Type */
370 build_append_int_noprefix(table_data, 8, 2); /* Length */
371 build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
372 build_append_int_noprefix(table_data, 0, 1); /* Reserved */
373 /* MMU Type */
374 if (cpu->cfg.max_satp_mode == VM_1_10_SV57) {
375 build_append_int_noprefix(table_data, 2, 1); /* Sv57 */
376 } else if (cpu->cfg.max_satp_mode == VM_1_10_SV48) {
377 build_append_int_noprefix(table_data, 1, 1); /* Sv48 */
378 } else if (cpu->cfg.max_satp_mode == VM_1_10_SV39) {
379 build_append_int_noprefix(table_data, 0, 1); /* Sv39 */
380 } else {
381 g_assert_not_reached();
382 }
383 }
384
385 /* Hart Info Node */
386 for (int i = 0; i < arch_ids->len; i++) {
387 len = 16;
388 int num_offsets = 1;
389 build_append_int_noprefix(table_data, 0xFFFF, 2); /* Type */
390
391 /* Length */
392 if (cmo_offset) {
393 len += 4;
394 num_offsets++;
395 }
396
397 if (mmu_offset) {
398 len += 4;
399 num_offsets++;
400 }
401
402 build_append_int_noprefix(table_data, len, 2);
403 build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
404 /* Number of offsets */
405 build_append_int_noprefix(table_data, num_offsets, 2);
406 build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */
407 /* Offsets */
408 build_append_int_noprefix(table_data, isa_offset, 4);
409 if (cmo_offset) {
410 build_append_int_noprefix(table_data, cmo_offset, 4);
411 }
412
413 if (mmu_offset) {
414 build_append_int_noprefix(table_data, mmu_offset, 4);
415 }
416 }
417
418 acpi_table_end(linker, &table);
419 }
420
421 /*
422 * ACPI spec, Revision 6.6
423 * 5.2.9 Fixed ACPI Description Table (MADT)
424 */
build_fadt_rev6(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s,unsigned dsdt_tbl_offset)425 static void build_fadt_rev6(GArray *table_data,
426 BIOSLinker *linker,
427 RISCVVirtState *s,
428 unsigned dsdt_tbl_offset)
429 {
430 AcpiFadtData fadt = {
431 .rev = 6,
432 .minor_ver = 6,
433 .flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI,
434 .xdsdt_tbl_offset = &dsdt_tbl_offset,
435 };
436
437 build_fadt(table_data, linker, &fadt, s->oem_id, s->oem_table_id);
438 }
439
440 /* DSDT */
build_dsdt(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)441 static void build_dsdt(GArray *table_data,
442 BIOSLinker *linker,
443 RISCVVirtState *s)
444 {
445 Aml *scope, *dsdt;
446 MachineState *ms = MACHINE(s);
447 uint8_t socket_count;
448 const MemMapEntry *memmap = s->memmap;
449 AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = s->oem_id,
450 .oem_table_id = s->oem_table_id };
451
452
453 acpi_table_begin(&table, table_data);
454 dsdt = init_aml_allocator();
455
456 /*
457 * When booting the VM with UEFI, UEFI takes ownership of the RTC hardware.
458 * While UEFI can use libfdt to disable the RTC device node in the DTB that
459 * it passes to the OS, it cannot modify AML. Therefore, we won't generate
460 * the RTC ACPI device at all when using UEFI.
461 */
462 scope = aml_scope("\\_SB");
463 acpi_dsdt_add_cpus(scope, s);
464
465 fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]);
466
467 socket_count = riscv_socket_count(ms);
468
469 if (s->aia_type == VIRT_AIA_TYPE_NONE) {
470 acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_PLIC].base,
471 memmap[VIRT_PLIC].size, "RSCV0001");
472 } else {
473 acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_APLIC_S].base,
474 memmap[VIRT_APLIC_S].size, "RSCV0002");
475 }
476
477 acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ);
478 if (virt_is_iommu_sys_enabled(s)) {
479 acpi_dsdt_add_iommu_sys(scope, &memmap[VIRT_IOMMU_SYS], IOMMU_SYS_IRQ);
480 }
481
482 if (socket_count == 1) {
483 virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
484 memmap[VIRT_VIRTIO].size,
485 VIRTIO_IRQ, 0, VIRTIO_COUNT);
486 acpi_dsdt_add_gpex_host(scope, PCIE_IRQ);
487 } else if (socket_count == 2) {
488 virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
489 memmap[VIRT_VIRTIO].size,
490 VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0,
491 VIRTIO_COUNT);
492 acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES);
493 } else {
494 virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
495 memmap[VIRT_VIRTIO].size,
496 VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0,
497 VIRTIO_COUNT);
498 acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES * 2);
499 }
500
501 aml_append(dsdt, scope);
502
503 /* copy AML table into ACPI tables blob and patch header there */
504 g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
505
506 acpi_table_end(linker, &table);
507 free_aml_allocator();
508 }
509
510 /*
511 * ACPI spec, Revision 6.6
512 * 5.2.12 Multiple APIC Description Table (MADT)
513 */
build_madt(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)514 static void build_madt(GArray *table_data,
515 BIOSLinker *linker,
516 RISCVVirtState *s)
517 {
518 MachineClass *mc = MACHINE_GET_CLASS(s);
519 MachineState *ms = MACHINE(s);
520 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
521 uint8_t group_index_bits = imsic_num_bits(riscv_socket_count(ms));
522 uint8_t guest_index_bits = imsic_num_bits(s->aia_guests + 1);
523 uint16_t imsic_max_hart_per_socket = 0;
524 uint8_t hart_index_bits;
525 uint64_t aplic_addr;
526 uint32_t gsi_base;
527 uint8_t socket;
528
529 for (socket = 0; socket < riscv_socket_count(ms); socket++) {
530 if (imsic_max_hart_per_socket < s->soc[socket].num_harts) {
531 imsic_max_hart_per_socket = s->soc[socket].num_harts;
532 }
533 }
534
535 hart_index_bits = imsic_num_bits(imsic_max_hart_per_socket);
536
537 AcpiTable table = { .sig = "APIC", .rev = 7, .oem_id = s->oem_id,
538 .oem_table_id = s->oem_table_id };
539
540 acpi_table_begin(&table, table_data);
541 /* Local Interrupt Controller Address */
542 build_append_int_noprefix(table_data, 0, 4);
543 build_append_int_noprefix(table_data, 0, 4); /* MADT Flags */
544
545 /* RISC-V Local INTC structures per HART */
546 for (int i = 0; i < arch_ids->len; i++) {
547 riscv_acpi_madt_add_rintc(i, arch_ids, table_data, s);
548 }
549
550 /* IMSIC */
551 if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
552 /* IMSIC */
553 build_append_int_noprefix(table_data, 0x19, 1); /* Type */
554 build_append_int_noprefix(table_data, 16, 1); /* Length */
555 build_append_int_noprefix(table_data, 1, 1); /* Version */
556 build_append_int_noprefix(table_data, 0, 1); /* Reserved */
557 build_append_int_noprefix(table_data, 0, 4); /* Flags */
558 /* Number of supervisor mode Interrupt Identities */
559 build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
560 /* Number of guest mode Interrupt Identities */
561 build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
562 /* Guest Index Bits */
563 build_append_int_noprefix(table_data, guest_index_bits, 1);
564 /* Hart Index Bits */
565 build_append_int_noprefix(table_data, hart_index_bits, 1);
566 /* Group Index Bits */
567 build_append_int_noprefix(table_data, group_index_bits, 1);
568 /* Group Index Shift */
569 build_append_int_noprefix(table_data, IMSIC_MMIO_GROUP_MIN_SHIFT, 1);
570 }
571
572 if (s->aia_type != VIRT_AIA_TYPE_NONE) {
573 /* APLICs */
574 for (socket = 0; socket < riscv_socket_count(ms); socket++) {
575 aplic_addr = s->memmap[VIRT_APLIC_S].base +
576 s->memmap[VIRT_APLIC_S].size * socket;
577 gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
578 build_append_int_noprefix(table_data, 0x1A, 1); /* Type */
579 build_append_int_noprefix(table_data, 36, 1); /* Length */
580 build_append_int_noprefix(table_data, 1, 1); /* Version */
581 build_append_int_noprefix(table_data, socket, 1); /* APLIC ID */
582 build_append_int_noprefix(table_data, 0, 4); /* Flags */
583 build_append_int_noprefix(table_data, 0, 8); /* Hardware ID */
584 /* Number of IDCs */
585 if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
586 build_append_int_noprefix(table_data,
587 s->soc[socket].num_harts,
588 2);
589 } else {
590 build_append_int_noprefix(table_data, 0, 2);
591 }
592 /* Total External Interrupt Sources Supported */
593 build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_SOURCES, 2);
594 /* Global System Interrupt Base */
595 build_append_int_noprefix(table_data, gsi_base, 4);
596 /* APLIC Address */
597 build_append_int_noprefix(table_data, aplic_addr, 8);
598 /* APLIC size */
599 build_append_int_noprefix(table_data,
600 s->memmap[VIRT_APLIC_S].size, 4);
601 }
602 } else {
603 /* PLICs */
604 for (socket = 0; socket < riscv_socket_count(ms); socket++) {
605 aplic_addr = s->memmap[VIRT_PLIC].base +
606 s->memmap[VIRT_PLIC].size * socket;
607 gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
608 build_append_int_noprefix(table_data, 0x1B, 1); /* Type */
609 build_append_int_noprefix(table_data, 36, 1); /* Length */
610 build_append_int_noprefix(table_data, 1, 1); /* Version */
611 build_append_int_noprefix(table_data, socket, 1); /* PLIC ID */
612 build_append_int_noprefix(table_data, 0, 8); /* Hardware ID */
613 /* Total External Interrupt Sources Supported */
614 build_append_int_noprefix(table_data,
615 VIRT_IRQCHIP_NUM_SOURCES - 1, 2);
616 build_append_int_noprefix(table_data, 0, 2); /* Max Priority */
617 build_append_int_noprefix(table_data, 0, 4); /* Flags */
618 /* PLIC Size */
619 build_append_int_noprefix(table_data, s->memmap[VIRT_PLIC].size, 4);
620 /* PLIC Address */
621 build_append_int_noprefix(table_data, aplic_addr, 8);
622 /* Global System Interrupt Vector Base */
623 build_append_int_noprefix(table_data, gsi_base, 4);
624 }
625 }
626
627 acpi_table_end(linker, &table);
628 }
629
630 #define ID_MAPPING_ENTRY_SIZE 20
631 #define IOMMU_ENTRY_SIZE 40
632 #define RISCV_INTERRUPT_WIRE_OFFSSET 40
633 #define ROOT_COMPLEX_ENTRY_SIZE 20
634 #define RIMT_NODE_OFFSET 48
635
636 /*
637 * ID Mapping Structure
638 */
build_rimt_id_mapping(GArray * table_data,uint32_t source_id_base,uint32_t num_ids,uint32_t dest_id_base)639 static void build_rimt_id_mapping(GArray *table_data, uint32_t source_id_base,
640 uint32_t num_ids, uint32_t dest_id_base)
641 {
642 /* Source ID Base */
643 build_append_int_noprefix(table_data, source_id_base, 4);
644 /* Number of IDs */
645 build_append_int_noprefix(table_data, num_ids, 4);
646 /* Destination Device ID Base */
647 build_append_int_noprefix(table_data, source_id_base, 4);
648 /* Destination IOMMU Offset */
649 build_append_int_noprefix(table_data, dest_id_base, 4);
650 /* Flags */
651 build_append_int_noprefix(table_data, 0, 4);
652 }
653
654 struct AcpiRimtIdMapping {
655 uint32_t source_id_base;
656 uint32_t num_ids;
657 };
658 typedef struct AcpiRimtIdMapping AcpiRimtIdMapping;
659
660 /* Build the rimt ID mapping to IOMMU for a given PCI host bridge */
rimt_host_bridges(Object * obj,void * opaque)661 static int rimt_host_bridges(Object *obj, void *opaque)
662 {
663 GArray *idmap_blob = opaque;
664
665 if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
666 PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
667
668 if (bus && !pci_bus_bypass_iommu(bus)) {
669 int min_bus, max_bus;
670
671 pci_bus_range(bus, &min_bus, &max_bus);
672
673 AcpiRimtIdMapping idmap = {
674 .source_id_base = min_bus << 8,
675 .num_ids = (max_bus - min_bus + 1) << 8,
676 };
677 g_array_append_val(idmap_blob, idmap);
678 }
679 }
680
681 return 0;
682 }
683
rimt_idmap_compare(gconstpointer a,gconstpointer b)684 static int rimt_idmap_compare(gconstpointer a, gconstpointer b)
685 {
686 AcpiRimtIdMapping *idmap_a = (AcpiRimtIdMapping *)a;
687 AcpiRimtIdMapping *idmap_b = (AcpiRimtIdMapping *)b;
688
689 return idmap_a->source_id_base - idmap_b->source_id_base;
690 }
691
692 /*
693 * RISC-V IO Mapping Table (RIMT)
694 * https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf
695 */
build_rimt(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)696 static void build_rimt(GArray *table_data, BIOSLinker *linker,
697 RISCVVirtState *s)
698 {
699 int i, nb_nodes, rc_mapping_count;
700 size_t node_size, iommu_offset = 0;
701 uint32_t id = 0;
702 g_autoptr(GArray) iommu_idmaps = g_array_new(false, true,
703 sizeof(AcpiRimtIdMapping));
704
705 AcpiTable table = { .sig = "RIMT", .rev = 1, .oem_id = s->oem_id,
706 .oem_table_id = s->oem_table_id };
707
708 acpi_table_begin(&table, table_data);
709
710 object_child_foreach_recursive(object_get_root(),
711 rimt_host_bridges, iommu_idmaps);
712
713 /* Sort the ID mapping by Source ID Base*/
714 g_array_sort(iommu_idmaps, rimt_idmap_compare);
715
716 nb_nodes = 2; /* RC, IOMMU */
717 rc_mapping_count = iommu_idmaps->len;
718 /* Number of RIMT Nodes */
719 build_append_int_noprefix(table_data, nb_nodes, 4);
720
721 /* Offset to Array of RIMT Nodes */
722 build_append_int_noprefix(table_data, RIMT_NODE_OFFSET, 4);
723 build_append_int_noprefix(table_data, 0, 4); /* Reserved */
724
725 iommu_offset = table_data->len - table.table_offset;
726 /* IOMMU Device Structure */
727 build_append_int_noprefix(table_data, 0, 1); /* Type - IOMMU*/
728 build_append_int_noprefix(table_data, 1, 1); /* Revision */
729 node_size = IOMMU_ENTRY_SIZE;
730 build_append_int_noprefix(table_data, node_size, 2); /* Length */
731 build_append_int_noprefix(table_data, 0, 2); /* Reserved */
732 build_append_int_noprefix(table_data, id++, 2); /* ID */
733 if (virt_is_iommu_sys_enabled(s)) {
734 /* Hardware ID */
735 build_append_int_noprefix(table_data, 'R', 1);
736 build_append_int_noprefix(table_data, 'S', 1);
737 build_append_int_noprefix(table_data, 'C', 1);
738 build_append_int_noprefix(table_data, 'V', 1);
739 build_append_int_noprefix(table_data, '0', 1);
740 build_append_int_noprefix(table_data, '0', 1);
741 build_append_int_noprefix(table_data, '0', 1);
742 build_append_int_noprefix(table_data, '4', 1);
743 /* Base Address */
744 build_append_int_noprefix(table_data,
745 s->memmap[VIRT_IOMMU_SYS].base, 8);
746 build_append_int_noprefix(table_data, 0, 4); /* Flags */
747 } else {
748 /* Hardware ID */
749 build_append_int_noprefix(table_data, '0', 1);
750 build_append_int_noprefix(table_data, '0', 1);
751 build_append_int_noprefix(table_data, '1', 1);
752 build_append_int_noprefix(table_data, '0', 1);
753 build_append_int_noprefix(table_data, '0', 1);
754 build_append_int_noprefix(table_data, '0', 1);
755 build_append_int_noprefix(table_data, '1', 1);
756 build_append_int_noprefix(table_data, '4', 1);
757
758 build_append_int_noprefix(table_data, 0, 8); /* Base Address */
759 build_append_int_noprefix(table_data, 1, 4); /* Flags */
760 }
761
762 build_append_int_noprefix(table_data, 0, 4); /* Proximity Domain */
763 build_append_int_noprefix(table_data, 0, 2); /* PCI Segment number */
764 /* PCIe B/D/F */
765 if (virt_is_iommu_sys_enabled(s)) {
766 build_append_int_noprefix(table_data, 0, 2);
767 } else {
768 build_append_int_noprefix(table_data, s->pci_iommu_bdf, 2);
769 }
770 /* Number of interrupt wires */
771 build_append_int_noprefix(table_data, 0, 2);
772 /* Interrupt wire array offset */
773 build_append_int_noprefix(table_data, RISCV_INTERRUPT_WIRE_OFFSSET, 2);
774
775 /* PCIe Root Complex Node */
776 build_append_int_noprefix(table_data, 1, 1); /* Type */
777 build_append_int_noprefix(table_data, 1, 1); /* Revision */
778 node_size = ROOT_COMPLEX_ENTRY_SIZE +
779 ID_MAPPING_ENTRY_SIZE * rc_mapping_count;
780 build_append_int_noprefix(table_data, node_size, 2); /* Length */
781 build_append_int_noprefix(table_data, 0, 2); /* Reserved */
782 build_append_int_noprefix(table_data, id++, 2); /* ID */
783 build_append_int_noprefix(table_data, 0, 4); /* Flags */
784 build_append_int_noprefix(table_data, 0, 2); /* Reserved */
785 /* PCI Segment number */
786 build_append_int_noprefix(table_data, 0, 2);
787 /* ID mapping array offset */
788 build_append_int_noprefix(table_data, ROOT_COMPLEX_ENTRY_SIZE, 2);
789 /* Number of ID mappings */
790 build_append_int_noprefix(table_data, rc_mapping_count, 2);
791
792 /* Output Reference */
793 AcpiRimtIdMapping *range;
794
795 /* ID mapping array */
796 for (i = 0; i < iommu_idmaps->len; i++) {
797 range = &g_array_index(iommu_idmaps, AcpiRimtIdMapping, i);
798 if (virt_is_iommu_sys_enabled(s)) {
799 range->source_id_base = 0;
800 } else {
801 range->source_id_base = s->pci_iommu_bdf + 1;
802 }
803 range->num_ids = 0xffff - s->pci_iommu_bdf;
804 build_rimt_id_mapping(table_data, range->source_id_base,
805 range->num_ids, iommu_offset);
806 }
807
808 acpi_table_end(linker, &table);
809 }
810
811 /*
812 * ACPI spec, Revision 6.6
813 * 5.2.16 System Resource Affinity Table (SRAT)
814 */
815 static void
build_srat(GArray * table_data,BIOSLinker * linker,RISCVVirtState * vms)816 build_srat(GArray *table_data, BIOSLinker *linker, RISCVVirtState *vms)
817 {
818 int i;
819 uint64_t mem_base;
820 MachineClass *mc = MACHINE_GET_CLASS(vms);
821 MachineState *ms = MACHINE(vms);
822 const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(ms);
823 AcpiTable table = { .sig = "SRAT", .rev = 3, .oem_id = vms->oem_id,
824 .oem_table_id = vms->oem_table_id };
825
826 acpi_table_begin(&table, table_data);
827 build_append_int_noprefix(table_data, 1, 4); /* Reserved */
828 build_append_int_noprefix(table_data, 0, 8); /* Reserved */
829
830 for (i = 0; i < cpu_list->len; ++i) {
831 uint32_t nodeid = cpu_list->cpus[i].props.node_id;
832 /*
833 * 5.2.16.8 RINTC Affinity Structure
834 */
835 build_append_int_noprefix(table_data, 7, 1); /* Type */
836 build_append_int_noprefix(table_data, 20, 1); /* Length */
837 build_append_int_noprefix(table_data, 0, 2); /* Reserved */
838 build_append_int_noprefix(table_data, nodeid, 4); /* Proximity Domain */
839 build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */
840 /* Flags, Table 5-70 */
841 build_append_int_noprefix(table_data, 1 /* Flags: Enabled */, 4);
842 build_append_int_noprefix(table_data, 0, 4); /* Clock Domain */
843 }
844
845 mem_base = vms->memmap[VIRT_DRAM].base;
846 for (i = 0; i < ms->numa_state->num_nodes; ++i) {
847 if (ms->numa_state->nodes[i].node_mem > 0) {
848 build_srat_memory(table_data, mem_base,
849 ms->numa_state->nodes[i].node_mem, i,
850 MEM_AFFINITY_ENABLED);
851 mem_base += ms->numa_state->nodes[i].node_mem;
852 }
853 }
854
855 acpi_table_end(linker, &table);
856 }
857
virt_acpi_build(RISCVVirtState * s,AcpiBuildTables * tables)858 static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables)
859 {
860 GArray *table_offsets;
861 unsigned dsdt, xsdt;
862 GArray *tables_blob = tables->table_data;
863 MachineState *ms = MACHINE(s);
864
865 table_offsets = g_array_new(false, true,
866 sizeof(uint32_t));
867
868 bios_linker_loader_alloc(tables->linker,
869 ACPI_BUILD_TABLE_FILE, tables_blob,
870 64, false);
871
872 /* DSDT is pointed to by FADT */
873 dsdt = tables_blob->len;
874 build_dsdt(tables_blob, tables->linker, s);
875
876 /* FADT and others pointed to by XSDT */
877 acpi_add_table(table_offsets, tables_blob);
878 build_fadt_rev6(tables_blob, tables->linker, s, dsdt);
879
880 acpi_add_table(table_offsets, tables_blob);
881 build_madt(tables_blob, tables->linker, s);
882
883 acpi_add_table(table_offsets, tables_blob);
884 build_rhct(tables_blob, tables->linker, s);
885
886 if (virt_is_iommu_sys_enabled(s) || s->pci_iommu_bdf) {
887 acpi_add_table(table_offsets, tables_blob);
888 build_rimt(tables_blob, tables->linker, s);
889 }
890
891 acpi_add_table(table_offsets, tables_blob);
892
893 if (ms->acpi_spcr_enabled) {
894 spcr_setup(tables_blob, tables->linker, s);
895 }
896
897 acpi_add_table(table_offsets, tables_blob);
898 {
899 AcpiMcfgInfo mcfg = {
900 .base = s->memmap[VIRT_PCIE_ECAM].base,
901 .size = s->memmap[VIRT_PCIE_ECAM].size,
902 };
903 build_mcfg(tables_blob, tables->linker, &mcfg, s->oem_id,
904 s->oem_table_id);
905 }
906
907 if (ms->numa_state->num_nodes > 0) {
908 acpi_add_table(table_offsets, tables_blob);
909 build_srat(tables_blob, tables->linker, s);
910 if (ms->numa_state->have_numa_distance) {
911 acpi_add_table(table_offsets, tables_blob);
912 build_slit(tables_blob, tables->linker, ms, s->oem_id,
913 s->oem_table_id);
914 }
915 }
916
917 /* XSDT is pointed to by RSDP */
918 xsdt = tables_blob->len;
919 build_xsdt(tables_blob, tables->linker, table_offsets, s->oem_id,
920 s->oem_table_id);
921
922 /* RSDP is in FSEG memory, so allocate it separately */
923 {
924 AcpiRsdpData rsdp_data = {
925 .revision = 2,
926 .oem_id = s->oem_id,
927 .xsdt_tbl_offset = &xsdt,
928 .rsdt_tbl_offset = NULL,
929 };
930 build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
931 }
932
933 /*
934 * The align size is 128, warn if 64k is not enough therefore
935 * the align size could be resized.
936 */
937 if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
938 warn_report("ACPI table size %u exceeds %d bytes,"
939 " migration may not work",
940 tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
941 error_printf("Try removing some objects.");
942 }
943
944 acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
945
946 /* Clean up memory that's no longer used */
947 g_array_free(table_offsets, true);
948 }
949
acpi_ram_update(MemoryRegion * mr,GArray * data)950 static void acpi_ram_update(MemoryRegion *mr, GArray *data)
951 {
952 uint32_t size = acpi_data_len(data);
953
954 /*
955 * Make sure RAM size is correct - in case it got changed
956 * e.g. by migration
957 */
958 memory_region_ram_resize(mr, size, &error_abort);
959
960 memcpy(memory_region_get_ram_ptr(mr), data->data, size);
961 memory_region_set_dirty(mr, 0, size);
962 }
963
virt_acpi_build_update(void * build_opaque)964 static void virt_acpi_build_update(void *build_opaque)
965 {
966 AcpiBuildState *build_state = build_opaque;
967 AcpiBuildTables tables;
968
969 /* No state to update or already patched? Nothing to do. */
970 if (!build_state || build_state->patched) {
971 return;
972 }
973
974 build_state->patched = true;
975
976 acpi_build_tables_init(&tables);
977
978 virt_acpi_build(RISCV_VIRT_MACHINE(qdev_get_machine()), &tables);
979
980 acpi_ram_update(build_state->table_mr, tables.table_data);
981 acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
982 acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
983
984 acpi_build_tables_cleanup(&tables, true);
985 }
986
virt_acpi_build_reset(void * build_opaque)987 static void virt_acpi_build_reset(void *build_opaque)
988 {
989 AcpiBuildState *build_state = build_opaque;
990 build_state->patched = false;
991 }
992
993 static const VMStateDescription vmstate_virt_acpi_build = {
994 .name = "virt_acpi_build",
995 .version_id = 1,
996 .minimum_version_id = 1,
997 .fields = (const VMStateField[]) {
998 VMSTATE_BOOL(patched, AcpiBuildState),
999 VMSTATE_END_OF_LIST()
1000 },
1001 };
1002
virt_acpi_setup(RISCVVirtState * s)1003 void virt_acpi_setup(RISCVVirtState *s)
1004 {
1005 AcpiBuildTables tables;
1006 AcpiBuildState *build_state;
1007
1008 build_state = g_malloc0(sizeof *build_state);
1009
1010 acpi_build_tables_init(&tables);
1011 virt_acpi_build(s, &tables);
1012
1013 /* Now expose it all to Guest */
1014 build_state->table_mr = acpi_add_rom_blob(virt_acpi_build_update,
1015 build_state, tables.table_data,
1016 ACPI_BUILD_TABLE_FILE);
1017 assert(build_state->table_mr != NULL);
1018
1019 build_state->linker_mr = acpi_add_rom_blob(virt_acpi_build_update,
1020 build_state,
1021 tables.linker->cmd_blob,
1022 ACPI_BUILD_LOADER_FILE);
1023
1024 build_state->rsdp_mr = acpi_add_rom_blob(virt_acpi_build_update,
1025 build_state, tables.rsdp,
1026 ACPI_BUILD_RSDP_FILE);
1027
1028 qemu_register_reset(virt_acpi_build_reset, build_state);
1029 virt_acpi_build_reset(build_state);
1030 vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state);
1031
1032 /*
1033 * Clean up tables but don't free the memory: we track it
1034 * in build_state.
1035 */
1036 acpi_build_tables_cleanup(&tables, false);
1037 }
1038