xref: /openbmc/qemu/hw/riscv/virt-acpi-build.c (revision 5885bcef3d760e84d17eb4113e85f2aea0bd0582)
17da2fb24SSunil V L /*
27da2fb24SSunil V L  * Support for generating ACPI tables and passing them to Guests
37da2fb24SSunil V L  *
47da2fb24SSunil V L  * RISC-V virt ACPI generation
57da2fb24SSunil V L  *
67da2fb24SSunil V L  * Copyright (C) 2008-2010  Kevin O'Connor <kevin@koconnor.net>
77da2fb24SSunil V L  * Copyright (C) 2006 Fabrice Bellard
87da2fb24SSunil V L  * Copyright (C) 2013 Red Hat Inc
97da2fb24SSunil V L  * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD.
107da2fb24SSunil V L  * Copyright (C) 2021-2023 Ventana Micro Systems Inc
117da2fb24SSunil V L  *
127da2fb24SSunil V L  * This program is free software; you can redistribute it and/or modify
137da2fb24SSunil V L  * it under the terms of the GNU General Public License as published by
147da2fb24SSunil V L  * the Free Software Foundation; either version 2 of the License, or
157da2fb24SSunil V L  * (at your option) any later version.
167da2fb24SSunil V L 
177da2fb24SSunil V L  * This program is distributed in the hope that it will be useful,
187da2fb24SSunil V L  * but WITHOUT ANY WARRANTY; without even the implied warranty of
197da2fb24SSunil V L  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
207da2fb24SSunil V L  * GNU General Public License for more details.
217da2fb24SSunil V L 
227da2fb24SSunil V L  * You should have received a copy of the GNU General Public License along
237da2fb24SSunil V L  * with this program; if not, see <http://www.gnu.org/licenses/>.
247da2fb24SSunil V L  */
257da2fb24SSunil V L 
267da2fb24SSunil V L #include "qemu/osdep.h"
277da2fb24SSunil V L #include "hw/acpi/acpi-defs.h"
287da2fb24SSunil V L #include "hw/acpi/acpi.h"
297da2fb24SSunil V L #include "hw/acpi/aml-build.h"
3055ecd83bSSunil V L #include "hw/acpi/pci.h"
317da2fb24SSunil V L #include "hw/acpi/utils.h"
3255ecd83bSSunil V L #include "hw/intc/riscv_aclint.h"
334c7f4f4fSSunil V L #include "hw/nvram/fw_cfg_acpi.h"
3455ecd83bSSunil V L #include "hw/pci-host/gpex.h"
3555ecd83bSSunil V L #include "hw/riscv/virt.h"
3655ecd83bSSunil V L #include "hw/riscv/numa.h"
3755ecd83bSSunil V L #include "hw/virtio/virtio-acpi.h"
3855ecd83bSSunil V L #include "migration/vmstate.h"
397da2fb24SSunil V L #include "qapi/error.h"
40cc37d98bSRichard Henderson #include "qemu/error-report.h"
417da2fb24SSunil V L #include "sysemu/reset.h"
427da2fb24SSunil V L 
437da2fb24SSunil V L #define ACPI_BUILD_TABLE_SIZE             0x20000
440efb12b7SSunil V L #define ACPI_BUILD_INTC_ID(socket, index) ((socket << 24) | (index))
457da2fb24SSunil V L 
467da2fb24SSunil V L typedef struct AcpiBuildState {
477da2fb24SSunil V L     /* Copy of table in RAM (for patching) */
487da2fb24SSunil V L     MemoryRegion *table_mr;
497da2fb24SSunil V L     MemoryRegion *rsdp_mr;
507da2fb24SSunil V L     MemoryRegion *linker_mr;
517da2fb24SSunil V L     /* Is table patched? */
527da2fb24SSunil V L     bool patched;
537da2fb24SSunil V L } AcpiBuildState;
547da2fb24SSunil V L 
acpi_align_size(GArray * blob,unsigned align)557da2fb24SSunil V L static void acpi_align_size(GArray *blob, unsigned align)
567da2fb24SSunil V L {
577da2fb24SSunil V L     /*
587da2fb24SSunil V L      * Align size to multiple of given size. This reduces the chance
597da2fb24SSunil V L      * we need to change size in the future (breaking cross version migration).
607da2fb24SSunil V L      */
617da2fb24SSunil V L     g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
627da2fb24SSunil V L }
637da2fb24SSunil V L 
riscv_acpi_madt_add_rintc(uint32_t uid,const CPUArchIdList * arch_ids,GArray * entry,RISCVVirtState * s)647da2fb24SSunil V L static void riscv_acpi_madt_add_rintc(uint32_t uid,
657da2fb24SSunil V L                                       const CPUArchIdList *arch_ids,
660efb12b7SSunil V L                                       GArray *entry,
670efb12b7SSunil V L                                       RISCVVirtState *s)
687da2fb24SSunil V L {
690efb12b7SSunil V L     uint8_t  guest_index_bits = imsic_num_bits(s->aia_guests + 1);
707da2fb24SSunil V L     uint64_t hart_id = arch_ids->cpus[uid].arch_id;
710efb12b7SSunil V L     uint32_t imsic_size, local_cpu_id, socket_id;
720efb12b7SSunil V L     uint64_t imsic_socket_addr, imsic_addr;
730efb12b7SSunil V L     MachineState *ms = MACHINE(s);
747da2fb24SSunil V L 
750efb12b7SSunil V L     socket_id = arch_ids->cpus[uid].props.node_id;
760efb12b7SSunil V L     local_cpu_id = (arch_ids->cpus[uid].arch_id -
770efb12b7SSunil V L                     riscv_socket_first_hartid(ms, socket_id)) %
780efb12b7SSunil V L                     riscv_socket_hart_count(ms, socket_id);
790efb12b7SSunil V L     imsic_socket_addr = s->memmap[VIRT_IMSIC_S].base +
800efb12b7SSunil V L                         (socket_id * VIRT_IMSIC_GROUP_MAX_SIZE);
810efb12b7SSunil V L     imsic_size = IMSIC_HART_SIZE(guest_index_bits);
820efb12b7SSunil V L     imsic_addr = imsic_socket_addr + local_cpu_id * imsic_size;
837da2fb24SSunil V L     build_append_int_noprefix(entry, 0x18, 1);       /* Type     */
840efb12b7SSunil V L     build_append_int_noprefix(entry, 36, 1);         /* Length   */
857da2fb24SSunil V L     build_append_int_noprefix(entry, 1, 1);          /* Version  */
867da2fb24SSunil V L     build_append_int_noprefix(entry, 0, 1);          /* Reserved */
877da2fb24SSunil V L     build_append_int_noprefix(entry, 0x1, 4);        /* Flags    */
887da2fb24SSunil V L     build_append_int_noprefix(entry, hart_id, 8);    /* Hart ID  */
897da2fb24SSunil V L     build_append_int_noprefix(entry, uid, 4);        /* ACPI Processor UID */
900efb12b7SSunil V L     /* External Interrupt Controller ID */
910efb12b7SSunil V L     if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
920efb12b7SSunil V L         build_append_int_noprefix(entry,
930efb12b7SSunil V L                                   ACPI_BUILD_INTC_ID(
940efb12b7SSunil V L                                       arch_ids->cpus[uid].props.node_id,
950efb12b7SSunil V L                                       local_cpu_id),
960efb12b7SSunil V L                                   4);
97d641da6eSSunil V L     } else if (s->aia_type == VIRT_AIA_TYPE_NONE) {
98d641da6eSSunil V L         build_append_int_noprefix(entry,
99d641da6eSSunil V L                                   ACPI_BUILD_INTC_ID(
100d641da6eSSunil V L                                       arch_ids->cpus[uid].props.node_id,
101d641da6eSSunil V L                                       2 * local_cpu_id + 1),
102d641da6eSSunil V L                                   4);
1030efb12b7SSunil V L     } else {
1040efb12b7SSunil V L         build_append_int_noprefix(entry, 0, 4);
1050efb12b7SSunil V L     }
1060efb12b7SSunil V L 
1070efb12b7SSunil V L     if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
1080efb12b7SSunil V L         /* IMSIC Base address */
1090efb12b7SSunil V L         build_append_int_noprefix(entry, imsic_addr, 8);
1100efb12b7SSunil V L         /* IMSIC Size */
1110efb12b7SSunil V L         build_append_int_noprefix(entry, imsic_size, 4);
1120efb12b7SSunil V L     } else {
1130efb12b7SSunil V L         build_append_int_noprefix(entry, 0, 8);
1140efb12b7SSunil V L         build_append_int_noprefix(entry, 0, 4);
1150efb12b7SSunil V L     }
1167da2fb24SSunil V L }
1177da2fb24SSunil V L 
acpi_dsdt_add_cpus(Aml * scope,RISCVVirtState * s)1187da2fb24SSunil V L static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s)
1197da2fb24SSunil V L {
1207da2fb24SSunil V L     MachineClass *mc = MACHINE_GET_CLASS(s);
1217da2fb24SSunil V L     MachineState *ms = MACHINE(s);
1227da2fb24SSunil V L     const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
1237da2fb24SSunil V L 
1247da2fb24SSunil V L     for (int i = 0; i < arch_ids->len; i++) {
1257da2fb24SSunil V L             Aml *dev;
1267da2fb24SSunil V L             GArray *madt_buf = g_array_new(0, 1, 1);
1277da2fb24SSunil V L 
1287da2fb24SSunil V L             dev = aml_device("C%.03X", i);
1297da2fb24SSunil V L             aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
1307da2fb24SSunil V L             aml_append(dev, aml_name_decl("_UID",
1317da2fb24SSunil V L                        aml_int(arch_ids->cpus[i].arch_id)));
1327da2fb24SSunil V L 
1337da2fb24SSunil V L             /* build _MAT object */
1340efb12b7SSunil V L             riscv_acpi_madt_add_rintc(i, arch_ids, madt_buf, s);
1357da2fb24SSunil V L             aml_append(dev, aml_name_decl("_MAT",
1367da2fb24SSunil V L                                           aml_buffer(madt_buf->len,
1377da2fb24SSunil V L                                           (uint8_t *)madt_buf->data)));
1387da2fb24SSunil V L             g_array_free(madt_buf, true);
1397da2fb24SSunil V L 
1407da2fb24SSunil V L             aml_append(scope, dev);
1417da2fb24SSunil V L     }
1427da2fb24SSunil V L }
1437da2fb24SSunil V L 
acpi_dsdt_add_plic_aplic(Aml * scope,uint8_t socket_count,uint64_t mmio_base,uint64_t mmio_size,const char * hid)144a54dd0cdSSunil V L static void acpi_dsdt_add_plic_aplic(Aml *scope, uint8_t socket_count,
145a54dd0cdSSunil V L                                      uint64_t mmio_base, uint64_t mmio_size,
146a54dd0cdSSunil V L                                      const char *hid)
147a54dd0cdSSunil V L {
148a54dd0cdSSunil V L     uint64_t plic_aplic_addr;
149a54dd0cdSSunil V L     uint32_t gsi_base;
150a54dd0cdSSunil V L     uint8_t  socket;
151a54dd0cdSSunil V L 
152a54dd0cdSSunil V L     for (socket = 0; socket < socket_count; socket++) {
153a54dd0cdSSunil V L         plic_aplic_addr = mmio_base + mmio_size * socket;
154a54dd0cdSSunil V L         gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
155a54dd0cdSSunil V L         Aml *dev = aml_device("IC%.02X", socket);
156a54dd0cdSSunil V L         aml_append(dev, aml_name_decl("_HID", aml_string("%s", hid)));
157a54dd0cdSSunil V L         aml_append(dev, aml_name_decl("_UID", aml_int(socket)));
158a54dd0cdSSunil V L         aml_append(dev, aml_name_decl("_GSB", aml_int(gsi_base)));
159a54dd0cdSSunil V L 
160a54dd0cdSSunil V L         Aml *crs = aml_resource_template();
161a54dd0cdSSunil V L         aml_append(crs, aml_memory32_fixed(plic_aplic_addr, mmio_size,
162a54dd0cdSSunil V L                                            AML_READ_WRITE));
163a54dd0cdSSunil V L         aml_append(dev, aml_name_decl("_CRS", crs));
164a54dd0cdSSunil V L         aml_append(scope, dev);
165a54dd0cdSSunil V L     }
166a54dd0cdSSunil V L }
167a54dd0cdSSunil V L 
16855ecd83bSSunil V L static void
acpi_dsdt_add_uart(Aml * scope,const MemMapEntry * uart_memmap,uint32_t uart_irq)16955ecd83bSSunil V L acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
17055ecd83bSSunil V L                     uint32_t uart_irq)
17155ecd83bSSunil V L {
17255ecd83bSSunil V L     Aml *dev = aml_device("COM0");
173*faacd2e6SSunil V L     aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0003")));
17455ecd83bSSunil V L     aml_append(dev, aml_name_decl("_UID", aml_int(0)));
17555ecd83bSSunil V L 
17655ecd83bSSunil V L     Aml *crs = aml_resource_template();
17755ecd83bSSunil V L     aml_append(crs, aml_memory32_fixed(uart_memmap->base,
17855ecd83bSSunil V L                                          uart_memmap->size, AML_READ_WRITE));
17955ecd83bSSunil V L     aml_append(crs,
18055ecd83bSSunil V L                 aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
18155ecd83bSSunil V L                                AML_EXCLUSIVE, &uart_irq, 1));
18255ecd83bSSunil V L     aml_append(dev, aml_name_decl("_CRS", crs));
18355ecd83bSSunil V L 
18455ecd83bSSunil V L     Aml *pkg = aml_package(2);
18555ecd83bSSunil V L     aml_append(pkg, aml_string("clock-frequency"));
18655ecd83bSSunil V L     aml_append(pkg, aml_int(3686400));
18755ecd83bSSunil V L 
18855ecd83bSSunil V L     Aml *UUID = aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301");
18955ecd83bSSunil V L 
19055ecd83bSSunil V L     Aml *pkg1 = aml_package(1);
19155ecd83bSSunil V L     aml_append(pkg1, pkg);
19255ecd83bSSunil V L 
19355ecd83bSSunil V L     Aml *package = aml_package(2);
19455ecd83bSSunil V L     aml_append(package, UUID);
19555ecd83bSSunil V L     aml_append(package, pkg1);
19655ecd83bSSunil V L 
19755ecd83bSSunil V L     aml_append(dev, aml_name_decl("_DSD", package));
19855ecd83bSSunil V L     aml_append(scope, dev);
19955ecd83bSSunil V L }
20055ecd83bSSunil V L 
2013e6f1e61SSia Jee Heng /*
2023e6f1e61SSia Jee Heng  * Serial Port Console Redirection Table (SPCR)
2033e6f1e61SSia Jee Heng  * Rev: 1.07
2043e6f1e61SSia Jee Heng  */
2053e6f1e61SSia Jee Heng 
2063e6f1e61SSia Jee Heng static void
spcr_setup(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)2073e6f1e61SSia Jee Heng spcr_setup(GArray *table_data, BIOSLinker *linker, RISCVVirtState *s)
2083e6f1e61SSia Jee Heng {
2093e6f1e61SSia Jee Heng     AcpiSpcrData serial = {
2103e6f1e61SSia Jee Heng         .interface_type = 0,       /* 16550 compatible */
2113e6f1e61SSia Jee Heng         .base_addr.id = AML_AS_SYSTEM_MEMORY,
2123e6f1e61SSia Jee Heng         .base_addr.width = 32,
2133e6f1e61SSia Jee Heng         .base_addr.offset = 0,
2143e6f1e61SSia Jee Heng         .base_addr.size = 1,
2153e6f1e61SSia Jee Heng         .base_addr.addr = s->memmap[VIRT_UART0].base,
2163e6f1e61SSia Jee Heng         .interrupt_type = (1 << 4),/* Bit[4] RISC-V PLIC/APLIC */
2173e6f1e61SSia Jee Heng         .pc_interrupt = 0,
2183e6f1e61SSia Jee Heng         .interrupt = UART0_IRQ,
2193e6f1e61SSia Jee Heng         .baud_rate = 7,            /* 15200 */
2203e6f1e61SSia Jee Heng         .parity = 0,
2213e6f1e61SSia Jee Heng         .stop_bits = 1,
2223e6f1e61SSia Jee Heng         .flow_control = 0,
2233e6f1e61SSia Jee Heng         .terminal_type = 3,        /* ANSI */
2243e6f1e61SSia Jee Heng         .language = 0,             /* Language */
2253e6f1e61SSia Jee Heng         .pci_device_id = 0xffff,   /* not a PCI device*/
2263e6f1e61SSia Jee Heng         .pci_vendor_id = 0xffff,   /* not a PCI device*/
2273e6f1e61SSia Jee Heng         .pci_bus = 0,
2283e6f1e61SSia Jee Heng         .pci_device = 0,
2293e6f1e61SSia Jee Heng         .pci_function = 0,
2303e6f1e61SSia Jee Heng         .pci_flags = 0,
2313e6f1e61SSia Jee Heng         .pci_segment = 0,
2323e6f1e61SSia Jee Heng     };
2333e6f1e61SSia Jee Heng 
2343e6f1e61SSia Jee Heng     build_spcr(table_data, linker, &serial, 2, s->oem_id, s->oem_table_id);
2353e6f1e61SSia Jee Heng }
2363e6f1e61SSia Jee Heng 
237ebfd3928SSunil V L /* RHCT Node[N] starts at offset 56 */
238ebfd3928SSunil V L #define RHCT_NODE_ARRAY_OFFSET 56
239ebfd3928SSunil V L 
240ebfd3928SSunil V L /*
241ebfd3928SSunil V L  * ACPI spec, Revision 6.5+
242ebfd3928SSunil V L  * 5.2.36 RISC-V Hart Capabilities Table (RHCT)
243ebfd3928SSunil V L  * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/16
244ebfd3928SSunil V L  *      https://drive.google.com/file/d/1nP3nFiH4jkPMp6COOxP6123DCZKR-tia/view
245e810a517SSunil V L  *      https://drive.google.com/file/d/1sKbOa8m1UZw1JkquZYe3F1zQBN1xXsaf/view
246ebfd3928SSunil V L  */
build_rhct(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)247ebfd3928SSunil V L static void build_rhct(GArray *table_data,
248ebfd3928SSunil V L                        BIOSLinker *linker,
249ebfd3928SSunil V L                        RISCVVirtState *s)
250ebfd3928SSunil V L {
251ebfd3928SSunil V L     MachineClass *mc = MACHINE_GET_CLASS(s);
252ebfd3928SSunil V L     MachineState *ms = MACHINE(s);
253ebfd3928SSunil V L     const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
254ebfd3928SSunil V L     size_t len, aligned_len;
255e810a517SSunil V L     uint32_t isa_offset, num_rhct_nodes, cmo_offset = 0;
256e810a517SSunil V L     RISCVCPU *cpu = &s->soc[0].harts[0];
257a52aea26SSunil V L     uint32_t mmu_offset = 0;
258a52aea26SSunil V L     uint8_t satp_mode_max;
2591a49762cSDaniel Henrique Barboza     g_autofree char *isa = NULL;
260ebfd3928SSunil V L 
261ebfd3928SSunil V L     AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id,
262ebfd3928SSunil V L                         .oem_table_id = s->oem_table_id };
263ebfd3928SSunil V L 
264ebfd3928SSunil V L     acpi_table_begin(&table, table_data);
265ebfd3928SSunil V L 
266ebfd3928SSunil V L     build_append_int_noprefix(table_data, 0x0, 4);   /* Reserved */
267ebfd3928SSunil V L 
268ebfd3928SSunil V L     /* Time Base Frequency */
269ebfd3928SSunil V L     build_append_int_noprefix(table_data,
270ebfd3928SSunil V L                               RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, 8);
271ebfd3928SSunil V L 
272ebfd3928SSunil V L     /* ISA + N hart info */
273ebfd3928SSunil V L     num_rhct_nodes = 1 + ms->smp.cpus;
274e810a517SSunil V L     if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) {
275e810a517SSunil V L         num_rhct_nodes++;
276e810a517SSunil V L     }
277ebfd3928SSunil V L 
278a52aea26SSunil V L     if (cpu->cfg.satp_mode.supported != 0) {
279a52aea26SSunil V L         num_rhct_nodes++;
280a52aea26SSunil V L     }
281a52aea26SSunil V L 
282ebfd3928SSunil V L     /* Number of RHCT nodes*/
283ebfd3928SSunil V L     build_append_int_noprefix(table_data, num_rhct_nodes, 4);
284ebfd3928SSunil V L 
285ebfd3928SSunil V L     /* Offset to the RHCT node array */
286ebfd3928SSunil V L     build_append_int_noprefix(table_data, RHCT_NODE_ARRAY_OFFSET, 4);
287ebfd3928SSunil V L 
288ebfd3928SSunil V L     /* ISA String Node */
289ebfd3928SSunil V L     isa_offset = table_data->len - table.table_offset;
290ebfd3928SSunil V L     build_append_int_noprefix(table_data, 0, 2);   /* Type 0 */
291ebfd3928SSunil V L 
292ebfd3928SSunil V L     isa = riscv_isa_string(cpu);
293ebfd3928SSunil V L     len = 8 + strlen(isa) + 1;
294ebfd3928SSunil V L     aligned_len = (len % 2) ? (len + 1) : len;
295ebfd3928SSunil V L 
296ebfd3928SSunil V L     build_append_int_noprefix(table_data, aligned_len, 2);   /* Length */
297ebfd3928SSunil V L     build_append_int_noprefix(table_data, 0x1, 2);           /* Revision */
298ebfd3928SSunil V L 
299ebfd3928SSunil V L     /* ISA string length including NUL */
300ebfd3928SSunil V L     build_append_int_noprefix(table_data, strlen(isa) + 1, 2);
301ebfd3928SSunil V L     g_array_append_vals(table_data, isa, strlen(isa) + 1);   /* ISA string */
302ebfd3928SSunil V L 
303ebfd3928SSunil V L     if (aligned_len != len) {
304ebfd3928SSunil V L         build_append_int_noprefix(table_data, 0x0, 1);   /* Optional Padding */
305ebfd3928SSunil V L     }
306ebfd3928SSunil V L 
307e810a517SSunil V L     /* CMO node */
308e810a517SSunil V L     if (cpu->cfg.ext_zicbom || cpu->cfg.ext_zicboz) {
309e810a517SSunil V L         cmo_offset = table_data->len - table.table_offset;
310e810a517SSunil V L         build_append_int_noprefix(table_data, 1, 2);    /* Type */
311e810a517SSunil V L         build_append_int_noprefix(table_data, 10, 2);   /* Length */
312e810a517SSunil V L         build_append_int_noprefix(table_data, 0x1, 2);  /* Revision */
313e810a517SSunil V L         build_append_int_noprefix(table_data, 0, 1);    /* Reserved */
314e810a517SSunil V L 
315e810a517SSunil V L         /* CBOM block size */
316e810a517SSunil V L         if (cpu->cfg.cbom_blocksize) {
317e810a517SSunil V L             build_append_int_noprefix(table_data,
318e810a517SSunil V L                                       __builtin_ctz(cpu->cfg.cbom_blocksize),
319e810a517SSunil V L                                       1);
320e810a517SSunil V L         } else {
321e810a517SSunil V L             build_append_int_noprefix(table_data, 0, 1);
322e810a517SSunil V L         }
323e810a517SSunil V L 
324e810a517SSunil V L         /* CBOP block size */
325e810a517SSunil V L         build_append_int_noprefix(table_data, 0, 1);
326e810a517SSunil V L 
327e810a517SSunil V L         /* CBOZ block size */
328e810a517SSunil V L         if (cpu->cfg.cboz_blocksize) {
329e810a517SSunil V L             build_append_int_noprefix(table_data,
330e810a517SSunil V L                                       __builtin_ctz(cpu->cfg.cboz_blocksize),
331e810a517SSunil V L                                       1);
332e810a517SSunil V L         } else {
333e810a517SSunil V L             build_append_int_noprefix(table_data, 0, 1);
334e810a517SSunil V L         }
335e810a517SSunil V L     }
336e810a517SSunil V L 
337a52aea26SSunil V L     /* MMU node structure */
338a52aea26SSunil V L     if (cpu->cfg.satp_mode.supported != 0) {
339a52aea26SSunil V L         satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
340a52aea26SSunil V L         mmu_offset = table_data->len - table.table_offset;
341a52aea26SSunil V L         build_append_int_noprefix(table_data, 2, 2);    /* Type */
342a52aea26SSunil V L         build_append_int_noprefix(table_data, 8, 2);    /* Length */
343a52aea26SSunil V L         build_append_int_noprefix(table_data, 0x1, 2);  /* Revision */
344a52aea26SSunil V L         build_append_int_noprefix(table_data, 0, 1);    /* Reserved */
345a52aea26SSunil V L         /* MMU Type */
346a52aea26SSunil V L         if (satp_mode_max == VM_1_10_SV57) {
347a52aea26SSunil V L             build_append_int_noprefix(table_data, 2, 1);    /* Sv57 */
348a52aea26SSunil V L         } else if (satp_mode_max == VM_1_10_SV48) {
349a52aea26SSunil V L             build_append_int_noprefix(table_data, 1, 1);    /* Sv48 */
350a52aea26SSunil V L         } else if (satp_mode_max == VM_1_10_SV39) {
351a52aea26SSunil V L             build_append_int_noprefix(table_data, 0, 1);    /* Sv39 */
352a52aea26SSunil V L         } else {
353a52aea26SSunil V L             assert(1);
354a52aea26SSunil V L         }
355a52aea26SSunil V L     }
356a52aea26SSunil V L 
357ebfd3928SSunil V L     /* Hart Info Node */
358ebfd3928SSunil V L     for (int i = 0; i < arch_ids->len; i++) {
359e810a517SSunil V L         len = 16;
360e810a517SSunil V L         int num_offsets = 1;
361ebfd3928SSunil V L         build_append_int_noprefix(table_data, 0xFFFF, 2);  /* Type */
362e810a517SSunil V L 
363e810a517SSunil V L         /* Length */
364e810a517SSunil V L         if (cmo_offset) {
365e810a517SSunil V L             len += 4;
366e810a517SSunil V L             num_offsets++;
367e810a517SSunil V L         }
368e810a517SSunil V L 
369a52aea26SSunil V L         if (mmu_offset) {
370a52aea26SSunil V L             len += 4;
371a52aea26SSunil V L             num_offsets++;
372a52aea26SSunil V L         }
373a52aea26SSunil V L 
374e810a517SSunil V L         build_append_int_noprefix(table_data, len, 2);
375ebfd3928SSunil V L         build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
376e810a517SSunil V L         /* Number of offsets */
377e810a517SSunil V L         build_append_int_noprefix(table_data, num_offsets, 2);
378ebfd3928SSunil V L         build_append_int_noprefix(table_data, i, 4);   /* ACPI Processor UID */
379e810a517SSunil V L         /* Offsets */
380e810a517SSunil V L         build_append_int_noprefix(table_data, isa_offset, 4);
381e810a517SSunil V L         if (cmo_offset) {
382e810a517SSunil V L             build_append_int_noprefix(table_data, cmo_offset, 4);
383e810a517SSunil V L         }
384a52aea26SSunil V L 
385a52aea26SSunil V L         if (mmu_offset) {
386a52aea26SSunil V L             build_append_int_noprefix(table_data, mmu_offset, 4);
387a52aea26SSunil V L         }
388ebfd3928SSunil V L     }
389ebfd3928SSunil V L 
390ebfd3928SSunil V L     acpi_table_end(linker, &table);
391ebfd3928SSunil V L }
392ebfd3928SSunil V L 
3937da2fb24SSunil V L /* FADT */
build_fadt_rev6(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s,unsigned dsdt_tbl_offset)3947da2fb24SSunil V L static void build_fadt_rev6(GArray *table_data,
3957da2fb24SSunil V L                             BIOSLinker *linker,
3967da2fb24SSunil V L                             RISCVVirtState *s,
3977da2fb24SSunil V L                             unsigned dsdt_tbl_offset)
3987da2fb24SSunil V L {
3997da2fb24SSunil V L     AcpiFadtData fadt = {
4007da2fb24SSunil V L         .rev = 6,
4017da2fb24SSunil V L         .minor_ver = 5,
4027da2fb24SSunil V L         .flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI,
4037da2fb24SSunil V L         .xdsdt_tbl_offset = &dsdt_tbl_offset,
4047da2fb24SSunil V L     };
4057da2fb24SSunil V L 
4067da2fb24SSunil V L     build_fadt(table_data, linker, &fadt, s->oem_id, s->oem_table_id);
4077da2fb24SSunil V L }
4087da2fb24SSunil V L 
4097da2fb24SSunil V L /* DSDT */
build_dsdt(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)4107da2fb24SSunil V L static void build_dsdt(GArray *table_data,
4117da2fb24SSunil V L                        BIOSLinker *linker,
4127da2fb24SSunil V L                        RISCVVirtState *s)
4137da2fb24SSunil V L {
4147da2fb24SSunil V L     Aml *scope, *dsdt;
41555ecd83bSSunil V L     MachineState *ms = MACHINE(s);
41655ecd83bSSunil V L     uint8_t socket_count;
4177da2fb24SSunil V L     const MemMapEntry *memmap = s->memmap;
4187da2fb24SSunil V L     AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = s->oem_id,
4197da2fb24SSunil V L                         .oem_table_id = s->oem_table_id };
4207da2fb24SSunil V L 
4217da2fb24SSunil V L 
4227da2fb24SSunil V L     acpi_table_begin(&table, table_data);
4237da2fb24SSunil V L     dsdt = init_aml_allocator();
4247da2fb24SSunil V L 
4257da2fb24SSunil V L     /*
4267da2fb24SSunil V L      * When booting the VM with UEFI, UEFI takes ownership of the RTC hardware.
4277da2fb24SSunil V L      * While UEFI can use libfdt to disable the RTC device node in the DTB that
4287da2fb24SSunil V L      * it passes to the OS, it cannot modify AML. Therefore, we won't generate
4297da2fb24SSunil V L      * the RTC ACPI device at all when using UEFI.
4307da2fb24SSunil V L      */
4317da2fb24SSunil V L     scope = aml_scope("\\_SB");
4327da2fb24SSunil V L     acpi_dsdt_add_cpus(scope, s);
4337da2fb24SSunil V L 
4344c7f4f4fSSunil V L     fw_cfg_acpi_dsdt_add(scope, &memmap[VIRT_FW_CFG]);
4357da2fb24SSunil V L 
43655ecd83bSSunil V L     socket_count = riscv_socket_count(ms);
43755ecd83bSSunil V L 
438a54dd0cdSSunil V L     if (s->aia_type == VIRT_AIA_TYPE_NONE) {
439a54dd0cdSSunil V L         acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_PLIC].base,
440a54dd0cdSSunil V L                                  memmap[VIRT_PLIC].size, "RSCV0001");
441a54dd0cdSSunil V L     } else {
442a54dd0cdSSunil V L         acpi_dsdt_add_plic_aplic(scope, socket_count, memmap[VIRT_APLIC_S].base,
443a54dd0cdSSunil V L                                  memmap[VIRT_APLIC_S].size, "RSCV0002");
444a54dd0cdSSunil V L     }
445a54dd0cdSSunil V L 
44655ecd83bSSunil V L     acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ);
44755ecd83bSSunil V L 
44855ecd83bSSunil V L     if (socket_count == 1) {
44955ecd83bSSunil V L         virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
45055ecd83bSSunil V L                              memmap[VIRT_VIRTIO].size,
45155ecd83bSSunil V L                              VIRTIO_IRQ, 0, VIRTIO_COUNT);
45255ecd83bSSunil V L         acpi_dsdt_add_gpex_host(scope, PCIE_IRQ);
45355ecd83bSSunil V L     } else if (socket_count == 2) {
45455ecd83bSSunil V L         virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
45555ecd83bSSunil V L                              memmap[VIRT_VIRTIO].size,
45655ecd83bSSunil V L                              VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0,
45755ecd83bSSunil V L                              VIRTIO_COUNT);
45855ecd83bSSunil V L         acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES);
45955ecd83bSSunil V L     } else {
46055ecd83bSSunil V L         virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
46155ecd83bSSunil V L                              memmap[VIRT_VIRTIO].size,
46255ecd83bSSunil V L                              VIRTIO_IRQ + VIRT_IRQCHIP_NUM_SOURCES, 0,
46355ecd83bSSunil V L                              VIRTIO_COUNT);
46455ecd83bSSunil V L         acpi_dsdt_add_gpex_host(scope, PCIE_IRQ + VIRT_IRQCHIP_NUM_SOURCES * 2);
46555ecd83bSSunil V L     }
46655ecd83bSSunil V L 
4677da2fb24SSunil V L     aml_append(dsdt, scope);
4687da2fb24SSunil V L 
4697da2fb24SSunil V L     /* copy AML table into ACPI tables blob and patch header there */
4707da2fb24SSunil V L     g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
4717da2fb24SSunil V L 
4727da2fb24SSunil V L     acpi_table_end(linker, &table);
4737da2fb24SSunil V L     free_aml_allocator();
4747da2fb24SSunil V L }
4757da2fb24SSunil V L 
4766cc40ea2SSunil V L /*
4776cc40ea2SSunil V L  * ACPI spec, Revision 6.5+
4786cc40ea2SSunil V L  * 5.2.12 Multiple APIC Description Table (MADT)
4796cc40ea2SSunil V L  * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/15
4806cc40ea2SSunil V L  *      https://drive.google.com/file/d/1R6k4MshhN3WTT-hwqAquu5nX6xSEqK2l/view
4810efb12b7SSunil V L  *      https://drive.google.com/file/d/1oMGPyOD58JaPgMl1pKasT-VKsIKia7zR/view
4826cc40ea2SSunil V L  */
build_madt(GArray * table_data,BIOSLinker * linker,RISCVVirtState * s)4836cc40ea2SSunil V L static void build_madt(GArray *table_data,
4846cc40ea2SSunil V L                        BIOSLinker *linker,
4856cc40ea2SSunil V L                        RISCVVirtState *s)
4866cc40ea2SSunil V L {
4876cc40ea2SSunil V L     MachineClass *mc = MACHINE_GET_CLASS(s);
4886cc40ea2SSunil V L     MachineState *ms = MACHINE(s);
4896cc40ea2SSunil V L     const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
49066ac45b7SSunil V L     uint8_t  group_index_bits = imsic_num_bits(riscv_socket_count(ms));
49166ac45b7SSunil V L     uint8_t  guest_index_bits = imsic_num_bits(s->aia_guests + 1);
49266ac45b7SSunil V L     uint16_t imsic_max_hart_per_socket = 0;
49366ac45b7SSunil V L     uint8_t  hart_index_bits;
4947d189186SSunil V L     uint64_t aplic_addr;
4957d189186SSunil V L     uint32_t gsi_base;
49666ac45b7SSunil V L     uint8_t  socket;
49766ac45b7SSunil V L 
49866ac45b7SSunil V L     for (socket = 0; socket < riscv_socket_count(ms); socket++) {
49966ac45b7SSunil V L         if (imsic_max_hart_per_socket < s->soc[socket].num_harts) {
50066ac45b7SSunil V L             imsic_max_hart_per_socket = s->soc[socket].num_harts;
50166ac45b7SSunil V L         }
50266ac45b7SSunil V L     }
50366ac45b7SSunil V L 
50466ac45b7SSunil V L     hart_index_bits = imsic_num_bits(imsic_max_hart_per_socket);
5056cc40ea2SSunil V L 
5066cc40ea2SSunil V L     AcpiTable table = { .sig = "APIC", .rev = 6, .oem_id = s->oem_id,
5076cc40ea2SSunil V L                         .oem_table_id = s->oem_table_id };
5086cc40ea2SSunil V L 
5096cc40ea2SSunil V L     acpi_table_begin(&table, table_data);
5106cc40ea2SSunil V L     /* Local Interrupt Controller Address */
5116cc40ea2SSunil V L     build_append_int_noprefix(table_data, 0, 4);
5126cc40ea2SSunil V L     build_append_int_noprefix(table_data, 0, 4);   /* MADT Flags */
5136cc40ea2SSunil V L 
5146cc40ea2SSunil V L     /* RISC-V Local INTC structures per HART */
5156cc40ea2SSunil V L     for (int i = 0; i < arch_ids->len; i++) {
5160efb12b7SSunil V L         riscv_acpi_madt_add_rintc(i, arch_ids, table_data, s);
5176cc40ea2SSunil V L     }
5186cc40ea2SSunil V L 
51966ac45b7SSunil V L     /* IMSIC */
52066ac45b7SSunil V L     if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) {
52166ac45b7SSunil V L         /* IMSIC */
52266ac45b7SSunil V L         build_append_int_noprefix(table_data, 0x19, 1);     /* Type */
52366ac45b7SSunil V L         build_append_int_noprefix(table_data, 16, 1);       /* Length */
52466ac45b7SSunil V L         build_append_int_noprefix(table_data, 1, 1);        /* Version */
52566ac45b7SSunil V L         build_append_int_noprefix(table_data, 0, 1);        /* Reserved */
52666ac45b7SSunil V L         build_append_int_noprefix(table_data, 0, 4);        /* Flags */
52766ac45b7SSunil V L         /* Number of supervisor mode Interrupt Identities */
52866ac45b7SSunil V L         build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
52966ac45b7SSunil V L         /* Number of guest mode Interrupt Identities */
53066ac45b7SSunil V L         build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_MSIS, 2);
53166ac45b7SSunil V L         /* Guest Index Bits */
53266ac45b7SSunil V L         build_append_int_noprefix(table_data, guest_index_bits, 1);
53366ac45b7SSunil V L         /* Hart Index Bits */
53466ac45b7SSunil V L         build_append_int_noprefix(table_data, hart_index_bits, 1);
53566ac45b7SSunil V L         /* Group Index Bits */
53666ac45b7SSunil V L         build_append_int_noprefix(table_data, group_index_bits, 1);
53766ac45b7SSunil V L         /* Group Index Shift */
53866ac45b7SSunil V L         build_append_int_noprefix(table_data, IMSIC_MMIO_GROUP_MIN_SHIFT, 1);
53966ac45b7SSunil V L     }
54066ac45b7SSunil V L 
5417d189186SSunil V L     if (s->aia_type != VIRT_AIA_TYPE_NONE) {
5427d189186SSunil V L         /* APLICs */
5437d189186SSunil V L         for (socket = 0; socket < riscv_socket_count(ms); socket++) {
5447d189186SSunil V L             aplic_addr = s->memmap[VIRT_APLIC_S].base +
5457d189186SSunil V L                              s->memmap[VIRT_APLIC_S].size * socket;
5467d189186SSunil V L             gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
5477d189186SSunil V L             build_append_int_noprefix(table_data, 0x1A, 1);    /* Type */
5487d189186SSunil V L             build_append_int_noprefix(table_data, 36, 1);      /* Length */
5497d189186SSunil V L             build_append_int_noprefix(table_data, 1, 1);       /* Version */
5507d189186SSunil V L             build_append_int_noprefix(table_data, socket, 1);  /* APLIC ID */
5517d189186SSunil V L             build_append_int_noprefix(table_data, 0, 4);       /* Flags */
5527d189186SSunil V L             build_append_int_noprefix(table_data, 0, 8);       /* Hardware ID */
5537d189186SSunil V L             /* Number of IDCs */
5547d189186SSunil V L             if (s->aia_type == VIRT_AIA_TYPE_APLIC) {
5557d189186SSunil V L                 build_append_int_noprefix(table_data,
5567d189186SSunil V L                                           s->soc[socket].num_harts,
5577d189186SSunil V L                                           2);
5587d189186SSunil V L             } else {
5597d189186SSunil V L                 build_append_int_noprefix(table_data, 0, 2);
5607d189186SSunil V L             }
5617d189186SSunil V L             /* Total External Interrupt Sources Supported */
5627d189186SSunil V L             build_append_int_noprefix(table_data, VIRT_IRQCHIP_NUM_SOURCES, 2);
5637d189186SSunil V L             /* Global System Interrupt Base */
5647d189186SSunil V L             build_append_int_noprefix(table_data, gsi_base, 4);
5657d189186SSunil V L             /* APLIC Address */
5667d189186SSunil V L             build_append_int_noprefix(table_data, aplic_addr, 8);
5677d189186SSunil V L             /* APLIC size */
5687d189186SSunil V L             build_append_int_noprefix(table_data,
5697d189186SSunil V L                                       s->memmap[VIRT_APLIC_S].size, 4);
5707d189186SSunil V L         }
571d641da6eSSunil V L     } else {
572d641da6eSSunil V L         /* PLICs */
573d641da6eSSunil V L         for (socket = 0; socket < riscv_socket_count(ms); socket++) {
574d641da6eSSunil V L             aplic_addr = s->memmap[VIRT_PLIC].base +
575d641da6eSSunil V L                          s->memmap[VIRT_PLIC].size * socket;
576d641da6eSSunil V L             gsi_base = VIRT_IRQCHIP_NUM_SOURCES * socket;
577d641da6eSSunil V L             build_append_int_noprefix(table_data, 0x1B, 1);   /* Type */
578d641da6eSSunil V L             build_append_int_noprefix(table_data, 36, 1);     /* Length */
579d641da6eSSunil V L             build_append_int_noprefix(table_data, 1, 1);      /* Version */
580d641da6eSSunil V L             build_append_int_noprefix(table_data, socket, 1); /* PLIC ID */
581d641da6eSSunil V L             build_append_int_noprefix(table_data, 0, 8);      /* Hardware ID */
582d641da6eSSunil V L             /* Total External Interrupt Sources Supported */
583d641da6eSSunil V L             build_append_int_noprefix(table_data,
584d641da6eSSunil V L                                       VIRT_IRQCHIP_NUM_SOURCES - 1, 2);
585d641da6eSSunil V L             build_append_int_noprefix(table_data, 0, 2);     /* Max Priority */
586d641da6eSSunil V L             build_append_int_noprefix(table_data, 0, 4);     /* Flags */
587d641da6eSSunil V L             /* PLIC Size */
588d641da6eSSunil V L             build_append_int_noprefix(table_data, s->memmap[VIRT_PLIC].size, 4);
589d641da6eSSunil V L             /* PLIC Address */
590d641da6eSSunil V L             build_append_int_noprefix(table_data, aplic_addr, 8);
591d641da6eSSunil V L             /* Global System Interrupt Vector Base */
592d641da6eSSunil V L             build_append_int_noprefix(table_data, gsi_base, 4);
593d641da6eSSunil V L         }
5947d189186SSunil V L     }
5957d189186SSunil V L 
5966cc40ea2SSunil V L     acpi_table_end(linker, &table);
5976cc40ea2SSunil V L }
5986cc40ea2SSunil V L 
599a29f5b95SHaibo Xu /*
600a29f5b95SHaibo Xu  * ACPI spec, Revision 6.5+
601a29f5b95SHaibo Xu  * 5.2.16 System Resource Affinity Table (SRAT)
602a29f5b95SHaibo Xu  * REF: https://github.com/riscv-non-isa/riscv-acpi/issues/25
603a29f5b95SHaibo Xu  *      https://drive.google.com/file/d/1YTdDx2IPm5IeZjAW932EYU-tUtgS08tX/view
604a29f5b95SHaibo Xu  */
605a29f5b95SHaibo Xu static void
build_srat(GArray * table_data,BIOSLinker * linker,RISCVVirtState * vms)606a29f5b95SHaibo Xu build_srat(GArray *table_data, BIOSLinker *linker, RISCVVirtState *vms)
607a29f5b95SHaibo Xu {
608a29f5b95SHaibo Xu     int i;
609a29f5b95SHaibo Xu     uint64_t mem_base;
610a29f5b95SHaibo Xu     MachineClass *mc = MACHINE_GET_CLASS(vms);
611a29f5b95SHaibo Xu     MachineState *ms = MACHINE(vms);
612a29f5b95SHaibo Xu     const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(ms);
613a29f5b95SHaibo Xu     AcpiTable table = { .sig = "SRAT", .rev = 3, .oem_id = vms->oem_id,
614a29f5b95SHaibo Xu                         .oem_table_id = vms->oem_table_id };
615a29f5b95SHaibo Xu 
616a29f5b95SHaibo Xu     acpi_table_begin(&table, table_data);
617a29f5b95SHaibo Xu     build_append_int_noprefix(table_data, 1, 4); /* Reserved */
618a29f5b95SHaibo Xu     build_append_int_noprefix(table_data, 0, 8); /* Reserved */
619a29f5b95SHaibo Xu 
620a29f5b95SHaibo Xu     for (i = 0; i < cpu_list->len; ++i) {
621a29f5b95SHaibo Xu         uint32_t nodeid = cpu_list->cpus[i].props.node_id;
622a29f5b95SHaibo Xu         /*
623a29f5b95SHaibo Xu          * 5.2.16.8 RINTC Affinity Structure
624a29f5b95SHaibo Xu          */
625a29f5b95SHaibo Xu         build_append_int_noprefix(table_data, 7, 1);      /* Type */
626a29f5b95SHaibo Xu         build_append_int_noprefix(table_data, 20, 1);     /* Length */
627a29f5b95SHaibo Xu         build_append_int_noprefix(table_data, 0, 2);        /* Reserved */
628a29f5b95SHaibo Xu         build_append_int_noprefix(table_data, nodeid, 4); /* Proximity Domain */
629a29f5b95SHaibo Xu         build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */
630a29f5b95SHaibo Xu         /* Flags, Table 5-70 */
631a29f5b95SHaibo Xu         build_append_int_noprefix(table_data, 1 /* Flags: Enabled */, 4);
632a29f5b95SHaibo Xu         build_append_int_noprefix(table_data, 0, 4); /* Clock Domain */
633a29f5b95SHaibo Xu     }
634a29f5b95SHaibo Xu 
635a29f5b95SHaibo Xu     mem_base = vms->memmap[VIRT_DRAM].base;
636a29f5b95SHaibo Xu     for (i = 0; i < ms->numa_state->num_nodes; ++i) {
637a29f5b95SHaibo Xu         if (ms->numa_state->nodes[i].node_mem > 0) {
638a29f5b95SHaibo Xu             build_srat_memory(table_data, mem_base,
639a29f5b95SHaibo Xu                               ms->numa_state->nodes[i].node_mem, i,
640a29f5b95SHaibo Xu                               MEM_AFFINITY_ENABLED);
641a29f5b95SHaibo Xu             mem_base += ms->numa_state->nodes[i].node_mem;
642a29f5b95SHaibo Xu         }
643a29f5b95SHaibo Xu     }
644a29f5b95SHaibo Xu 
645a29f5b95SHaibo Xu     acpi_table_end(linker, &table);
646a29f5b95SHaibo Xu }
647a29f5b95SHaibo Xu 
virt_acpi_build(RISCVVirtState * s,AcpiBuildTables * tables)6487da2fb24SSunil V L static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables)
6497da2fb24SSunil V L {
6507da2fb24SSunil V L     GArray *table_offsets;
6517da2fb24SSunil V L     unsigned dsdt, xsdt;
6527da2fb24SSunil V L     GArray *tables_blob = tables->table_data;
653a29f5b95SHaibo Xu     MachineState *ms = MACHINE(s);
6547da2fb24SSunil V L 
6557da2fb24SSunil V L     table_offsets = g_array_new(false, true,
6567da2fb24SSunil V L                                 sizeof(uint32_t));
6577da2fb24SSunil V L 
6587da2fb24SSunil V L     bios_linker_loader_alloc(tables->linker,
6597da2fb24SSunil V L                              ACPI_BUILD_TABLE_FILE, tables_blob,
6607da2fb24SSunil V L                              64, false);
6617da2fb24SSunil V L 
6627da2fb24SSunil V L     /* DSDT is pointed to by FADT */
6637da2fb24SSunil V L     dsdt = tables_blob->len;
6647da2fb24SSunil V L     build_dsdt(tables_blob, tables->linker, s);
6657da2fb24SSunil V L 
6667da2fb24SSunil V L     /* FADT and others pointed to by XSDT */
6677da2fb24SSunil V L     acpi_add_table(table_offsets, tables_blob);
6687da2fb24SSunil V L     build_fadt_rev6(tables_blob, tables->linker, s, dsdt);
6697da2fb24SSunil V L 
6706cc40ea2SSunil V L     acpi_add_table(table_offsets, tables_blob);
6716cc40ea2SSunil V L     build_madt(tables_blob, tables->linker, s);
6726cc40ea2SSunil V L 
673ebfd3928SSunil V L     acpi_add_table(table_offsets, tables_blob);
674ebfd3928SSunil V L     build_rhct(tables_blob, tables->linker, s);
675ebfd3928SSunil V L 
67655ecd83bSSunil V L     acpi_add_table(table_offsets, tables_blob);
6773e6f1e61SSia Jee Heng     spcr_setup(tables_blob, tables->linker, s);
6783e6f1e61SSia Jee Heng 
6793e6f1e61SSia Jee Heng     acpi_add_table(table_offsets, tables_blob);
68055ecd83bSSunil V L     {
68155ecd83bSSunil V L         AcpiMcfgInfo mcfg = {
68230187659SIlya Chugin            .base = s->memmap[VIRT_PCIE_ECAM].base,
68330187659SIlya Chugin            .size = s->memmap[VIRT_PCIE_ECAM].size,
68455ecd83bSSunil V L         };
68555ecd83bSSunil V L         build_mcfg(tables_blob, tables->linker, &mcfg, s->oem_id,
68655ecd83bSSunil V L                    s->oem_table_id);
68755ecd83bSSunil V L     }
68855ecd83bSSunil V L 
689a29f5b95SHaibo Xu     if (ms->numa_state->num_nodes > 0) {
690a29f5b95SHaibo Xu         acpi_add_table(table_offsets, tables_blob);
691a29f5b95SHaibo Xu         build_srat(tables_blob, tables->linker, s);
692a29f5b95SHaibo Xu         if (ms->numa_state->have_numa_distance) {
693a29f5b95SHaibo Xu             acpi_add_table(table_offsets, tables_blob);
694a29f5b95SHaibo Xu             build_slit(tables_blob, tables->linker, ms, s->oem_id,
695a29f5b95SHaibo Xu                        s->oem_table_id);
696a29f5b95SHaibo Xu         }
697a29f5b95SHaibo Xu     }
698a29f5b95SHaibo Xu 
6997da2fb24SSunil V L     /* XSDT is pointed to by RSDP */
7007da2fb24SSunil V L     xsdt = tables_blob->len;
7017da2fb24SSunil V L     build_xsdt(tables_blob, tables->linker, table_offsets, s->oem_id,
7027da2fb24SSunil V L                 s->oem_table_id);
7037da2fb24SSunil V L 
7047da2fb24SSunil V L     /* RSDP is in FSEG memory, so allocate it separately */
7057da2fb24SSunil V L     {
7067da2fb24SSunil V L         AcpiRsdpData rsdp_data = {
7077da2fb24SSunil V L             .revision = 2,
7087da2fb24SSunil V L             .oem_id = s->oem_id,
7097da2fb24SSunil V L             .xsdt_tbl_offset = &xsdt,
7107da2fb24SSunil V L             .rsdt_tbl_offset = NULL,
7117da2fb24SSunil V L         };
7127da2fb24SSunil V L         build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
7137da2fb24SSunil V L     }
7147da2fb24SSunil V L 
7157da2fb24SSunil V L     /*
7167da2fb24SSunil V L      * The align size is 128, warn if 64k is not enough therefore
7177da2fb24SSunil V L      * the align size could be resized.
7187da2fb24SSunil V L      */
7197da2fb24SSunil V L     if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
7207da2fb24SSunil V L         warn_report("ACPI table size %u exceeds %d bytes,"
7217da2fb24SSunil V L                     " migration may not work",
7227da2fb24SSunil V L                     tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
7237da2fb24SSunil V L         error_printf("Try removing some objects.");
7247da2fb24SSunil V L     }
7257da2fb24SSunil V L 
7267da2fb24SSunil V L     acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
7277da2fb24SSunil V L 
7287da2fb24SSunil V L     /* Clean up memory that's no longer used */
7297da2fb24SSunil V L     g_array_free(table_offsets, true);
7307da2fb24SSunil V L }
7317da2fb24SSunil V L 
acpi_ram_update(MemoryRegion * mr,GArray * data)7327da2fb24SSunil V L static void acpi_ram_update(MemoryRegion *mr, GArray *data)
7337da2fb24SSunil V L {
7347da2fb24SSunil V L     uint32_t size = acpi_data_len(data);
7357da2fb24SSunil V L 
7367da2fb24SSunil V L     /*
7377da2fb24SSunil V L      * Make sure RAM size is correct - in case it got changed
7387da2fb24SSunil V L      * e.g. by migration
7397da2fb24SSunil V L      */
7407da2fb24SSunil V L     memory_region_ram_resize(mr, size, &error_abort);
7417da2fb24SSunil V L 
7427da2fb24SSunil V L     memcpy(memory_region_get_ram_ptr(mr), data->data, size);
7437da2fb24SSunil V L     memory_region_set_dirty(mr, 0, size);
7447da2fb24SSunil V L }
7457da2fb24SSunil V L 
virt_acpi_build_update(void * build_opaque)7467da2fb24SSunil V L static void virt_acpi_build_update(void *build_opaque)
7477da2fb24SSunil V L {
7487da2fb24SSunil V L     AcpiBuildState *build_state = build_opaque;
7497da2fb24SSunil V L     AcpiBuildTables tables;
7507da2fb24SSunil V L 
7517da2fb24SSunil V L     /* No state to update or already patched? Nothing to do. */
7527da2fb24SSunil V L     if (!build_state || build_state->patched) {
7537da2fb24SSunil V L         return;
7547da2fb24SSunil V L     }
7557da2fb24SSunil V L 
7567da2fb24SSunil V L     build_state->patched = true;
7577da2fb24SSunil V L 
7587da2fb24SSunil V L     acpi_build_tables_init(&tables);
7597da2fb24SSunil V L 
7607da2fb24SSunil V L     virt_acpi_build(RISCV_VIRT_MACHINE(qdev_get_machine()), &tables);
7617da2fb24SSunil V L 
7627da2fb24SSunil V L     acpi_ram_update(build_state->table_mr, tables.table_data);
7637da2fb24SSunil V L     acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
7647da2fb24SSunil V L     acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
7657da2fb24SSunil V L 
7667da2fb24SSunil V L     acpi_build_tables_cleanup(&tables, true);
7677da2fb24SSunil V L }
7687da2fb24SSunil V L 
virt_acpi_build_reset(void * build_opaque)7697da2fb24SSunil V L static void virt_acpi_build_reset(void *build_opaque)
7707da2fb24SSunil V L {
7717da2fb24SSunil V L     AcpiBuildState *build_state = build_opaque;
7727da2fb24SSunil V L     build_state->patched = false;
7737da2fb24SSunil V L }
7747da2fb24SSunil V L 
7757da2fb24SSunil V L static const VMStateDescription vmstate_virt_acpi_build = {
7767da2fb24SSunil V L     .name = "virt_acpi_build",
7777da2fb24SSunil V L     .version_id = 1,
7787da2fb24SSunil V L     .minimum_version_id = 1,
779a2c2fe57SRichard Henderson     .fields = (const VMStateField[]) {
7807da2fb24SSunil V L         VMSTATE_BOOL(patched, AcpiBuildState),
7817da2fb24SSunil V L         VMSTATE_END_OF_LIST()
7827da2fb24SSunil V L     },
7837da2fb24SSunil V L };
7847da2fb24SSunil V L 
virt_acpi_setup(RISCVVirtState * s)7857da2fb24SSunil V L void virt_acpi_setup(RISCVVirtState *s)
7867da2fb24SSunil V L {
7877da2fb24SSunil V L     AcpiBuildTables tables;
7887da2fb24SSunil V L     AcpiBuildState *build_state;
7897da2fb24SSunil V L 
7907da2fb24SSunil V L     build_state = g_malloc0(sizeof *build_state);
7917da2fb24SSunil V L 
7927da2fb24SSunil V L     acpi_build_tables_init(&tables);
7937da2fb24SSunil V L     virt_acpi_build(s, &tables);
7947da2fb24SSunil V L 
7957da2fb24SSunil V L     /* Now expose it all to Guest */
7967da2fb24SSunil V L     build_state->table_mr = acpi_add_rom_blob(virt_acpi_build_update,
7977da2fb24SSunil V L                                               build_state, tables.table_data,
7987da2fb24SSunil V L                                               ACPI_BUILD_TABLE_FILE);
7997da2fb24SSunil V L     assert(build_state->table_mr != NULL);
8007da2fb24SSunil V L 
8017da2fb24SSunil V L     build_state->linker_mr = acpi_add_rom_blob(virt_acpi_build_update,
8027da2fb24SSunil V L                                                build_state,
8037da2fb24SSunil V L                                                tables.linker->cmd_blob,
8047da2fb24SSunil V L                                                ACPI_BUILD_LOADER_FILE);
8057da2fb24SSunil V L 
8067da2fb24SSunil V L     build_state->rsdp_mr = acpi_add_rom_blob(virt_acpi_build_update,
8077da2fb24SSunil V L                                              build_state, tables.rsdp,
8087da2fb24SSunil V L                                              ACPI_BUILD_RSDP_FILE);
8097da2fb24SSunil V L 
8107da2fb24SSunil V L     qemu_register_reset(virt_acpi_build_reset, build_state);
8117da2fb24SSunil V L     virt_acpi_build_reset(build_state);
8127da2fb24SSunil V L     vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state);
8137da2fb24SSunil V L 
8147da2fb24SSunil V L     /*
8157da2fb24SSunil V L      * Clean up tables but don't free the memory: we track it
8167da2fb24SSunil V L      * in build_state.
8177da2fb24SSunil V L      */
8187da2fb24SSunil V L     acpi_build_tables_cleanup(&tables, false);
8197da2fb24SSunil V L }
820