xref: /qemu/hw/riscv/virt-acpi-build.c (revision 73f81da0a3628180409a0ae90ece19534bcdf09b)
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 
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 
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 
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 
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
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  */
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
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  */
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     uint8_t satp_mode_max;
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 (cpu->cfg.satp_mode.supported != 0) {
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 (cpu->cfg.satp_mode.supported != 0) {
371         satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
372         mmu_offset = table_data->len - table.table_offset;
373         build_append_int_noprefix(table_data, 2, 2);    /* Type */
374         build_append_int_noprefix(table_data, 8, 2);    /* Length */
375         build_append_int_noprefix(table_data, 0x1, 2);  /* Revision */
376         build_append_int_noprefix(table_data, 0, 1);    /* Reserved */
377         /* MMU Type */
378         if (satp_mode_max == VM_1_10_SV57) {
379             build_append_int_noprefix(table_data, 2, 1);    /* Sv57 */
380         } else if (satp_mode_max == VM_1_10_SV48) {
381             build_append_int_noprefix(table_data, 1, 1);    /* Sv48 */
382         } else if (satp_mode_max == VM_1_10_SV39) {
383             build_append_int_noprefix(table_data, 0, 1);    /* Sv39 */
384         } else {
385             assert(1);
386         }
387     }
388 
389     /* Hart Info Node */
390     for (int i = 0; i < arch_ids->len; i++) {
391         len = 16;
392         int num_offsets = 1;
393         build_append_int_noprefix(table_data, 0xFFFF, 2);  /* Type */
394 
395         /* Length */
396         if (cmo_offset) {
397             len += 4;
398             num_offsets++;
399         }
400 
401         if (mmu_offset) {
402             len += 4;
403             num_offsets++;
404         }
405 
406         build_append_int_noprefix(table_data, len, 2);
407         build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
408         /* Number of offsets */
409         build_append_int_noprefix(table_data, num_offsets, 2);
410         build_append_int_noprefix(table_data, i, 4);   /* ACPI Processor UID */
411         /* Offsets */
412         build_append_int_noprefix(table_data, isa_offset, 4);
413         if (cmo_offset) {
414             build_append_int_noprefix(table_data, cmo_offset, 4);
415         }
416 
417         if (mmu_offset) {
418             build_append_int_noprefix(table_data, mmu_offset, 4);
419         }
420     }
421 
422     acpi_table_end(linker, &table);
423 }
424 
425 /* FADT */
426 static void build_fadt_rev6(GArray *table_data,
427                             BIOSLinker *linker,
428                             RISCVVirtState *s,
429                             unsigned dsdt_tbl_offset)
430 {
431     AcpiFadtData fadt = {
432         .rev = 6,
433         .minor_ver = 5,
434         .flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI,
435         .xdsdt_tbl_offset = &dsdt_tbl_offset,
436     };
437 
438     build_fadt(table_data, linker, &fadt, s->oem_id, s->oem_table_id);
439 }
440 
441 /* DSDT */
442 static void build_dsdt(GArray *table_data,
443                        BIOSLinker *linker,
444                        RISCVVirtState *s)
445 {
446     Aml *scope, *dsdt;
447     MachineState *ms = MACHINE(s);
448     uint8_t socket_count;
449     const MemMapEntry *memmap = s->memmap;
450     AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = s->oem_id,
451                         .oem_table_id = s->oem_table_id };
452 
453 
454     acpi_table_begin(&table, table_data);
455     dsdt = init_aml_allocator();
456 
457     /*
458      * When booting the VM with UEFI, UEFI takes ownership of the RTC hardware.
459      * While UEFI can use libfdt to disable the RTC device node in the DTB that
460      * it passes to the OS, it cannot modify AML. Therefore, we won't generate
461      * the RTC ACPI device at all when using UEFI.
462      */
463     scope = aml_scope("\\_SB");
464     acpi_dsdt_add_cpus(scope, s);
465 
466     fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]);
467 
468     socket_count = riscv_socket_count(ms);
469 
470     if (s->aia_type == VIRT_AIA_TYPE_NONE) {
471         acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_PLIC].base,
472                                  memmap[VIRT_PLIC].size, "RSCV0001");
473     } else {
474         acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_APLIC_S].base,
475                                  memmap[VIRT_APLIC_S].size, "RSCV0002");
476     }
477 
478     acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ);
479     if (virt_is_iommu_sys_enabled(s)) {
480         acpi_dsdt_add_iommu_sys(scope, &memmap[VIRT_IOMMU_SYS], IOMMU_SYS_IRQ);
481     }
482 
483     if (socket_count == 1) {
484         virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
485                              memmap[VIRT_VIRTIO].size,
486                              VIRTIO_IRQ, 0, VIRTIO_COUNT);
487         acpi_dsdt_add_gpex_host(scope, PCIE_IRQ);
488     } else if (socket_count == 2) {
489         virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
490                              memmap[VIRT_VIRTIO].size,
491                              VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0,
492                              VIRTIO_COUNT);
493         acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES);
494     } else {
495         virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
496                              memmap[VIRT_VIRTIO].size,
497                              VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0,
498                              VIRTIO_COUNT);
499         acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES * 2);
500     }
501 
502     aml_append(dsdt, scope);
503 
504     /* copy AML table into ACPI tables blob and patch header there */
505     g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
506 
507     acpi_table_end(linker, &table);
508     free_aml_allocator();
509 }
510 
511 /*
512  * ACPI spec, Revision 6.5+
513  * 5.2.12 Multiple APIC Description Table (MADT)
514  * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/15
515  *      https://drive.google.com/file/d/1R6k4MshhN3WTT-hwqAquu5nX6xSEqK2l/view
516  *      https://drive.google.com/file/d/1oMGPyOD58JaPgMl1pKasT-VKsIKia7zR/view
517  */
518 static void build_madt(GArray *table_data,
519                        BIOSLinker *linker,
520                        RISCVVirtState *s)
521 {
522     MachineClass *mc = MACHINE_GET_CLASS(s);
523     MachineState *ms = MACHINE(s);
524     const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
525     uint8_t  group_index_bits = imsic_num_bits(riscv_socket_count(ms));
526     uint8_t  guest_index_bits = imsic_num_bits(s->aia_guests + 1);
527     uint16_t imsic_max_hart_per_socket = 0;
528     uint8_t  hart_index_bits;
529     uint64_t aplic_addr;
530     uint32_t gsi_base;
531     uint8_t  socket;
532 
533     for (socket = 0; socket < riscv_socket_count(ms); socket++) {
534         if (imsic_max_hart_per_socket < s->soc[socket].num_harts) {
535             imsic_max_hart_per_socket = s->soc[socket].num_harts;
536         }
537     }
538 
539     hart_index_bits = imsic_num_bits(imsic_max_hart_per_socket);
540 
541     AcpiTable table = { .sig = "APIC", .rev = 6, .oem_id = s->oem_id,
542                         .oem_table_id = s->oem_table_id };
543 
544     acpi_table_begin(&table, table_data);
545     /* Local Interrupt Controller Address */
546     build_append_int_noprefix(table_data, 0, 4);
547     build_append_int_noprefix(table_data, 0, 4);   /* MADT Flags */
548 
549     /* RISC-V Local INTC structures per HART */
550     for (int i = 0; i < arch_ids->len; i++) {
551         riscv_acpi_madt_add_rintc(i, arch_ids, table_data, s);
552     }
553 
554     /* IMSIC */
555     if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
556         /* IMSIC */
557         build_append_int_noprefix(table_data, 0x19, 1);     /* Type */
558         build_append_int_noprefix(table_data, 16, 1);       /* Length */
559         build_append_int_noprefix(table_data, 1, 1);        /* Version */
560         build_append_int_noprefix(table_data, 0, 1);        /* Reserved */
561         build_append_int_noprefix(table_data, 0, 4);        /* Flags */
562         /* Number of supervisor mode Interrupt Identities */
563         build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
564         /* Number of guest mode Interrupt Identities */
565         build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
566         /* Guest Index Bits */
567         build_append_int_noprefix(table_data, guest_index_bits, 1);
568         /* Hart Index Bits */
569         build_append_int_noprefix(table_data, hart_index_bits, 1);
570         /* Group Index Bits */
571         build_append_int_noprefix(table_data, group_index_bits, 1);
572         /* Group Index Shift */
573         build_append_int_noprefix(table_data, IMSIC_MMIO_GROUP_MIN_SHIFT, 1);
574     }
575 
576     if (s->aia_type != VIRT_AIA_TYPE_NONE) {
577         /* APLICs */
578         for (socket = 0; socket < riscv_socket_count(ms); socket++) {
579             aplic_addr = s->memmap[VIRT_APLIC_S].base +
580                              s->memmap[VIRT_APLIC_S].size * socket;
581             gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
582             build_append_int_noprefix(table_data, 0x1A, 1);    /* Type */
583             build_append_int_noprefix(table_data, 36, 1);      /* Length */
584             build_append_int_noprefix(table_data, 1, 1);       /* Version */
585             build_append_int_noprefix(table_data, socket, 1);  /* APLIC ID */
586             build_append_int_noprefix(table_data, 0, 4);       /* Flags */
587             build_append_int_noprefix(table_data, 0, 8);       /* Hardware ID */
588             /* Number of IDCs */
589             if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
590                 build_append_int_noprefix(table_data,
591                                           s->soc[socket].num_harts,
592                                           2);
593             } else {
594                 build_append_int_noprefix(table_data, 0, 2);
595             }
596             /* Total External Interrupt Sources Supported */
597             build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_SOURCES, 2);
598             /* Global System Interrupt Base */
599             build_append_int_noprefix(table_data, gsi_base, 4);
600             /* APLIC Address */
601             build_append_int_noprefix(table_data, aplic_addr, 8);
602             /* APLIC size */
603             build_append_int_noprefix(table_data,
604                                       s->memmap[VIRT_APLIC_S].size, 4);
605         }
606     } else {
607         /* PLICs */
608         for (socket = 0; socket < riscv_socket_count(ms); socket++) {
609             aplic_addr = s->memmap[VIRT_PLIC].base +
610                          s->memmap[VIRT_PLIC].size * socket;
611             gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
612             build_append_int_noprefix(table_data, 0x1B, 1);   /* Type */
613             build_append_int_noprefix(table_data, 36, 1);     /* Length */
614             build_append_int_noprefix(table_data, 1, 1);      /* Version */
615             build_append_int_noprefix(table_data, socket, 1); /* PLIC ID */
616             build_append_int_noprefix(table_data, 0, 8);      /* Hardware ID */
617             /* Total External Interrupt Sources Supported */
618             build_append_int_noprefix(table_data,
619                                       VIRT_IRQCHIP_NUM_SOURCES - 1, 2);
620             build_append_int_noprefix(table_data, 0, 2);     /* Max Priority */
621             build_append_int_noprefix(table_data, 0, 4);     /* Flags */
622             /* PLIC Size */
623             build_append_int_noprefix(table_data, s->memmap[VIRT_PLIC].size, 4);
624             /* PLIC Address */
625             build_append_int_noprefix(table_data, aplic_addr, 8);
626             /* Global System Interrupt Vector Base */
627             build_append_int_noprefix(table_data, gsi_base, 4);
628         }
629     }
630 
631     acpi_table_end(linker, &table);
632 }
633 
634 #define ID_MAPPING_ENTRY_SIZE        20
635 #define IOMMU_ENTRY_SIZE             40
636 #define RISCV_INTERRUPT_WIRE_OFFSSET 40
637 #define ROOT_COMPLEX_ENTRY_SIZE      20
638 #define RIMT_NODE_OFFSET             48
639 
640 /*
641  * ID Mapping Structure
642  */
643 static void build_rimt_id_mapping(GArray *table_data, uint32_t source_id_base,
644                                   uint32_t num_ids, uint32_t dest_id_base)
645 {
646     /* Source ID Base */
647     build_append_int_noprefix(table_data, source_id_base, 4);
648     /* Number of IDs */
649     build_append_int_noprefix(table_data, num_ids, 4);
650     /* Destination Device ID Base */
651     build_append_int_noprefix(table_data, source_id_base, 4);
652     /* Destination IOMMU Offset */
653     build_append_int_noprefix(table_data, dest_id_base, 4);
654     /* Flags */
655     build_append_int_noprefix(table_data, 0, 4);
656 }
657 
658 struct AcpiRimtIdMapping {
659     uint32_t source_id_base;
660     uint32_t num_ids;
661 };
662 typedef struct AcpiRimtIdMapping AcpiRimtIdMapping;
663 
664 /* Build the rimt ID mapping to IOMMU for a given PCI host bridge */
665 static int rimt_host_bridges(Object *obj, void *opaque)
666 {
667     GArray *idmap_blob = opaque;
668 
669     if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
670         PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
671 
672         if (bus && !pci_bus_bypass_iommu(bus)) {
673             int min_bus, max_bus;
674 
675             pci_bus_range(bus, &min_bus, &max_bus);
676 
677             AcpiRimtIdMapping idmap = {
678                 .source_id_base = min_bus << 8,
679                 .num_ids = (max_bus - min_bus + 1) << 8,
680             };
681             g_array_append_val(idmap_blob, idmap);
682         }
683     }
684 
685     return 0;
686 }
687 
688 static int rimt_idmap_compare(gconstpointer a, gconstpointer b)
689 {
690     AcpiRimtIdMapping *idmap_a = (AcpiRimtIdMapping *)a;
691     AcpiRimtIdMapping *idmap_b = (AcpiRimtIdMapping *)b;
692 
693     return idmap_a->source_id_base - idmap_b->source_id_base;
694 }
695 
696 /*
697  * RISC-V IO Mapping Table (RIMT)
698  * https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf
699  */
700 static void build_rimt(GArray *table_data, BIOSLinker *linker,
701                        RISCVVirtState *s)
702 {
703     int i, nb_nodes, rc_mapping_count;
704     size_t node_size, iommu_offset = 0;
705     uint32_t id = 0;
706     g_autoptr(GArray) iommu_idmaps = g_array_new(false, true,
707                                                  sizeof(AcpiRimtIdMapping));
708 
709     AcpiTable table = { .sig = "RIMT", .rev = 1, .oem_id = s->oem_id,
710                         .oem_table_id = s->oem_table_id };
711 
712     acpi_table_begin(&table, table_data);
713 
714     object_child_foreach_recursive(object_get_root(),
715                                    rimt_host_bridges, iommu_idmaps);
716 
717     /* Sort the ID mapping  by Source ID Base*/
718     g_array_sort(iommu_idmaps, rimt_idmap_compare);
719 
720     nb_nodes = 2; /* RC, IOMMU */
721     rc_mapping_count = iommu_idmaps->len;
722     /* Number of RIMT Nodes */
723     build_append_int_noprefix(table_data, nb_nodes, 4);
724 
725     /* Offset to Array of RIMT Nodes */
726     build_append_int_noprefix(table_data, RIMT_NODE_OFFSET, 4);
727     build_append_int_noprefix(table_data, 0, 4); /* Reserved */
728 
729     iommu_offset = table_data->len - table.table_offset;
730     /*  IOMMU Device Structure */
731     build_append_int_noprefix(table_data, 0, 1);         /* Type - IOMMU*/
732     build_append_int_noprefix(table_data, 1, 1);         /* Revision */
733     node_size =  IOMMU_ENTRY_SIZE;
734     build_append_int_noprefix(table_data, node_size, 2); /* Length */
735     build_append_int_noprefix(table_data, 0, 2);         /* Reserved */
736     build_append_int_noprefix(table_data, id++, 2);      /* ID */
737     if (virt_is_iommu_sys_enabled(s)) {
738         /* Hardware ID */
739         build_append_int_noprefix(table_data, 'R', 1);
740         build_append_int_noprefix(table_data, 'S', 1);
741         build_append_int_noprefix(table_data, 'C', 1);
742         build_append_int_noprefix(table_data, 'V', 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, '0', 1);
746         build_append_int_noprefix(table_data, '4', 1);
747         /* Base Address */
748         build_append_int_noprefix(table_data,
749                                   s->memmap[VIRT_IOMMU_SYS].base, 8);
750         build_append_int_noprefix(table_data, 0, 4);   /* Flags */
751     } else {
752         /* Hardware ID */
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, '0', 1);
757         build_append_int_noprefix(table_data, '0', 1);
758         build_append_int_noprefix(table_data, '0', 1);
759         build_append_int_noprefix(table_data, '1', 1);
760         build_append_int_noprefix(table_data, '4', 1);
761 
762         build_append_int_noprefix(table_data, 0, 8);   /* Base Address */
763         build_append_int_noprefix(table_data, 1, 4);   /* Flags */
764     }
765 
766     build_append_int_noprefix(table_data, 0, 4);       /* Proximity Domain */
767     build_append_int_noprefix(table_data, 0, 2);       /* PCI Segment number */
768     /* PCIe B/D/F */
769     if (virt_is_iommu_sys_enabled(s)) {
770         build_append_int_noprefix(table_data, 0, 2);
771     } else {
772         build_append_int_noprefix(table_data, s->pci_iommu_bdf, 2);
773     }
774     /* Number of interrupt wires */
775     build_append_int_noprefix(table_data, 0, 2);
776     /* Interrupt wire array offset */
777     build_append_int_noprefix(table_data, RISCV_INTERRUPT_WIRE_OFFSSET, 2);
778 
779     /*  PCIe Root Complex Node */
780     build_append_int_noprefix(table_data, 1, 1);           /* Type */
781     build_append_int_noprefix(table_data, 1, 1);           /* Revision */
782     node_size =  ROOT_COMPLEX_ENTRY_SIZE +
783                  ID_MAPPING_ENTRY_SIZE * rc_mapping_count;
784     build_append_int_noprefix(table_data, node_size, 2);   /* Length */
785     build_append_int_noprefix(table_data, 0, 2);           /* Reserved */
786     build_append_int_noprefix(table_data, id++, 2);        /* ID */
787     build_append_int_noprefix(table_data, 0, 4);           /* Flags */
788     build_append_int_noprefix(table_data, 0, 2);           /* Reserved */
789     /* PCI Segment number */
790     build_append_int_noprefix(table_data, 0, 2);
791     /* ID mapping array offset */
792     build_append_int_noprefix(table_data, ROOT_COMPLEX_ENTRY_SIZE, 2);
793     /* Number of ID mappings */
794     build_append_int_noprefix(table_data, rc_mapping_count, 2);
795 
796     /* Output Reference */
797     AcpiRimtIdMapping *range;
798 
799     /* ID mapping array */
800     for (i = 0; i < iommu_idmaps->len; i++) {
801         range = &g_array_index(iommu_idmaps, AcpiRimtIdMapping, i);
802         if (virt_is_iommu_sys_enabled(s)) {
803             range->source_id_base = 0;
804         } else {
805             range->source_id_base = s->pci_iommu_bdf + 1;
806         }
807         range->num_ids = 0xffff - s->pci_iommu_bdf;
808         build_rimt_id_mapping(table_data, range->source_id_base,
809                               range->num_ids, iommu_offset);
810     }
811 
812     acpi_table_end(linker, &table);
813 }
814 
815 /*
816  * ACPI spec, Revision 6.5+
817  * 5.2.16 System Resource Affinity Table (SRAT)
818  * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/25
819  *      https://drive.google.com/file/d/1YTdDx2IPm5IeZjAW932EYU-tUtgS08tX/view
820  */
821 static void
822 build_srat(GArray *table_data, BIOSLinker *linker, RISCVVirtState *vms)
823 {
824     int i;
825     uint64_t mem_base;
826     MachineClass *mc = MACHINE_GET_CLASS(vms);
827     MachineState *ms = MACHINE(vms);
828     const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(ms);
829     AcpiTable table = { .sig = "SRAT", .rev = 3, .oem_id = vms->oem_id,
830                         .oem_table_id = vms->oem_table_id };
831 
832     acpi_table_begin(&table, table_data);
833     build_append_int_noprefix(table_data, 1, 4); /* Reserved */
834     build_append_int_noprefix(table_data, 0, 8); /* Reserved */
835 
836     for (i = 0; i < cpu_list->len; ++i) {
837         uint32_t nodeid = cpu_list->cpus[i].props.node_id;
838         /*
839          * 5.2.16.8 RINTC Affinity Structure
840          */
841         build_append_int_noprefix(table_data, 7, 1);      /* Type */
842         build_append_int_noprefix(table_data, 20, 1);     /* Length */
843         build_append_int_noprefix(table_data, 0, 2);        /* Reserved */
844         build_append_int_noprefix(table_data, nodeid, 4); /* Proximity Domain */
845         build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */
846         /* Flags, Table 5-70 */
847         build_append_int_noprefix(table_data, 1 /* Flags: Enabled */, 4);
848         build_append_int_noprefix(table_data, 0, 4); /* Clock Domain */
849     }
850 
851     mem_base = vms->memmap[VIRT_DRAM].base;
852     for (i = 0; i < ms->numa_state->num_nodes; ++i) {
853         if (ms->numa_state->nodes[i].node_mem > 0) {
854             build_srat_memory(table_data, mem_base,
855                               ms->numa_state->nodes[i].node_mem, i,
856                               MEM_AFFINITY_ENABLED);
857             mem_base += ms->numa_state->nodes[i].node_mem;
858         }
859     }
860 
861     acpi_table_end(linker, &table);
862 }
863 
864 static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables)
865 {
866     GArray *table_offsets;
867     unsigned dsdt, xsdt;
868     GArray *tables_blob = tables->table_data;
869     MachineState *ms = MACHINE(s);
870 
871     table_offsets = g_array_new(false, true,
872                                 sizeof(uint32_t));
873 
874     bios_linker_loader_alloc(tables->linker,
875                              ACPI_BUILD_TABLE_FILE, tables_blob,
876                              64, false);
877 
878     /* DSDT is pointed to by FADT */
879     dsdt = tables_blob->len;
880     build_dsdt(tables_blob, tables->linker, s);
881 
882     /* FADT and others pointed to by XSDT */
883     acpi_add_table(table_offsets, tables_blob);
884     build_fadt_rev6(tables_blob, tables->linker, s, dsdt);
885 
886     acpi_add_table(table_offsets, tables_blob);
887     build_madt(tables_blob, tables->linker, s);
888 
889     acpi_add_table(table_offsets, tables_blob);
890     build_rhct(tables_blob, tables->linker, s);
891 
892     if (virt_is_iommu_sys_enabled(s) || s->pci_iommu_bdf) {
893         acpi_add_table(table_offsets, tables_blob);
894         build_rimt(tables_blob, tables->linker, s);
895     }
896 
897     acpi_add_table(table_offsets, tables_blob);
898     spcr_setup(tables_blob, tables->linker, s);
899 
900     acpi_add_table(table_offsets, tables_blob);
901     {
902         AcpiMcfgInfo mcfg = {
903            .base = s->memmap[VIRT_PCIE_ECAM].base,
904            .size = s->memmap[VIRT_PCIE_ECAM].size,
905         };
906         build_mcfg(tables_blob, tables->linker, &mcfg, s->oem_id,
907                    s->oem_table_id);
908     }
909 
910     if (ms->numa_state->num_nodes > 0) {
911         acpi_add_table(table_offsets, tables_blob);
912         build_srat(tables_blob, tables->linker, s);
913         if (ms->numa_state->have_numa_distance) {
914             acpi_add_table(table_offsets, tables_blob);
915             build_slit(tables_blob, tables->linker, ms, s->oem_id,
916                        s->oem_table_id);
917         }
918     }
919 
920     /* XSDT is pointed to by RSDP */
921     xsdt = tables_blob->len;
922     build_xsdt(tables_blob, tables->linker, table_offsets, s->oem_id,
923                 s->oem_table_id);
924 
925     /* RSDP is in FSEG memory, so allocate it separately */
926     {
927         AcpiRsdpData rsdp_data = {
928             .revision = 2,
929             .oem_id = s->oem_id,
930             .xsdt_tbl_offset = &xsdt,
931             .rsdt_tbl_offset = NULL,
932         };
933         build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
934     }
935 
936     /*
937      * The align size is 128, warn if 64k is not enough therefore
938      * the align size could be resized.
939      */
940     if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
941         warn_report("ACPI table size %u exceeds %d bytes,"
942                     " migration may not work",
943                     tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
944         error_printf("Try removing some objects.");
945     }
946 
947     acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
948 
949     /* Clean up memory that's no longer used */
950     g_array_free(table_offsets, true);
951 }
952 
953 static void acpi_ram_update(MemoryRegion *mr, GArray *data)
954 {
955     uint32_t size = acpi_data_len(data);
956 
957     /*
958      * Make sure RAM size is correct - in case it got changed
959      * e.g. by migration
960      */
961     memory_region_ram_resize(mr, size, &error_abort);
962 
963     memcpy(memory_region_get_ram_ptr(mr), data->data, size);
964     memory_region_set_dirty(mr, 0, size);
965 }
966 
967 static void virt_acpi_build_update(void *build_opaque)
968 {
969     AcpiBuildState *build_state = build_opaque;
970     AcpiBuildTables tables;
971 
972     /* No state to update or already patched? Nothing to do. */
973     if (!build_state || build_state->patched) {
974         return;
975     }
976 
977     build_state->patched = true;
978 
979     acpi_build_tables_init(&tables);
980 
981     virt_acpi_build(RISCV_VIRT_MACHINE(qdev_get_machine()), &tables);
982 
983     acpi_ram_update(build_state->table_mr, tables.table_data);
984     acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
985     acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
986 
987     acpi_build_tables_cleanup(&tables, true);
988 }
989 
990 static void virt_acpi_build_reset(void *build_opaque)
991 {
992     AcpiBuildState *build_state = build_opaque;
993     build_state->patched = false;
994 }
995 
996 static const VMStateDescription vmstate_virt_acpi_build = {
997     .name = "virt_acpi_build",
998     .version_id = 1,
999     .minimum_version_id = 1,
1000     .fields = (const VMStateField[]) {
1001         VMSTATE_BOOL(patched, AcpiBuildState),
1002         VMSTATE_END_OF_LIST()
1003     },
1004 };
1005 
1006 void virt_acpi_setup(RISCVVirtState *s)
1007 {
1008     AcpiBuildTables tables;
1009     AcpiBuildState *build_state;
1010 
1011     build_state = g_malloc0(sizeof *build_state);
1012 
1013     acpi_build_tables_init(&tables);
1014     virt_acpi_build(s, &tables);
1015 
1016     /* Now expose it all to Guest */
1017     build_state->table_mr = acpi_add_rom_blob(virt_acpi_build_update,
1018                                               build_state, tables.table_data,
1019                                               ACPI_BUILD_TABLE_FILE);
1020     assert(build_state->table_mr != NULL);
1021 
1022     build_state->linker_mr = acpi_add_rom_blob(virt_acpi_build_update,
1023                                                build_state,
1024                                                tables.linker->cmd_blob,
1025                                                ACPI_BUILD_LOADER_FILE);
1026 
1027     build_state->rsdp_mr = acpi_add_rom_blob(virt_acpi_build_update,
1028                                              build_state, tables.rsdp,
1029                                              ACPI_BUILD_RSDP_FILE);
1030 
1031     qemu_register_reset(virt_acpi_build_reset, build_state);
1032     virt_acpi_build_reset(build_state);
1033     vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state);
1034 
1035     /*
1036      * Clean up tables but don't free the memory: we track it
1037      * in build_state.
1038      */
1039     acpi_build_tables_cleanup(&tables, false);
1040 }
1041