From: Sunil V L <sunilvl@ventanamicro.com>
To: Palmer Dabbelt <palmer@dabbelt.com>,
Alistair Francis <alistair.francis@wdc.com>,
Bin Meng <bin.meng@windriver.com>
Cc: qemu-riscv@nongnu.org, qemu-devel@nongnu.org,
Andrew Jones <ajones@ventanamicro.com>,
Anup Patel <apatel@ventanamicro.com>,
Atish Kumar Patra <atishp@rivosinc.com>,
Daniel Henrique Barboza <dbarboza@ventanamicro.com>,
Sunil V L <sunilvl@ventanamicro.com>
Subject: [PATCH V2 04/10] hw/riscv/virt: virt-acpi-build.c: Add basic ACPI tables
Date: Mon, 13 Feb 2023 20:10:32 +0530 [thread overview]
Message-ID: <20230213144038.2547584-5-sunilvl@ventanamicro.com> (raw)
In-Reply-To: <20230213144038.2547584-1-sunilvl@ventanamicro.com>
Add few basic ACPI tables and DSDT with few devices in a
new file virt-acpi-build.c.
These are mostly leveraged from arm64.
Signed-off-by: Sunil V L <sunilvl@ventanamicro.com>
---
hw/riscv/virt-acpi-build.c | 285 +++++++++++++++++++++++++++++++++++++
include/hw/riscv/virt.h | 1 +
2 files changed, 286 insertions(+)
create mode 100644 hw/riscv/virt-acpi-build.c
diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c
new file mode 100644
index 0000000000..3c4da6c385
--- /dev/null
+++ b/hw/riscv/virt-acpi-build.c
@@ -0,0 +1,285 @@
+/*
+ * Support for generating ACPI tables and passing them to Guests
+ *
+ * RISC-V virt ACPI generation
+ *
+ * Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
+ * Copyright (C) 2006 Fabrice Bellard
+ * Copyright (C) 2013 Red Hat Inc
+ * Copyright (c) 2015 HUAWEI TECHNOLOGIES CO.,LTD.
+ * Copyright (C) 2021-2023 Ventana Micro Systems Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/acpi/acpi-defs.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/riscv/virt.h"
+#include "hw/riscv/numa.h"
+#include "hw/acpi/pci.h"
+#include "hw/acpi/utils.h"
+#include "sysemu/reset.h"
+#include "hw/pci-host/gpex.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+
+#define ACPI_BUILD_TABLE_SIZE 0x20000
+
+typedef struct AcpiBuildState {
+ /* Copy of table in RAM (for patching) */
+ MemoryRegion *table_mr;
+ MemoryRegion *rsdp_mr;
+ MemoryRegion *linker_mr;
+ /* Is table patched? */
+ bool patched;
+} AcpiBuildState;
+
+static void acpi_align_size(GArray *blob, unsigned align)
+{
+ /*
+ * Align size to multiple of given size. This reduces the chance
+ * we need to change size in the future (breaking cross version migration).
+ */
+ g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
+}
+
+static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s)
+{
+ MachineState *ms = MACHINE(s);
+ uint16_t i;
+
+ for (i = 0; i < ms->smp.cpus; i++) {
+ Aml *dev = aml_device("C%.03X", i);
+ aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007")));
+ aml_append(dev, aml_name_decl("_UID", aml_int(i)));
+ aml_append(scope, dev);
+ }
+}
+
+static void
+acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap)
+{
+ Aml *dev = aml_device("FWCF");
+ aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002")));
+ /* device present, functioning, decoding, not shown in UI */
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
+ aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
+
+ Aml *crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base,
+ fw_cfg_memmap->size, AML_READ_WRITE));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+}
+
+/* FADT */
+static void
+build_fadt_rev6(GArray *table_data, BIOSLinker *linker,
+ RISCVVirtState *s, unsigned dsdt_tbl_offset)
+{
+ /* ACPI v5.1 */
+ AcpiFadtData fadt = {
+ .rev = 6,
+ .minor_ver = 0,
+ .flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI,
+ .xdsdt_tbl_offset = &dsdt_tbl_offset,
+ };
+
+ build_fadt(table_data, linker, &fadt, s->oem_id, s->oem_table_id);
+}
+
+/* DSDT */
+static void
+build_dsdt(GArray *table_data, BIOSLinker *linker, RISCVVirtState *s)
+{
+ Aml *scope, *dsdt;
+ const MemMapEntry *memmap = s->memmap;
+ AcpiTable table = { .sig = "DSDT", .rev = 2, .oem_id = s->oem_id,
+ .oem_table_id = s->oem_table_id };
+
+
+ acpi_table_begin(&table, table_data);
+ dsdt = init_aml_allocator();
+
+ /*
+ * When booting the VM with UEFI, UEFI takes ownership of the RTC hardware.
+ * While UEFI can use libfdt to disable the RTC device node in the DTB that
+ * it passes to the OS, it cannot modify AML. Therefore, we won't generate
+ * the RTC ACPI device at all when using UEFI.
+ */
+ scope = aml_scope("\\_SB");
+ acpi_dsdt_add_cpus(scope, s);
+
+ acpi_dsdt_add_fw_cfg(scope, &memmap[VIRT_FW_CFG]);
+
+ aml_append(dsdt, scope);
+
+ /* copy AML table into ACPI tables blob and patch header there */
+ g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
+
+ acpi_table_end(linker, &table);
+ free_aml_allocator();
+}
+
+static void
+virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables)
+{
+ GArray *table_offsets;
+ unsigned dsdt, xsdt;
+ GArray *tables_blob = tables->table_data;
+
+ table_offsets = g_array_new(false, true,
+ sizeof(uint32_t));
+
+ bios_linker_loader_alloc(tables->linker,
+ ACPI_BUILD_TABLE_FILE, tables_blob,
+ 64, false);
+
+ /* DSDT is pointed to by FADT */
+ dsdt = tables_blob->len;
+ build_dsdt(tables_blob, tables->linker, s);
+
+ /* FADT and others pointed to by RSDT */
+ acpi_add_table(table_offsets, tables_blob);
+ build_fadt_rev6(tables_blob, tables->linker, s, dsdt);
+
+ acpi_add_table(table_offsets, tables_blob);
+ build_madt(tables_blob, tables->linker, s);
+
+ acpi_add_table(table_offsets, tables_blob);
+ build_rhct(tables_blob, tables->linker, s);
+
+ /* XSDT is pointed to by RSDP */
+ xsdt = tables_blob->len;
+ build_xsdt(tables_blob, tables->linker, table_offsets, s->oem_id,
+ s->oem_table_id);
+
+ /* RSDP is in FSEG memory, so allocate it separately */
+ {
+ AcpiRsdpData rsdp_data = {
+ .revision = 2,
+ .oem_id = s->oem_id,
+ .xsdt_tbl_offset = &xsdt,
+ .rsdt_tbl_offset = NULL,
+ };
+ build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
+ }
+
+ /*
+ * The align size is 128, warn if 64k is not enough therefore
+ * the align size could be resized.
+ */
+ if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
+ warn_report("ACPI table size %u exceeds %d bytes,"
+ " migration may not work",
+ tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
+ error_printf("Try removing CPUs, NUMA nodes, memory slots"
+ " or PCI bridges.");
+ }
+ acpi_align_size(tables_blob, ACPI_BUILD_TABLE_SIZE);
+
+
+ /* Clean up memory that's no longer used */
+ g_array_free(table_offsets, true);
+}
+
+static void acpi_ram_update(MemoryRegion *mr, GArray *data)
+{
+ uint32_t size = acpi_data_len(data);
+
+ /*
+ * Make sure RAM size is correct - in case it got changed
+ * e.g. by migration
+ */
+ memory_region_ram_resize(mr, size, &error_abort);
+
+ memcpy(memory_region_get_ram_ptr(mr), data->data, size);
+ memory_region_set_dirty(mr, 0, size);
+}
+
+static void virt_acpi_build_update(void *build_opaque)
+{
+ AcpiBuildState *build_state = build_opaque;
+ AcpiBuildTables tables;
+
+ /* No state to update or already patched? Nothing to do. */
+ if (!build_state || build_state->patched) {
+ return;
+ }
+ build_state->patched = true;
+
+ acpi_build_tables_init(&tables);
+
+ virt_acpi_build(RISCV_VIRT_MACHINE(qdev_get_machine()), &tables);
+
+ acpi_ram_update(build_state->table_mr, tables.table_data);
+ acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
+ acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
+
+ acpi_build_tables_cleanup(&tables, true);
+}
+
+static void virt_acpi_build_reset(void *build_opaque)
+{
+ AcpiBuildState *build_state = build_opaque;
+ build_state->patched = false;
+}
+
+static const VMStateDescription vmstate_virt_acpi_build = {
+ .name = "virt_acpi_build",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_BOOL(patched, AcpiBuildState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+void virt_acpi_setup(RISCVVirtState *s)
+{
+ AcpiBuildTables tables;
+ AcpiBuildState *build_state;
+
+ build_state = g_malloc0(sizeof *build_state);
+
+ acpi_build_tables_init(&tables);
+ virt_acpi_build(s, &tables);
+
+ /* Now expose it all to Guest */
+ build_state->table_mr = acpi_add_rom_blob(virt_acpi_build_update,
+ build_state, tables.table_data,
+ ACPI_BUILD_TABLE_FILE);
+ assert(build_state->table_mr != NULL);
+
+ build_state->linker_mr = acpi_add_rom_blob(virt_acpi_build_update,
+ build_state,
+ tables.linker->cmd_blob,
+ ACPI_BUILD_LOADER_FILE);
+
+ build_state->rsdp_mr = acpi_add_rom_blob(virt_acpi_build_update,
+ build_state, tables.rsdp,
+ ACPI_BUILD_RSDP_FILE);
+
+ qemu_register_reset(virt_acpi_build_reset, build_state);
+ virt_acpi_build_reset(build_state);
+ vmstate_register(NULL, 0, &vmstate_virt_acpi_build, build_state);
+
+ /*
+ * Clean up tables but don't free the memory: we track it
+ * in build_state.
+ */
+ acpi_build_tables_cleanup(&tables, false);
+}
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index 379501edcc..e5c474b26e 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -126,4 +126,5 @@ enum {
1 + FDT_APLIC_INT_CELLS)
bool virt_is_acpi_enabled(RISCVVirtState *s);
+void virt_acpi_setup(RISCVVirtState *vms);
#endif
--
2.34.1
next prev parent reply other threads:[~2023-02-13 14:41 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-02-13 14:40 [PATCH V2 00/10] Add basic ACPI support for risc-v virt Sunil V L
2023-02-13 14:40 ` [PATCH V2 01/10] hw/riscv/virt: Add OEM_ID and OEM_TABLE_ID fields Sunil V L
2023-02-15 12:17 ` Andrew Jones
2023-02-13 14:40 ` [PATCH V2 02/10] hw/riscv/virt: Add a switch to enable/disable ACPI Sunil V L
2023-02-15 12:24 ` Andrew Jones
2023-02-13 14:40 ` [PATCH V2 03/10] hw/riscv/virt: Add memmap pointer to RiscVVirtState Sunil V L
2023-02-15 12:25 ` Andrew Jones
2023-02-13 14:40 ` Sunil V L [this message]
2023-02-13 18:48 ` [PATCH V2 04/10] hw/riscv/virt: virt-acpi-build.c: Add basic ACPI tables Daniel Henrique Barboza
2023-02-14 3:43 ` Sunil V L
2023-02-14 4:03 ` Bin Meng
2023-02-14 6:56 ` Andrew Jones
2023-02-14 8:44 ` Daniel Henrique Barboza
2023-02-15 14:08 ` Sunil V L
2023-02-16 16:26 ` Palmer Dabbelt
2023-02-16 17:26 ` Sunil V L
2023-02-15 12:55 ` Andrew Jones
2023-02-13 14:40 ` [PATCH V2 05/10] hw/riscv/virt: virt-acpi-build.c: Add RINTC in MADT Sunil V L
2023-02-15 13:05 ` Andrew Jones
2023-02-13 14:40 ` [PATCH V2 06/10] hw/riscv/virt: virt-acpi-build.c: Add RHCT Table Sunil V L
2023-02-15 13:22 ` Andrew Jones
2023-02-13 14:40 ` [PATCH V2 07/10] hw/riscv: meson.build: Build virt-acpi-build.c Sunil V L
2023-02-15 13:24 ` Andrew Jones
2023-02-13 14:40 ` [PATCH V2 08/10] hw/riscv/Kconfig: virt: Enable ACPI config option Sunil V L
2023-02-15 13:24 ` Andrew Jones
2023-02-15 14:05 ` Sunil V L
2023-02-13 14:40 ` [PATCH V2 09/10] hw/riscv/virt.c: Initialize the ACPI tables Sunil V L
2023-02-15 13:24 ` Andrew Jones
2023-02-13 14:40 ` [PATCH V2 10/10] MAINTAINERS: Add entry for RISC-V ACPI Sunil V L
2023-02-15 13:28 ` Andrew Jones
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230213144038.2547584-5-sunilvl@ventanamicro.com \
--to=sunilvl@ventanamicro.com \
--cc=ajones@ventanamicro.com \
--cc=alistair.francis@wdc.com \
--cc=apatel@ventanamicro.com \
--cc=atishp@rivosinc.com \
--cc=bin.meng@windriver.com \
--cc=dbarboza@ventanamicro.com \
--cc=palmer@dabbelt.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.