mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-09 02:24:58 -06:00
Sixth RISC-V PR for 8.0
* Support for the Zicbiom, ZCicboz, and Zicbop extensions. * OpenSBI has been updated to version 1.2, see <https://github.com/riscv-software-src/opensbi/releases/tag/v1.2> for the release notes. * Support for setting the virtual address width (ie, sv39/sv48/sv57) on the command line. * Support for ACPI on RISC-V. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAmQGYGgTHHBhbG1lckBk YWJiZWx0LmNvbQAKCRAuExnzX7sYidmyEAC6FEMbbFM5D++qR6w6xM6hXgzcrev6 s1kyRRNVa45uSA78ti/Zi0hsDLNf7ZsNPndF0OIkkO5iAE0OVm3LU7tV1TqKcT82 Dd9VXxe93zEmfnuJazHrMa54SXPhhnNdWHtKlZ6vBfZpbxgx0FFs50xkCsrM5LQZ hYHxQUqPWQTvF2MdDHrxCuLcdKl+Wg3ysCcgRh2d049KUBrIu6vNaHC2+AGRjCbj BkrGCkB82fTmVJjzAcVWQxLoAV12pCbJS4og1GtP8hA7WevtB39tbPin9siBKRZp QBeiIsg0nebkpmZGrb+xWVwlIBNe9yYwJa0KmveQk8v7L5RIzjM1mtDL91VrVljC KC2tfT570m0Iq2NoFMb3wd/kESHFzVDM/g+XYqRd4KSoiCNP/RbqYNQBwbMc31Tr E27xfA1D8w2vem0Rk20x3KgPf1Z5OmGXjq6YObTpnAzG8cZlA37qKBP+ortt5aHX GZSg3CAwknHHVajd4aaegkPsHxm1tRvoTfh38MwkPSNxaA9GD0nz0k9xaYDmeZ2L olfanNsaQEwcVUId31+7sAENg1TZU0fnj879/nxkMUCazVTdL8/mz+IoTTx0QCST 3+9ATWcyJUlmjbDKIs7kr1L+wJdvvHEJggPAbbPI8ekpXaLZvUYOT6ObzYKNAmwY wELQBn8QKXcLVA== =5gAt -----END PGP SIGNATURE----- Merge tag 'pull-riscv-to-apply-20230306' of https://gitlab.com/palmer-dabbelt/qemu into staging Sixth RISC-V PR for 8.0 * Support for the Zicbiom, ZCicboz, and Zicbop extensions. * OpenSBI has been updated to version 1.2, see <https://github.com/riscv-software-src/opensbi/releases/tag/v1.2> for the release notes. * Support for setting the virtual address width (ie, sv39/sv48/sv57) on the command line. * Support for ACPI on RISC-V. # -----BEGIN PGP SIGNATURE----- # # iQJHBAABCAAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAmQGYGgTHHBhbG1lckBk # YWJiZWx0LmNvbQAKCRAuExnzX7sYidmyEAC6FEMbbFM5D++qR6w6xM6hXgzcrev6 # s1kyRRNVa45uSA78ti/Zi0hsDLNf7ZsNPndF0OIkkO5iAE0OVm3LU7tV1TqKcT82 # Dd9VXxe93zEmfnuJazHrMa54SXPhhnNdWHtKlZ6vBfZpbxgx0FFs50xkCsrM5LQZ # hYHxQUqPWQTvF2MdDHrxCuLcdKl+Wg3ysCcgRh2d049KUBrIu6vNaHC2+AGRjCbj # BkrGCkB82fTmVJjzAcVWQxLoAV12pCbJS4og1GtP8hA7WevtB39tbPin9siBKRZp # QBeiIsg0nebkpmZGrb+xWVwlIBNe9yYwJa0KmveQk8v7L5RIzjM1mtDL91VrVljC # KC2tfT570m0Iq2NoFMb3wd/kESHFzVDM/g+XYqRd4KSoiCNP/RbqYNQBwbMc31Tr # E27xfA1D8w2vem0Rk20x3KgPf1Z5OmGXjq6YObTpnAzG8cZlA37qKBP+ortt5aHX # GZSg3CAwknHHVajd4aaegkPsHxm1tRvoTfh38MwkPSNxaA9GD0nz0k9xaYDmeZ2L # olfanNsaQEwcVUId31+7sAENg1TZU0fnj879/nxkMUCazVTdL8/mz+IoTTx0QCST # 3+9ATWcyJUlmjbDKIs7kr1L+wJdvvHEJggPAbbPI8ekpXaLZvUYOT6ObzYKNAmwY # wELQBn8QKXcLVA== # =5gAt # -----END PGP SIGNATURE----- # gpg: Signature made Mon 06 Mar 2023 21:51:36 GMT # gpg: using RSA key 2B3C3747446843B24A943A7A2E1319F35FBB1889 # gpg: issuer "palmer@dabbelt.com" # gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" [unknown] # gpg: aka "Palmer Dabbelt <palmerdabbelt@google.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 00CE 76D1 8349 60DF CE88 6DF8 EF4C A150 2CCB AB41 # Subkey fingerprint: 2B3C 3747 4468 43B2 4A94 3A7A 2E13 19F3 5FBB 1889 * tag 'pull-riscv-to-apply-20230306' of https://gitlab.com/palmer-dabbelt/qemu: (22 commits) MAINTAINERS: Add entry for RISC-V ACPI hw/riscv/virt.c: Initialize the ACPI tables hw/riscv/virt: virt-acpi-build.c: Add RHCT Table hw/riscv/virt: virt-acpi-build.c: Add RINTC in MADT hw/riscv/virt: Enable basic ACPI infrastructure hw/riscv/virt: Add memmap pointer to RiscVVirtState hw/riscv/virt: Add a switch to disable ACPI hw/riscv/virt: Add OEM_ID and OEM_TABLE_ID fields riscv: Correctly set the device-tree entry 'mmu-type' riscv: Introduce satp mode hw capabilities riscv: Allow user to set the satp mode riscv: Change type of valid_vm_1_10_[32|64] to bool riscv: Pass Object to register_cpu_props instead of DeviceState roms/opensbi: Upgrade from v1.1 to v1.2 gitlab/opensbi: Move to docker:stable hw: intc: Use cpu_by_arch_id to fetch CPU state target/riscv: cpu: Implement get_arch_id callback disas/riscv Fix ctzw disassemble hw/riscv/virt.c: add cbo[mz]-block-size fdt properties target/riscv: add Zicbop cbo.prefetch{i, r, m} placeholder ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
9832009d9d
23 changed files with 1061 additions and 61 deletions
|
@ -130,7 +130,7 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
|
|||
addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) {
|
||||
size_t hartid = mtimer->hartid_base +
|
||||
((addr - mtimer->timecmp_base) >> 3);
|
||||
CPUState *cpu = qemu_get_cpu(hartid);
|
||||
CPUState *cpu = cpu_by_arch_id(hartid);
|
||||
CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
|
||||
if (!env) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
|
@ -173,7 +173,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
|
|||
addr < (mtimer->timecmp_base + (mtimer->num_harts << 3))) {
|
||||
size_t hartid = mtimer->hartid_base +
|
||||
((addr - mtimer->timecmp_base) >> 3);
|
||||
CPUState *cpu = qemu_get_cpu(hartid);
|
||||
CPUState *cpu = cpu_by_arch_id(hartid);
|
||||
CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
|
||||
if (!env) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
|
@ -231,7 +231,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
|
|||
|
||||
/* Check if timer interrupt is triggered for each hart. */
|
||||
for (i = 0; i < mtimer->num_harts; i++) {
|
||||
CPUState *cpu = qemu_get_cpu(mtimer->hartid_base + i);
|
||||
CPUState *cpu = cpu_by_arch_id(mtimer->hartid_base + i);
|
||||
CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
|
||||
if (!env) {
|
||||
continue;
|
||||
|
@ -292,7 +292,7 @@ static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
|
|||
s->timecmp = g_new0(uint64_t, s->num_harts);
|
||||
/* Claim timer interrupt bits */
|
||||
for (i = 0; i < s->num_harts; i++) {
|
||||
RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
|
||||
RISCVCPU *cpu = RISCV_CPU(cpu_by_arch_id(s->hartid_base + i));
|
||||
if (riscv_cpu_claim_interrupts(cpu, MIP_MTIP) < 0) {
|
||||
error_report("MTIP already claimed");
|
||||
exit(1);
|
||||
|
@ -372,7 +372,7 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
|
|||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
|
||||
|
||||
for (i = 0; i < num_harts; i++) {
|
||||
CPUState *cpu = qemu_get_cpu(hartid_base + i);
|
||||
CPUState *cpu = cpu_by_arch_id(hartid_base + i);
|
||||
RISCVCPU *rvcpu = RISCV_CPU(cpu);
|
||||
CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
|
||||
riscv_aclint_mtimer_callback *cb =
|
||||
|
@ -407,7 +407,7 @@ static uint64_t riscv_aclint_swi_read(void *opaque, hwaddr addr,
|
|||
|
||||
if (addr < (swi->num_harts << 2)) {
|
||||
size_t hartid = swi->hartid_base + (addr >> 2);
|
||||
CPUState *cpu = qemu_get_cpu(hartid);
|
||||
CPUState *cpu = cpu_by_arch_id(hartid);
|
||||
CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
|
||||
if (!env) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
|
@ -430,7 +430,7 @@ static void riscv_aclint_swi_write(void *opaque, hwaddr addr, uint64_t value,
|
|||
|
||||
if (addr < (swi->num_harts << 2)) {
|
||||
size_t hartid = swi->hartid_base + (addr >> 2);
|
||||
CPUState *cpu = qemu_get_cpu(hartid);
|
||||
CPUState *cpu = cpu_by_arch_id(hartid);
|
||||
CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
|
||||
if (!env) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
|
@ -545,7 +545,7 @@ DeviceState *riscv_aclint_swi_create(hwaddr addr, uint32_t hartid_base,
|
|||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
|
||||
|
||||
for (i = 0; i < num_harts; i++) {
|
||||
CPUState *cpu = qemu_get_cpu(hartid_base + i);
|
||||
CPUState *cpu = cpu_by_arch_id(hartid_base + i);
|
||||
RISCVCPU *rvcpu = RISCV_CPU(cpu);
|
||||
|
||||
qdev_connect_gpio_out(dev, i,
|
||||
|
|
|
@ -833,7 +833,7 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
/* Claim the CPU interrupt to be triggered by this APLIC */
|
||||
for (i = 0; i < aplic->num_harts; i++) {
|
||||
RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(aplic->hartid_base + i));
|
||||
RISCVCPU *cpu = RISCV_CPU(cpu_by_arch_id(aplic->hartid_base + i));
|
||||
if (riscv_cpu_claim_interrupts(cpu,
|
||||
(aplic->mmode) ? MIP_MEIP : MIP_SEIP) < 0) {
|
||||
error_report("%s already claimed",
|
||||
|
@ -966,7 +966,7 @@ DeviceState *riscv_aplic_create(hwaddr addr, hwaddr size,
|
|||
|
||||
if (!msimode) {
|
||||
for (i = 0; i < num_harts; i++) {
|
||||
CPUState *cpu = qemu_get_cpu(hartid_base + i);
|
||||
CPUState *cpu = cpu_by_arch_id(hartid_base + i);
|
||||
|
||||
qdev_connect_gpio_out_named(dev, NULL, i,
|
||||
qdev_get_gpio_in(DEVICE(cpu),
|
||||
|
|
|
@ -316,8 +316,8 @@ static const MemoryRegionOps riscv_imsic_ops = {
|
|||
static void riscv_imsic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
RISCVIMSICState *imsic = RISCV_IMSIC(dev);
|
||||
RISCVCPU *rcpu = RISCV_CPU(qemu_get_cpu(imsic->hartid));
|
||||
CPUState *cpu = qemu_get_cpu(imsic->hartid);
|
||||
RISCVCPU *rcpu = RISCV_CPU(cpu_by_arch_id(imsic->hartid));
|
||||
CPUState *cpu = cpu_by_arch_id(imsic->hartid);
|
||||
CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
|
||||
|
||||
imsic->num_eistate = imsic->num_pages * imsic->num_irqs;
|
||||
|
@ -413,7 +413,7 @@ DeviceState *riscv_imsic_create(hwaddr addr, uint32_t hartid, bool mmode,
|
|||
uint32_t num_pages, uint32_t num_ids)
|
||||
{
|
||||
DeviceState *dev = qdev_new(TYPE_RISCV_IMSIC);
|
||||
CPUState *cpu = qemu_get_cpu(hartid);
|
||||
CPUState *cpu = cpu_by_arch_id(hartid);
|
||||
uint32_t i;
|
||||
|
||||
assert(!(addr & (IMSIC_MMIO_PAGE_SZ - 1)));
|
||||
|
|
|
@ -44,6 +44,7 @@ config RISCV_VIRT
|
|||
select VIRTIO_MMIO
|
||||
select FW_CFG_DMA
|
||||
select PLATFORM_BUS
|
||||
select ACPI
|
||||
|
||||
config SHAKTI_C
|
||||
bool
|
||||
|
|
|
@ -9,5 +9,6 @@ riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c'))
|
|||
riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c'))
|
||||
riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c'))
|
||||
riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c'))
|
||||
riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
|
||||
|
||||
hw_arch += {'riscv': riscv_ss}
|
||||
|
|
416
hw/riscv/virt-acpi-build.c
Normal file
416
hw/riscv/virt-acpi-build.c
Normal file
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* 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/acpi/utils.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/riscv/virt.h"
|
||||
#include "hw/riscv/numa.h"
|
||||
#include "hw/intc/riscv_aclint.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 riscv_acpi_madt_add_rintc(uint32_t uid,
|
||||
const CPUArchIdList *arch_ids,
|
||||
GArray *entry)
|
||||
{
|
||||
uint64_t hart_id = arch_ids->cpus[uid].arch_id;
|
||||
|
||||
build_append_int_noprefix(entry, 0x18, 1); /* Type */
|
||||
build_append_int_noprefix(entry, 20, 1); /* Length */
|
||||
build_append_int_noprefix(entry, 1, 1); /* Version */
|
||||
build_append_int_noprefix(entry, 0, 1); /* Reserved */
|
||||
build_append_int_noprefix(entry, 0x1, 4); /* Flags */
|
||||
build_append_int_noprefix(entry, hart_id, 8); /* Hart ID */
|
||||
build_append_int_noprefix(entry, uid, 4); /* ACPI Processor UID */
|
||||
}
|
||||
|
||||
static void acpi_dsdt_add_cpus(Aml *scope, RISCVVirtState *s)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(s);
|
||||
MachineState *ms = MACHINE(s);
|
||||
const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
|
||||
|
||||
for (int i = 0; i < arch_ids->len; i++) {
|
||||
Aml *dev;
|
||||
GArray *madt_buf = g_array_new(0, 1, 1);
|
||||
|
||||
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(arch_ids->cpus[i].arch_id)));
|
||||
|
||||
/* build _MAT object */
|
||||
riscv_acpi_madt_add_rintc(i, arch_ids, madt_buf);
|
||||
aml_append(dev, aml_name_decl("_MAT",
|
||||
aml_buffer(madt_buf->len,
|
||||
(uint8_t *)madt_buf->data)));
|
||||
g_array_free(madt_buf, true);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* RHCT Node[N] starts at offset 56 */
|
||||
#define RHCT_NODE_ARRAY_OFFSET 56
|
||||
|
||||
/*
|
||||
* ACPI spec, Revision 6.5+
|
||||
* 5.2.36 RISC-V Hart Capabilities Table (RHCT)
|
||||
* REF: https://github.com/riscv-non-isa/riscv-acpi/issues/16
|
||||
* https://drive.google.com/file/d/1nP3nFiH4jkPMp6COOxP6123DCZKR-tia/view
|
||||
*/
|
||||
static void build_rhct(GArray *table_data,
|
||||
BIOSLinker *linker,
|
||||
RISCVVirtState *s)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(s);
|
||||
MachineState *ms = MACHINE(s);
|
||||
const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
|
||||
size_t len, aligned_len;
|
||||
uint32_t isa_offset, num_rhct_nodes;
|
||||
RISCVCPU *cpu;
|
||||
char *isa;
|
||||
|
||||
AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id,
|
||||
.oem_table_id = s->oem_table_id };
|
||||
|
||||
acpi_table_begin(&table, table_data);
|
||||
|
||||
build_append_int_noprefix(table_data, 0x0, 4); /* Reserved */
|
||||
|
||||
/* Time Base Frequency */
|
||||
build_append_int_noprefix(table_data,
|
||||
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, 8);
|
||||
|
||||
/* ISA + N hart info */
|
||||
num_rhct_nodes = 1 + ms->smp.cpus;
|
||||
|
||||
/* Number of RHCT nodes*/
|
||||
build_append_int_noprefix(table_data, num_rhct_nodes, 4);
|
||||
|
||||
/* Offset to the RHCT node array */
|
||||
build_append_int_noprefix(table_data, RHCT_NODE_ARRAY_OFFSET, 4);
|
||||
|
||||
/* ISA String Node */
|
||||
isa_offset = table_data->len - table.table_offset;
|
||||
build_append_int_noprefix(table_data, 0, 2); /* Type 0 */
|
||||
|
||||
cpu = &s->soc[0].harts[0];
|
||||
isa = riscv_isa_string(cpu);
|
||||
len = 8 + strlen(isa) + 1;
|
||||
aligned_len = (len % 2) ? (len + 1) : len;
|
||||
|
||||
build_append_int_noprefix(table_data, aligned_len, 2); /* Length */
|
||||
build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
|
||||
|
||||
/* ISA string length including NUL */
|
||||
build_append_int_noprefix(table_data, strlen(isa) + 1, 2);
|
||||
g_array_append_vals(table_data, isa, strlen(isa) + 1); /* ISA string */
|
||||
|
||||
if (aligned_len != len) {
|
||||
build_append_int_noprefix(table_data, 0x0, 1); /* Optional Padding */
|
||||
}
|
||||
|
||||
/* Hart Info Node */
|
||||
for (int i = 0; i < arch_ids->len; i++) {
|
||||
build_append_int_noprefix(table_data, 0xFFFF, 2); /* Type */
|
||||
build_append_int_noprefix(table_data, 16, 2); /* Length */
|
||||
build_append_int_noprefix(table_data, 0x1, 2); /* Revision */
|
||||
build_append_int_noprefix(table_data, 1, 2); /* Number of offsets */
|
||||
build_append_int_noprefix(table_data, i, 4); /* ACPI Processor UID */
|
||||
build_append_int_noprefix(table_data, isa_offset, 4); /* Offsets[0] */
|
||||
}
|
||||
|
||||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
/* FADT */
|
||||
static void build_fadt_rev6(GArray *table_data,
|
||||
BIOSLinker *linker,
|
||||
RISCVVirtState *s,
|
||||
unsigned dsdt_tbl_offset)
|
||||
{
|
||||
AcpiFadtData fadt = {
|
||||
.rev = 6,
|
||||
.minor_ver = 5,
|
||||
.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();
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI spec, Revision 6.5+
|
||||
* 5.2.12 Multiple APIC Description Table (MADT)
|
||||
* REF: https://github.com/riscv-non-isa/riscv-acpi/issues/15
|
||||
* https://drive.google.com/file/d/1R6k4MshhN3WTT-hwqAquu5nX6xSEqK2l/view
|
||||
*/
|
||||
static void build_madt(GArray *table_data,
|
||||
BIOSLinker *linker,
|
||||
RISCVVirtState *s)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(s);
|
||||
MachineState *ms = MACHINE(s);
|
||||
const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
|
||||
|
||||
AcpiTable table = { .sig = "APIC", .rev = 6, .oem_id = s->oem_id,
|
||||
.oem_table_id = s->oem_table_id };
|
||||
|
||||
acpi_table_begin(&table, table_data);
|
||||
/* Local Interrupt Controller Address */
|
||||
build_append_int_noprefix(table_data, 0, 4);
|
||||
build_append_int_noprefix(table_data, 0, 4); /* MADT Flags */
|
||||
|
||||
/* RISC-V Local INTC structures per HART */
|
||||
for (int i = 0; i < arch_ids->len; i++) {
|
||||
riscv_acpi_madt_add_rintc(i, arch_ids, table_data);
|
||||
}
|
||||
|
||||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
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 XSDT */
|
||||
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 some objects.");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
|
@ -49,6 +49,8 @@
|
|||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci-host/gpex.h"
|
||||
#include "hw/display/ramfb.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "qapi/qapi-visit-common.h"
|
||||
|
||||
/*
|
||||
* The virt machine physical address space used by some of the devices
|
||||
|
@ -228,8 +230,9 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
|
|||
int cpu;
|
||||
uint32_t cpu_phandle;
|
||||
MachineState *ms = MACHINE(s);
|
||||
char *name, *cpu_name, *core_name, *intc_name;
|
||||
char *name, *cpu_name, *core_name, *intc_name, *sv_name;
|
||||
bool is_32_bit = riscv_is_32bit(&s->soc[0]);
|
||||
uint8_t satp_mode_max;
|
||||
|
||||
for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) {
|
||||
RISCVCPU *cpu_ptr = &s->soc[socket].harts[cpu];
|
||||
|
@ -239,16 +242,29 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
|
|||
cpu_name = g_strdup_printf("/cpus/cpu@%d",
|
||||
s->soc[socket].hartid_base + cpu);
|
||||
qemu_fdt_add_subnode(ms->fdt, cpu_name);
|
||||
if (cpu_ptr->cfg.mmu) {
|
||||
qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type",
|
||||
(is_32_bit) ? "riscv,sv32" : "riscv,sv48");
|
||||
} else {
|
||||
qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type",
|
||||
"riscv,none");
|
||||
}
|
||||
|
||||
satp_mode_max = satp_mode_max_from_map(
|
||||
s->soc[socket].harts[cpu].cfg.satp_mode.map);
|
||||
sv_name = g_strdup_printf("riscv,%s",
|
||||
satp_mode_str(satp_mode_max, is_32_bit));
|
||||
qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", sv_name);
|
||||
g_free(sv_name);
|
||||
|
||||
|
||||
name = riscv_isa_string(cpu_ptr);
|
||||
qemu_fdt_setprop_string(ms->fdt, cpu_name, "riscv,isa", name);
|
||||
g_free(name);
|
||||
|
||||
if (cpu_ptr->cfg.ext_icbom) {
|
||||
qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbom-block-size",
|
||||
cpu_ptr->cfg.cbom_blocksize);
|
||||
}
|
||||
|
||||
if (cpu_ptr->cfg.ext_icboz) {
|
||||
qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cboz-block-size",
|
||||
cpu_ptr->cfg.cboz_blocksize);
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_string(ms->fdt, cpu_name, "compatible", "riscv");
|
||||
qemu_fdt_setprop_string(ms->fdt, cpu_name, "status", "okay");
|
||||
qemu_fdt_setprop_cell(ms->fdt, cpu_name, "reg",
|
||||
|
@ -1307,6 +1323,10 @@ static void virt_machine_done(Notifier *notifier, void *data)
|
|||
if (kvm_enabled()) {
|
||||
riscv_setup_direct_kernel(kernel_entry, fdt_load_addr);
|
||||
}
|
||||
|
||||
if (virt_is_acpi_enabled(s)) {
|
||||
virt_acpi_setup(s);
|
||||
}
|
||||
}
|
||||
|
||||
static void virt_machine_init(MachineState *machine)
|
||||
|
@ -1442,6 +1462,8 @@ static void virt_machine_init(MachineState *machine)
|
|||
ROUND_UP(virt_high_pcie_memmap.base, virt_high_pcie_memmap.size);
|
||||
}
|
||||
|
||||
s->memmap = virt_memmap;
|
||||
|
||||
/* register system main memory (actual RAM) */
|
||||
memory_region_add_subregion(system_memory, memmap[VIRT_DRAM].base,
|
||||
machine->ram);
|
||||
|
@ -1514,6 +1536,11 @@ static void virt_machine_init(MachineState *machine)
|
|||
|
||||
static void virt_machine_instance_init(Object *obj)
|
||||
{
|
||||
RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
|
||||
|
||||
s->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
|
||||
s->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
|
||||
s->acpi = ON_OFF_AUTO_AUTO;
|
||||
}
|
||||
|
||||
static char *virt_get_aia_guests(Object *obj, Error **errp)
|
||||
|
@ -1588,6 +1615,28 @@ static void virt_set_aclint(Object *obj, bool value, Error **errp)
|
|||
s->have_aclint = value;
|
||||
}
|
||||
|
||||
bool virt_is_acpi_enabled(RISCVVirtState *s)
|
||||
{
|
||||
return s->acpi != ON_OFF_AUTO_OFF;
|
||||
}
|
||||
|
||||
static void virt_get_acpi(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
|
||||
OnOffAuto acpi = s->acpi;
|
||||
|
||||
visit_type_OnOffAuto(v, name, &acpi, errp);
|
||||
}
|
||||
|
||||
static void virt_set_acpi(Object *obj, Visitor *v, const char *name,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
|
||||
|
||||
visit_type_OnOffAuto(v, name, &s->acpi, errp);
|
||||
}
|
||||
|
||||
static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
|
||||
DeviceState *dev)
|
||||
{
|
||||
|
@ -1659,6 +1708,11 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
|
|||
sprintf(str, "Set number of guest MMIO pages for AIA IMSIC. Valid value "
|
||||
"should be between 0 and %d.", VIRT_IRQCHIP_MAX_GUESTS);
|
||||
object_class_property_set_description(oc, "aia-guests", str);
|
||||
object_class_property_add(oc, "acpi", "OnOffAuto",
|
||||
virt_get_acpi, virt_set_acpi,
|
||||
NULL, NULL);
|
||||
object_class_property_set_description(oc, "acpi",
|
||||
"Enable ACPI");
|
||||
}
|
||||
|
||||
static const TypeInfo virt_machine_typeinfo = {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue