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