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.5+
274 * 5.2.36 RISC-V Hart Capabilities Table (RHCT)
275 * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/16
276 * https://drive.google.com/file/d/1nP3nFiH4jkPMp6COOxP6123DCZKR-tia/view
277 * https://drive.google.com/file/d/1sKbOa8m1UZw1JkquZYe3F1zQBN1xXsaf/view
278 */
build_rhct(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)279 static void build_rhct(GArray *table_data,
280 BIOSLinker *linker,
281 RISCVVirtState *s)
282 {
283 MachineClass *mc = MACHINE_GET_CLASS(s);
284 MachineState *ms = MACHINE(s);
285 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
286 size_t len, aligned_len;
287 uint32_t isa_offset, num_rhct_nodes, cmo_offset = 0;
288 RISCVCPU *cpu = &s->soc[0].harts[0];
289 uint32_t mmu_offset = 0;
290 bool rv32 = riscv_cpu_is_32bit(cpu);
291 g_autofree char *isa = NULL;
292
293 AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id,
294 .oem_table_id = s->oem_table_id };
295
296 acpi_table_begin(&table, table_data);
297
298 build_append_int_noprefix(table_data, 0x0, 4); /* Reserved */
299
300 /* Time Base Frequency */
301 build_append_int_noprefix(table_data,
302 RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, 8);
303
304 /* ISA + N hart info */
305 num_rhct_nodes = 1 + ms->smp.cpus;
306 if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) {
307 num_rhct_nodes++;
308 }
309
310 if (!rv32 && cpu->cfg.max_satp_mode >= VM_1_10_SV39) {
311 num_rhct_nodes++;
312 }
313
314 /* Number of RHCT nodes*/
315 build_append_int_noprefix(table_data, num_rhct_nodes, 4);
316
317 /* Offset to the RHCT node array */
318 build_append_int_noprefix(table_data, RHCT_NODE_ARRAY_OFFSET, 4);
319
320 /* ISA String Node */
321 isa_offset = table_data->len - table.table_offset;
322 build_append_int_noprefix(table_data, 0, 2); /* Type 0 */
323
324 isa = riscv_isa_string(cpu);
325 len = 8 + strlen(isa) + 1;
326 aligned_len = (len % 2) ? (len + 1) : len;
327
328 build_append_int_noprefix(table_data, aligned_len, 2); /* Length */
329 build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
330
331 /* ISA string length including NUL */
332 build_append_int_noprefix(table_data, strlen(isa) + 1, 2);
333 g_array_append_vals(table_data, isa, strlen(isa) + 1); /* ISA string */
334
335 if (aligned_len != len) {
336 build_append_int_noprefix(table_data, 0x0, 1); /* Optional Padding */
337 }
338
339 /* CMO node */
340 if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) {
341 cmo_offset = table_data->len - table.table_offset;
342 build_append_int_noprefix(table_data, 1, 2); /* Type */
343 build_append_int_noprefix(table_data, 10, 2); /* Length */
344 build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
345 build_append_int_noprefix(table_data, 0, 1); /* Reserved */
346
347 /* CBOM block size */
348 if (cpu->cfg.cbom_blocksize) {
349 build_append_int_noprefix(table_data,
350 __builtin_ctz(cpu->cfg.cbom_blocksize),
351 1);
352 } else {
353 build_append_int_noprefix(table_data, 0, 1);
354 }
355
356 /* CBOP block size */
357 build_append_int_noprefix(table_data, 0, 1);
358
359 /* CBOZ block size */
360 if (cpu->cfg.cboz_blocksize) {
361 build_append_int_noprefix(table_data,
362 __builtin_ctz(cpu->cfg.cboz_blocksize),
363 1);
364 } else {
365 build_append_int_noprefix(table_data, 0, 1);
366 }
367 }
368
369 /* MMU node structure */
370 if (!rv32 && cpu->cfg.max_satp_mode >= VM_1_10_SV39) {
371 mmu_offset = table_data->len - table.table_offset;
372 build_append_int_noprefix(table_data, 2, 2); /* Type */
373 build_append_int_noprefix(table_data, 8, 2); /* Length */
374 build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
375 build_append_int_noprefix(table_data, 0, 1); /* Reserved */
376 /* MMU Type */
377 if (cpu->cfg.max_satp_mode == VM_1_10_SV57) {
378 build_append_int_noprefix(table_data, 2, 1); /* Sv57 */
379 } else if (cpu->cfg.max_satp_mode == VM_1_10_SV48) {
380 build_append_int_noprefix(table_data, 1, 1); /* Sv48 */
381 } else if (cpu->cfg.max_satp_mode == VM_1_10_SV39) {
382 build_append_int_noprefix(table_data, 0, 1); /* Sv39 */
383 } else {
384 g_assert_not_reached();
385 }
386 }
387
388 /* Hart Info Node */
389 for (int i = 0; i < arch_ids->len; i++) {
390 len = 16;
391 int num_offsets = 1;
392 build_append_int_noprefix(table_data, 0xFFFF, 2); /* Type */
393
394 /* Length */
395 if (cmo_offset) {
396 len += 4;
397 num_offsets++;
398 }
399
400 if (mmu_offset) {
401 len += 4;
402 num_offsets++;
403 }
404
405 build_append_int_noprefix(table_data, len, 2);
406 build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
407 /* Number of offsets */
408 build_append_int_noprefix(table_data, num_offsets, 2);
409 build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */
410 /* Offsets */
411 build_append_int_noprefix(table_data, isa_offset, 4);
412 if (cmo_offset) {
413 build_append_int_noprefix(table_data, cmo_offset, 4);
414 }
415
416 if (mmu_offset) {
417 build_append_int_noprefix(table_data, mmu_offset, 4);
418 }
419 }
420
421 acpi_table_end(linker, &table);
422 }
423
424 /* FADT */
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 = 5,
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.5+
512 * 5.2.12 Multiple APIC Description Table (MADT)
513 * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/15
514 * https://drive.google.com/file/d/1R6k4MshhN3WTT-hwqAquu5nX6xSEqK2l/view
515 * https://drive.google.com/file/d/1oMGPyOD58JaPgMl1pKasT-VKsIKia7zR/view
516 */
build_madt(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)517 static void build_madt(GArray *table_data,
518 BIOSLinker *linker,
519 RISCVVirtState *s)
520 {
521 MachineClass *mc = MACHINE_GET_CLASS(s);
522 MachineState *ms = MACHINE(s);
523 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
524 uint8_t group_index_bits = imsic_num_bits(riscv_socket_count(ms));
525 uint8_t guest_index_bits = imsic_num_bits(s->aia_guests + 1);
526 uint16_t imsic_max_hart_per_socket = 0;
527 uint8_t hart_index_bits;
528 uint64_t aplic_addr;
529 uint32_t gsi_base;
530 uint8_t socket;
531
532 for (socket = 0; socket < riscv_socket_count(ms); socket++) {
533 if (imsic_max_hart_per_socket < s->soc[socket].num_harts) {
534 imsic_max_hart_per_socket = s->soc[socket].num_harts;
535 }
536 }
537
538 hart_index_bits = imsic_num_bits(imsic_max_hart_per_socket);
539
540 AcpiTable table = { .sig = "APIC", .rev = 6, .oem_id = s->oem_id,
541 .oem_table_id = s->oem_table_id };
542
543 acpi_table_begin(&table, table_data);
544 /* Local Interrupt Controller Address */
545 build_append_int_noprefix(table_data, 0, 4);
546 build_append_int_noprefix(table_data, 0, 4); /* MADT Flags */
547
548 /* RISC-V Local INTC structures per HART */
549 for (int i = 0; i < arch_ids->len; i++) {
550 riscv_acpi_madt_add_rintc(i, arch_ids, table_data, s);
551 }
552
553 /* IMSIC */
554 if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
555 /* IMSIC */
556 build_append_int_noprefix(table_data, 0x19, 1); /* Type */
557 build_append_int_noprefix(table_data, 16, 1); /* Length */
558 build_append_int_noprefix(table_data, 1, 1); /* Version */
559 build_append_int_noprefix(table_data, 0, 1); /* Reserved */
560 build_append_int_noprefix(table_data, 0, 4); /* Flags */
561 /* Number of supervisor mode Interrupt Identities */
562 build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
563 /* Number of guest mode Interrupt Identities */
564 build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
565 /* Guest Index Bits */
566 build_append_int_noprefix(table_data, guest_index_bits, 1);
567 /* Hart Index Bits */
568 build_append_int_noprefix(table_data, hart_index_bits, 1);
569 /* Group Index Bits */
570 build_append_int_noprefix(table_data, group_index_bits, 1);
571 /* Group Index Shift */
572 build_append_int_noprefix(table_data, IMSIC_MMIO_GROUP_MIN_SHIFT, 1);
573 }
574
575 if (s->aia_type != VIRT_AIA_TYPE_NONE) {
576 /* APLICs */
577 for (socket = 0; socket < riscv_socket_count(ms); socket++) {
578 aplic_addr = s->memmap[VIRT_APLIC_S].base +
579 s->memmap[VIRT_APLIC_S].size * socket;
580 gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
581 build_append_int_noprefix(table_data, 0x1A, 1); /* Type */
582 build_append_int_noprefix(table_data, 36, 1); /* Length */
583 build_append_int_noprefix(table_data, 1, 1); /* Version */
584 build_append_int_noprefix(table_data, socket, 1); /* APLIC ID */
585 build_append_int_noprefix(table_data, 0, 4); /* Flags */
586 build_append_int_noprefix(table_data, 0, 8); /* Hardware ID */
587 /* Number of IDCs */
588 if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
589 build_append_int_noprefix(table_data,
590 s->soc[socket].num_harts,
591 2);
592 } else {
593 build_append_int_noprefix(table_data, 0, 2);
594 }
595 /* Total External Interrupt Sources Supported */
596 build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_SOURCES, 2);
597 /* Global System Interrupt Base */
598 build_append_int_noprefix(table_data, gsi_base, 4);
599 /* APLIC Address */
600 build_append_int_noprefix(table_data, aplic_addr, 8);
601 /* APLIC size */
602 build_append_int_noprefix(table_data,
603 s->memmap[VIRT_APLIC_S].size, 4);
604 }
605 } else {
606 /* PLICs */
607 for (socket = 0; socket < riscv_socket_count(ms); socket++) {
608 aplic_addr = s->memmap[VIRT_PLIC].base +
609 s->memmap[VIRT_PLIC].size * socket;
610 gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
611 build_append_int_noprefix(table_data, 0x1B, 1); /* Type */
612 build_append_int_noprefix(table_data, 36, 1); /* Length */
613 build_append_int_noprefix(table_data, 1, 1); /* Version */
614 build_append_int_noprefix(table_data, socket, 1); /* PLIC ID */
615 build_append_int_noprefix(table_data, 0, 8); /* Hardware ID */
616 /* Total External Interrupt Sources Supported */
617 build_append_int_noprefix(table_data,
618 VIRT_IRQCHIP_NUM_SOURCES - 1, 2);
619 build_append_int_noprefix(table_data, 0, 2); /* Max Priority */
620 build_append_int_noprefix(table_data, 0, 4); /* Flags */
621 /* PLIC Size */
622 build_append_int_noprefix(table_data, s->memmap[VIRT_PLIC].size, 4);
623 /* PLIC Address */
624 build_append_int_noprefix(table_data, aplic_addr, 8);
625 /* Global System Interrupt Vector Base */
626 build_append_int_noprefix(table_data, gsi_base, 4);
627 }
628 }
629
630 acpi_table_end(linker, &table);
631 }
632
633 #define ID_MAPPING_ENTRY_SIZE 20
634 #define IOMMU_ENTRY_SIZE 40
635 #define RISCV_INTERRUPT_WIRE_OFFSSET 40
636 #define ROOT_COMPLEX_ENTRY_SIZE 20
637 #define RIMT_NODE_OFFSET 48
638
639 /*
640 * ID Mapping Structure
641 */
build_rimt_id_mapping(GArray * table_data,uint32_t source_id_base,uint32_t num_ids,uint32_t dest_id_base)642 static void build_rimt_id_mapping(GArray *table_data, uint32_t source_id_base,
643 uint32_t num_ids, uint32_t dest_id_base)
644 {
645 /* Source ID Base */
646 build_append_int_noprefix(table_data, source_id_base, 4);
647 /* Number of IDs */
648 build_append_int_noprefix(table_data, num_ids, 4);
649 /* Destination Device ID Base */
650 build_append_int_noprefix(table_data, source_id_base, 4);
651 /* Destination IOMMU Offset */
652 build_append_int_noprefix(table_data, dest_id_base, 4);
653 /* Flags */
654 build_append_int_noprefix(table_data, 0, 4);
655 }
656
657 struct AcpiRimtIdMapping {
658 uint32_t source_id_base;
659 uint32_t num_ids;
660 };
661 typedef struct AcpiRimtIdMapping AcpiRimtIdMapping;
662
663 /* Build the rimt ID mapping to IOMMU for a given PCI host bridge */
rimt_host_bridges(Object * obj,void * opaque)664 static int rimt_host_bridges(Object *obj, void *opaque)
665 {
666 GArray *idmap_blob = opaque;
667
668 if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
669 PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
670
671 if (bus && !pci_bus_bypass_iommu(bus)) {
672 int min_bus, max_bus;
673
674 pci_bus_range(bus, &min_bus, &max_bus);
675
676 AcpiRimtIdMapping idmap = {
677 .source_id_base = min_bus << 8,
678 .num_ids = (max_bus - min_bus + 1) << 8,
679 };
680 g_array_append_val(idmap_blob, idmap);
681 }
682 }
683
684 return 0;
685 }
686
rimt_idmap_compare(gconstpointer a,gconstpointer b)687 static int rimt_idmap_compare(gconstpointer a, gconstpointer b)
688 {
689 AcpiRimtIdMapping *idmap_a = (AcpiRimtIdMapping *)a;
690 AcpiRimtIdMapping *idmap_b = (AcpiRimtIdMapping *)b;
691
692 return idmap_a->source_id_base - idmap_b->source_id_base;
693 }
694
695 /*
696 * RISC-V IO Mapping Table (RIMT)
697 * https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf
698 */
build_rimt(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)699 static void build_rimt(GArray *table_data, BIOSLinker *linker,
700 RISCVVirtState *s)
701 {
702 int i, nb_nodes, rc_mapping_count;
703 size_t node_size, iommu_offset = 0;
704 uint32_t id = 0;
705 g_autoptr(GArray) iommu_idmaps = g_array_new(false, true,
706 sizeof(AcpiRimtIdMapping));
707
708 AcpiTable table = { .sig = "RIMT", .rev = 1, .oem_id = s->oem_id,
709 .oem_table_id = s->oem_table_id };
710
711 acpi_table_begin(&table, table_data);
712
713 object_child_foreach_recursive(object_get_root(),
714 rimt_host_bridges, iommu_idmaps);
715
716 /* Sort the ID mapping by Source ID Base*/
717 g_array_sort(iommu_idmaps, rimt_idmap_compare);
718
719 nb_nodes = 2; /* RC, IOMMU */
720 rc_mapping_count = iommu_idmaps->len;
721 /* Number of RIMT Nodes */
722 build_append_int_noprefix(table_data, nb_nodes, 4);
723
724 /* Offset to Array of RIMT Nodes */
725 build_append_int_noprefix(table_data, RIMT_NODE_OFFSET, 4);
726 build_append_int_noprefix(table_data, 0, 4); /* Reserved */
727
728 iommu_offset = table_data->len - table.table_offset;
729 /* IOMMU Device Structure */
730 build_append_int_noprefix(table_data, 0, 1); /* Type - IOMMU*/
731 build_append_int_noprefix(table_data, 1, 1); /* Revision */
732 node_size = IOMMU_ENTRY_SIZE;
733 build_append_int_noprefix(table_data, node_size, 2); /* Length */
734 build_append_int_noprefix(table_data, 0, 2); /* Reserved */
735 build_append_int_noprefix(table_data, id++, 2); /* ID */
736 if (virt_is_iommu_sys_enabled(s)) {
737 /* Hardware ID */
738 build_append_int_noprefix(table_data, 'R', 1);
739 build_append_int_noprefix(table_data, 'S', 1);
740 build_append_int_noprefix(table_data, 'C', 1);
741 build_append_int_noprefix(table_data, 'V', 1);
742 build_append_int_noprefix(table_data, '0', 1);
743 build_append_int_noprefix(table_data, '0', 1);
744 build_append_int_noprefix(table_data, '0', 1);
745 build_append_int_noprefix(table_data, '4', 1);
746 /* Base Address */
747 build_append_int_noprefix(table_data,
748 s->memmap[VIRT_IOMMU_SYS].base, 8);
749 build_append_int_noprefix(table_data, 0, 4); /* Flags */
750 } else {
751 /* Hardware ID */
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, '1', 1);
755 build_append_int_noprefix(table_data, '0', 1);
756 build_append_int_noprefix(table_data, '0', 1);
757 build_append_int_noprefix(table_data, '0', 1);
758 build_append_int_noprefix(table_data, '1', 1);
759 build_append_int_noprefix(table_data, '4', 1);
760
761 build_append_int_noprefix(table_data, 0, 8); /* Base Address */
762 build_append_int_noprefix(table_data, 1, 4); /* Flags */
763 }
764
765 build_append_int_noprefix(table_data, 0, 4); /* Proximity Domain */
766 build_append_int_noprefix(table_data, 0, 2); /* PCI Segment number */
767 /* PCIe B/D/F */
768 if (virt_is_iommu_sys_enabled(s)) {
769 build_append_int_noprefix(table_data, 0, 2);
770 } else {
771 build_append_int_noprefix(table_data, s->pci_iommu_bdf, 2);
772 }
773 /* Number of interrupt wires */
774 build_append_int_noprefix(table_data, 0, 2);
775 /* Interrupt wire array offset */
776 build_append_int_noprefix(table_data, RISCV_INTERRUPT_WIRE_OFFSSET, 2);
777
778 /* PCIe Root Complex Node */
779 build_append_int_noprefix(table_data, 1, 1); /* Type */
780 build_append_int_noprefix(table_data, 1, 1); /* Revision */
781 node_size = ROOT_COMPLEX_ENTRY_SIZE +
782 ID_MAPPING_ENTRY_SIZE * rc_mapping_count;
783 build_append_int_noprefix(table_data, node_size, 2); /* Length */
784 build_append_int_noprefix(table_data, 0, 2); /* Reserved */
785 build_append_int_noprefix(table_data, id++, 2); /* ID */
786 build_append_int_noprefix(table_data, 0, 4); /* Flags */
787 build_append_int_noprefix(table_data, 0, 2); /* Reserved */
788 /* PCI Segment number */
789 build_append_int_noprefix(table_data, 0, 2);
790 /* ID mapping array offset */
791 build_append_int_noprefix(table_data, ROOT_COMPLEX_ENTRY_SIZE, 2);
792 /* Number of ID mappings */
793 build_append_int_noprefix(table_data, rc_mapping_count, 2);
794
795 /* Output Reference */
796 AcpiRimtIdMapping *range;
797
798 /* ID mapping array */
799 for (i = 0; i < iommu_idmaps->len; i++) {
800 range = &g_array_index(iommu_idmaps, AcpiRimtIdMapping, i);
801 if (virt_is_iommu_sys_enabled(s)) {
802 range->source_id_base = 0;
803 } else {
804 range->source_id_base = s->pci_iommu_bdf + 1;
805 }
806 range->num_ids = 0xffff - s->pci_iommu_bdf;
807 build_rimt_id_mapping(table_data, range->source_id_base,
808 range->num_ids, iommu_offset);
809 }
810
811 acpi_table_end(linker, &table);
812 }
813
814 /*
815 * ACPI spec, Revision 6.5+
816 * 5.2.16 System Resource Affinity Table (SRAT)
817 * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/25
818 * https://drive.google.com/file/d/1YTdDx2IPm5IeZjAW932EYU-tUtgS08tX/view
819 */
820 static void
build_srat(GArray * table_data,BIOSLinker * linker,RISCVVirtState * vms)821 build_srat(GArray *table_data, BIOSLinker *linker, RISCVVirtState *vms)
822 {
823 int i;
824 uint64_t mem_base;
825 MachineClass *mc = MACHINE_GET_CLASS(vms);
826 MachineState *ms = MACHINE(vms);
827 const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(ms);
828 AcpiTable table = { .sig = "SRAT", .rev = 3, .oem_id = vms->oem_id,
829 .oem_table_id = vms->oem_table_id };
830
831 acpi_table_begin(&table, table_data);
832 build_append_int_noprefix(table_data, 1, 4); /* Reserved */
833 build_append_int_noprefix(table_data, 0, 8); /* Reserved */
834
835 for (i = 0; i < cpu_list->len; ++i) {
836 uint32_t nodeid = cpu_list->cpus[i].props.node_id;
837 /*
838 * 5.2.16.8 RINTC Affinity Structure
839 */
840 build_append_int_noprefix(table_data, 7, 1); /* Type */
841 build_append_int_noprefix(table_data, 20, 1); /* Length */
842 build_append_int_noprefix(table_data, 0, 2); /* Reserved */
843 build_append_int_noprefix(table_data, nodeid, 4); /* Proximity Domain */
844 build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */
845 /* Flags, Table 5-70 */
846 build_append_int_noprefix(table_data, 1 /* Flags: Enabled */, 4);
847 build_append_int_noprefix(table_data, 0, 4); /* Clock Domain */
848 }
849
850 mem_base = vms->memmap[VIRT_DRAM].base;
851 for (i = 0; i < ms->numa_state->num_nodes; ++i) {
852 if (ms->numa_state->nodes[i].node_mem > 0) {
853 build_srat_memory(table_data, mem_base,
854 ms->numa_state->nodes[i].node_mem, i,
855 MEM_AFFINITY_ENABLED);
856 mem_base += ms->numa_state->nodes[i].node_mem;
857 }
858 }
859
860 acpi_table_end(linker, &table);
861 }
862
virt_acpi_build(RISCVVirtState * s,AcpiBuildTables * tables)863 static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables)
864 {
865 GArray *table_offsets;
866 unsigned dsdt, xsdt;
867 GArray *tables_blob = tables->table_data;
868 MachineState *ms = MACHINE(s);
869
870 table_offsets = g_array_new(false, true,
871 sizeof(uint32_t));
872
873 bios_linker_loader_alloc(tables->linker,
874 ACPI_BUILD_TABLE_FILE, tables_blob,
875 64, false);
876
877 /* DSDT is pointed to by FADT */
878 dsdt = tables_blob->len;
879 build_dsdt(tables_blob, tables->linker, s);
880
881 /* FADT and others pointed to by XSDT */
882 acpi_add_table(table_offsets, tables_blob);
883 build_fadt_rev6(tables_blob, tables->linker, s, dsdt);
884
885 acpi_add_table(table_offsets, tables_blob);
886 build_madt(tables_blob, tables->linker, s);
887
888 acpi_add_table(table_offsets, tables_blob);
889 build_rhct(tables_blob, tables->linker, s);
890
891 if (virt_is_iommu_sys_enabled(s) || s->pci_iommu_bdf) {
892 acpi_add_table(table_offsets, tables_blob);
893 build_rimt(tables_blob, tables->linker, s);
894 }
895
896 acpi_add_table(table_offsets, tables_blob);
897 spcr_setup(tables_blob, tables->linker, s);
898
899 acpi_add_table(table_offsets, tables_blob);
900 {
901 AcpiMcfgInfo mcfg = {
902 .base = s->memmap[VIRT_PCIE_ECAM].base,
903 .size = s->memmap[VIRT_PCIE_ECAM].size,
904 };
905 build_mcfg(tables_blob, tables->linker, &mcfg, s->oem_id,
906 s->oem_table_id);
907 }
908
909 if (ms->numa_state->num_nodes > 0) {
910 acpi_add_table(table_offsets, tables_blob);
911 build_srat(tables_blob, tables->linker, s);
912 if (ms->numa_state->have_numa_distance) {
913 acpi_add_table(table_offsets, tables_blob);
914 build_slit(tables_blob, tables->linker, ms, s->oem_id,
915 s->oem_table_id);
916 }
917 }
918
919 /* XSDT is pointed to by RSDP */
920 xsdt = tables_blob->len;
921 build_xsdt(tables_blob, tables->linker, table_offsets, s->oem_id,
922 s->oem_table_id);
923
924 /* RSDP is in FSEG memory, so allocate it separately */
925 {
926 AcpiRsdpData rsdp_data = {
927 .revision = 2,
928 .oem_id = s->oem_id,
929 .xsdt_tbl_offset = &xsdt,
930 .rsdt_tbl_offset = NULL,
931 };
932 build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
933 }
934
935 /*
936 * The align size is 128, warn if 64k is not enough therefore
937 * the align size could be resized.
938 */
939 if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
940 warn_report("ACPI table size %u exceeds %d bytes,"
941 " migration may not work",
942 tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
943 error_printf("Try removing some objects.");
944 }
945
946 acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
947
948 /* Clean up memory that's no longer used */
949 g_array_free(table_offsets, true);
950 }
951
acpi_ram_update(MemoryRegion * mr,GArray * data)952 static void acpi_ram_update(MemoryRegion *mr, GArray *data)
953 {
954 uint32_t size = acpi_data_len(data);
955
956 /*
957 * Make sure RAM size is correct - in case it got changed
958 * e.g. by migration
959 */
960 memory_region_ram_resize(mr, size, &error_abort);
961
962 memcpy(memory_region_get_ram_ptr(mr), data->data, size);
963 memory_region_set_dirty(mr, 0, size);
964 }
965
virt_acpi_build_update(void * build_opaque)966 static void virt_acpi_build_update(void *build_opaque)
967 {
968 AcpiBuildState *build_state = build_opaque;
969 AcpiBuildTables tables;
970
971 /* No state to update or already patched? Nothing to do. */
972 if (!build_state || build_state->patched) {
973 return;
974 }
975
976 build_state->patched = true;
977
978 acpi_build_tables_init(&tables);
979
980 virt_acpi_build(RISCV_VIRT_MACHINE(qdev_get_machine()), &tables);
981
982 acpi_ram_update(build_state->table_mr, tables.table_data);
983 acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
984 acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
985
986 acpi_build_tables_cleanup(&tables, true);
987 }
988
virt_acpi_build_reset(void * build_opaque)989 static void virt_acpi_build_reset(void *build_opaque)
990 {
991 AcpiBuildState *build_state = build_opaque;
992 build_state->patched = false;
993 }
994
995 static const VMStateDescription vmstate_virt_acpi_build = {
996 .name = "virt_acpi_build",
997 .version_id = 1,
998 .minimum_version_id = 1,
999 .fields = (const VMStateField[]) {
1000 VMSTATE_BOOL(patched, AcpiBuildState),
1001 VMSTATE_END_OF_LIST()
1002 },
1003 };
1004
virt_acpi_setup(RISCVVirtState * s)1005 void virt_acpi_setup(RISCVVirtState *s)
1006 {
1007 AcpiBuildTables tables;
1008 AcpiBuildState *build_state;
1009
1010 build_state = g_malloc0(sizeof *build_state);
1011
1012 acpi_build_tables_init(&tables);
1013 virt_acpi_build(s, &tables);
1014
1015 /* Now expose it all to Guest */
1016 build_state->table_mr = acpi_add_rom_blob(virt_acpi_build_update,
1017 build_state, tables.table_data,
1018 ACPI_BUILD_TABLE_FILE);
1019 assert(build_state->table_mr != NULL);
1020
1021 build_state->linker_mr = acpi_add_rom_blob(virt_acpi_build_update,
1022 build_state,
1023 tables.linker->cmd_blob,
1024 ACPI_BUILD_LOADER_FILE);
1025
1026 build_state->rsdp_mr = acpi_add_rom_blob(virt_acpi_build_update,
1027 build_state, tables.rsdp,
1028 ACPI_BUILD_RSDP_FILE);
1029
1030 qemu_register_reset(virt_acpi_build_reset, build_state);
1031 virt_acpi_build_reset(build_state);
1032 vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state);
1033
1034 /*
1035 * Clean up tables but don't free the memory: we track it
1036 * in build_state.
1037 */
1038 acpi_build_tables_cleanup(&tables, false);
1039 }
1040