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:
Peter Maydell 2023-03-07 12:53:00 +00:00
commit 9832009d9d
23 changed files with 1061 additions and 61 deletions

View File

@ -42,9 +42,9 @@
docker-opensbi:
extends: .opensbi_job_rules
stage: containers
image: docker:19.03.1
image: docker:stable
services:
- docker:19.03.1-dind
- docker:stable-dind
variables:
GIT_DEPTH: 3
IMAGE_TAG: $CI_REGISTRY_IMAGE:opensbi-cross-build

View File

@ -15,6 +15,7 @@ RUN apt update \
ca-certificates \
git \
make \
python3 \
wget \
&& \
\

View File

@ -999,12 +999,6 @@ S: Maintained
F: hw/ssi/xlnx-versal-ospi.c
F: include/hw/ssi/xlnx-versal-ospi.h
ARM ACPI Subsystem
M: Shannon Zhao <shannon.zhaosl@gmail.com>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/virt-acpi-build.c
STM32F100
M: Alexandre Iooss <erdnaxe@crans.org>
L: qemu-arm@nongnu.org
@ -1892,6 +1886,18 @@ F: docs/specs/acpi_nvdimm.rst
F: docs/specs/acpi_pci_hotplug.rst
F: docs/specs/acpi_hw_reduced_hotplug.rst
ARM ACPI Subsystem
M: Shannon Zhao <shannon.zhaosl@gmail.com>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/virt-acpi-build.c
RISC-V ACPI Subsystem
M: Sunil V L <sunilvl@ventanamicro.com>
L: qemu-riscv@nongnu.org
S: Maintained
F: hw/riscv/virt-acpi-build.c
ACPI/VIOT
M: Jean-Philippe Brucker <jean-philippe@linaro.org>
S: Supported

View File

@ -1645,7 +1645,7 @@ const rv_opcode_data opcode_data[] = {
{ "max", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
{ "maxu", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
{ "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
{ "clzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
{ "ctzw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
{ "cpopw", rv_codec_r, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
{ "slli.uw", rv_codec_i_sh5, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 },
{ "add.uw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },

View File

@ -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,

View File

@ -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),

View File

@ -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)));

View File

@ -44,6 +44,7 @@ config RISCV_VIRT
select VIRTIO_MMIO
select FW_CFG_DMA
select PLATFORM_BUS
select ACPI
config SHAKTI_C
bool

View File

@ -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
View 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);
}

View File

@ -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 = {

View File

@ -56,6 +56,10 @@ struct RISCVVirtState {
bool have_aclint;
RISCVVirtAIAType aia_type;
int aia_guests;
char *oem_id;
char *oem_table_id;
OnOffAuto acpi;
const MemMapEntry *memmap;
};
enum {
@ -121,4 +125,6 @@ enum {
#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
1 + FDT_APLIC_INT_CELLS)
bool virt_is_acpi_enabled(RISCVVirtState *s);
void virt_acpi_setup(RISCVVirtState *vms);
#endif

@ -1 +1 @@
Subproject commit 4489876e933d8ba0d8bc6c64bae71e295d45faac
Subproject commit 6b5188ca14e59ce7bf71afe4e7d3d557c3d31bf8

View File

@ -28,6 +28,7 @@
#include "time_helper.h"
#include "exec/exec-all.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qemu/error-report.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
@ -75,6 +76,8 @@ struct isa_ext_data {
static const struct isa_ext_data isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(h, false, PRIV_VERSION_1_12_0, ext_h),
ISA_EXT_DATA_ENTRY(v, false, PRIV_VERSION_1_10_0, ext_v),
ISA_EXT_DATA_ENTRY(zicbom, true, PRIV_VERSION_1_12_0, ext_icbom),
ISA_EXT_DATA_ENTRY(zicboz, true, PRIV_VERSION_1_12_0, ext_icboz),
ISA_EXT_DATA_ENTRY(zicond, true, PRIV_VERSION_1_12_0, ext_zicond),
ISA_EXT_DATA_ENTRY(zicsr, true, PRIV_VERSION_1_10_0, ext_icsr),
ISA_EXT_DATA_ENTRY(zifencei, true, PRIV_VERSION_1_10_0, ext_ifencei),
@ -218,7 +221,7 @@ static const char * const riscv_intr_names[] = {
"reserved"
};
static void register_cpu_props(DeviceState *dev);
static void register_cpu_props(Object *obj);
const char *riscv_cpu_get_trap_name(target_ulong cause, bool async)
{
@ -247,6 +250,89 @@ static void set_vext_version(CPURISCVState *env, int vext_ver)
env->vext_ver = vext_ver;
}
#ifndef CONFIG_USER_ONLY
static uint8_t satp_mode_from_str(const char *satp_mode_str)
{
if (!strncmp(satp_mode_str, "mbare", 5)) {
return VM_1_10_MBARE;
}
if (!strncmp(satp_mode_str, "sv32", 4)) {
return VM_1_10_SV32;
}
if (!strncmp(satp_mode_str, "sv39", 4)) {
return VM_1_10_SV39;
}
if (!strncmp(satp_mode_str, "sv48", 4)) {
return VM_1_10_SV48;
}
if (!strncmp(satp_mode_str, "sv57", 4)) {
return VM_1_10_SV57;
}
if (!strncmp(satp_mode_str, "sv64", 4)) {
return VM_1_10_SV64;
}
g_assert_not_reached();
}
uint8_t satp_mode_max_from_map(uint32_t map)
{
/* map here has at least one bit set, so no problem with clz */
return 31 - __builtin_clz(map);
}
const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
{
if (is_32_bit) {
switch (satp_mode) {
case VM_1_10_SV32:
return "sv32";
case VM_1_10_MBARE:
return "none";
}
} else {
switch (satp_mode) {
case VM_1_10_SV64:
return "sv64";
case VM_1_10_SV57:
return "sv57";
case VM_1_10_SV48:
return "sv48";
case VM_1_10_SV39:
return "sv39";
case VM_1_10_MBARE:
return "none";
}
}
g_assert_not_reached();
}
static void set_satp_mode_max_supported(RISCVCPU *cpu,
uint8_t satp_mode)
{
bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64;
for (int i = 0; i <= satp_mode; ++i) {
if (valid_vm[i]) {
cpu->cfg.satp_mode.supported |= (1 << i);
}
}
}
/* Set the satp mode to the max supported */
static void set_satp_mode_default_map(RISCVCPU *cpu)
{
cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported;
}
#endif
static void riscv_any_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
@ -255,8 +341,15 @@ static void riscv_any_cpu_init(Object *obj)
#elif defined(TARGET_RISCV64)
set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
#endif
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj),
riscv_cpu_mxl(&RISCV_CPU(obj)->env) == MXL_RV32 ?
VM_1_10_SV32 : VM_1_10_SV57);
#endif
set_priv_version(env, PRIV_VERSION_1_12_0);
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
}
#if defined(TARGET_RISCV64)
@ -265,17 +358,23 @@ static void rv64_base_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, MXL_RV64, 0);
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
/* Set latest version of privileged specification */
set_priv_version(env, PRIV_VERSION_1_12_0);
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57);
#endif
}
static void rv64_sifive_u_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV39);
#endif
}
static void rv64_sifive_e_cpu_init(Object *obj)
@ -284,9 +383,12 @@ static void rv64_sifive_e_cpu_init(Object *obj)
RISCVCPU *cpu = RISCV_CPU(obj);
set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU);
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
cpu->cfg.mmu = false;
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
#endif
}
static void rv64_thead_c906_cpu_init(Object *obj)
@ -316,6 +418,9 @@ static void rv64_thead_c906_cpu_init(Object *obj)
cpu->cfg.ext_xtheadsync = true;
cpu->cfg.mvendorid = THEAD_VENDOR_ID;
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(cpu, VM_1_10_SV39);
#endif
}
static void rv128_base_cpu_init(Object *obj)
@ -329,9 +434,12 @@ static void rv128_base_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, MXL_RV128, 0);
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
/* Set latest version of privileged specification */
set_priv_version(env, PRIV_VERSION_1_12_0);
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57);
#endif
}
#else
static void rv32_base_cpu_init(Object *obj)
@ -339,17 +447,23 @@ static void rv32_base_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, MXL_RV32, 0);
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
/* Set latest version of privileged specification */
set_priv_version(env, PRIV_VERSION_1_12_0);
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32);
#endif
}
static void rv32_sifive_u_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32);
#endif
}
static void rv32_sifive_e_cpu_init(Object *obj)
@ -358,9 +472,12 @@ static void rv32_sifive_e_cpu_init(Object *obj)
RISCVCPU *cpu = RISCV_CPU(obj);
set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU);
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
cpu->cfg.mmu = false;
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
#endif
}
static void rv32_ibex_cpu_init(Object *obj)
@ -369,9 +486,12 @@ static void rv32_ibex_cpu_init(Object *obj)
RISCVCPU *cpu = RISCV_CPU(obj);
set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU);
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_11_0);
cpu->cfg.mmu = false;
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
#endif
cpu->cfg.epmp = true;
}
@ -381,9 +501,12 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj)
RISCVCPU *cpu = RISCV_CPU(obj);
set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU);
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
cpu->cfg.mmu = false;
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
#endif
}
#endif
@ -396,7 +519,7 @@ static void riscv_host_cpu_init(Object *obj)
#elif defined(TARGET_RISCV64)
set_misa(env, MXL_RV64, 0);
#endif
register_cpu_props(DEVICE(obj));
register_cpu_props(obj);
}
#endif
@ -916,6 +1039,88 @@ static void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
set_misa(env, env->misa_mxl, ext);
}
#ifndef CONFIG_USER_ONLY
static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
{
bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
uint8_t satp_mode_map_max;
uint8_t satp_mode_supported_max =
satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
if (cpu->cfg.satp_mode.map == 0) {
if (cpu->cfg.satp_mode.init == 0) {
/* If unset by the user, we fallback to the default satp mode. */
set_satp_mode_default_map(cpu);
} else {
/*
* Find the lowest level that was disabled and then enable the
* first valid level below which can be found in
* valid_vm_1_10_32/64.
*/
for (int i = 1; i < 16; ++i) {
if ((cpu->cfg.satp_mode.init & (1 << i)) &&
(cpu->cfg.satp_mode.supported & (1 << i))) {
for (int j = i - 1; j >= 0; --j) {
if (cpu->cfg.satp_mode.supported & (1 << j)) {
cpu->cfg.satp_mode.map |= (1 << j);
break;
}
}
break;
}
}
}
}
satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
/* Make sure the user asked for a supported configuration (HW and qemu) */
if (satp_mode_map_max > satp_mode_supported_max) {
error_setg(errp, "satp_mode %s is higher than hw max capability %s",
satp_mode_str(satp_mode_map_max, rv32),
satp_mode_str(satp_mode_supported_max, rv32));
return;
}
/*
* Make sure the user did not ask for an invalid configuration as per
* the specification.
*/
if (!rv32) {
for (int i = satp_mode_map_max - 1; i >= 0; --i) {
if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
(cpu->cfg.satp_mode.init & (1 << i)) &&
(cpu->cfg.satp_mode.supported & (1 << i))) {
error_setg(errp, "cannot disable %s satp mode if %s "
"is enabled", satp_mode_str(i, false),
satp_mode_str(satp_mode_map_max, false));
return;
}
}
}
/* Finally expand the map so that all valid modes are set */
for (int i = satp_mode_map_max - 1; i >= 0; --i) {
if (cpu->cfg.satp_mode.supported & (1 << i)) {
cpu->cfg.satp_mode.map |= (1 << i);
}
}
}
#endif
static void riscv_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
{
#ifndef CONFIG_USER_ONLY
Error *local_err = NULL;
riscv_cpu_satp_mode_finalize(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
#endif
}
static void riscv_cpu_realize(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
@ -1015,6 +1220,12 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
}
#endif
riscv_cpu_finalize_features(cpu, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
riscv_cpu_register_gdb_regs_for_features(cs);
qemu_init_vcpu(cs);
@ -1024,6 +1235,52 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
}
#ifndef CONFIG_USER_ONLY
static void cpu_riscv_get_satp(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
RISCVSATPMap *satp_map = opaque;
uint8_t satp = satp_mode_from_str(name);
bool value;
value = satp_map->map & (1 << satp);
visit_type_bool(v, name, &value, errp);
}
static void cpu_riscv_set_satp(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
RISCVSATPMap *satp_map = opaque;
uint8_t satp = satp_mode_from_str(name);
bool value;
if (!visit_type_bool(v, name, &value, errp)) {
return;
}
satp_map->map = deposit32(satp_map->map, satp, 1, value);
satp_map->init |= 1 << satp;
}
static void riscv_add_satp_mode_properties(Object *obj)
{
RISCVCPU *cpu = RISCV_CPU(obj);
if (cpu->env.misa_mxl == MXL_RV32) {
object_property_add(obj, "sv32", "bool", cpu_riscv_get_satp,
cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode);
} else {
object_property_add(obj, "sv39", "bool", cpu_riscv_get_satp,
cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode);
object_property_add(obj, "sv48", "bool", cpu_riscv_get_satp,
cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode);
object_property_add(obj, "sv57", "bool", cpu_riscv_get_satp,
cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode);
object_property_add(obj, "sv64", "bool", cpu_riscv_get_satp,
cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode);
}
}
static void riscv_cpu_set_irq(void *opaque, int irq, int level)
{
RISCVCPU *cpu = RISCV_CPU(opaque);
@ -1167,6 +1424,11 @@ static Property riscv_cpu_extensions[] = {
DEFINE_PROP_BOOL("zhinx", RISCVCPU, cfg.ext_zhinx, false),
DEFINE_PROP_BOOL("zhinxmin", RISCVCPU, cfg.ext_zhinxmin, false),
DEFINE_PROP_BOOL("zicbom", RISCVCPU, cfg.ext_icbom, true),
DEFINE_PROP_UINT16("cbom_blocksize", RISCVCPU, cfg.cbom_blocksize, 64),
DEFINE_PROP_BOOL("zicboz", RISCVCPU, cfg.ext_icboz, true),
DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64),
DEFINE_PROP_BOOL("zmmul", RISCVCPU, cfg.ext_zmmul, false),
/* Vendor-specific custom extensions */
@ -1203,11 +1465,12 @@ static Property riscv_cpu_extensions[] = {
* properties and leave. env.misa_ext = 0 means that we want
* all the default properties to be registered.
*/
static void register_cpu_props(DeviceState *dev)
static void register_cpu_props(Object *obj)
{
RISCVCPU *cpu = RISCV_CPU(OBJECT(dev));
RISCVCPU *cpu = RISCV_CPU(obj);
uint32_t misa_ext = cpu->env.misa_ext;
Property *prop;
DeviceState *dev = DEVICE(obj);
/*
* If misa_ext is not zero, set cfg properties now to
@ -1238,6 +1501,10 @@ static void register_cpu_props(DeviceState *dev)
for (prop = riscv_cpu_extensions; prop && prop->name; prop++) {
qdev_property_add_static(dev, prop);
}
#ifndef CONFIG_USER_ONLY
riscv_add_satp_mode_properties(obj);
#endif
}
static Property riscv_cpu_properties[] = {
@ -1294,6 +1561,13 @@ static const char *riscv_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
}
#ifndef CONFIG_USER_ONLY
static int64_t riscv_get_arch_id(CPUState *cs)
{
RISCVCPU *cpu = RISCV_CPU(cs);
return cpu->env.mhartid;
}
#include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps riscv_sysemu_ops = {
@ -1348,6 +1622,7 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
cc->disas_set_info = riscv_cpu_disas_set_info;
#ifndef CONFIG_USER_ONLY
cc->sysemu_ops = &riscv_sysemu_ops;
cc->get_arch_id = riscv_get_arch_id;
#endif
cc->gdb_arch_name = riscv_gdb_arch_name;
cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml;

View File

@ -27,6 +27,7 @@
#include "qom/object.h"
#include "qemu/int128.h"
#include "cpu_bits.h"
#include "qapi/qapi-types-common.h"
#define TCG_GUEST_DEFAULT_MO 0
@ -401,6 +402,21 @@ struct RISCVCPUClass {
ResettablePhases parent_phases;
};
/*
* map is a 16-bit bitmap: the most significant set bit in map is the maximum
* satp mode that is supported. It may be chosen by the user and must respect
* what qemu implements (valid_1_10_32/64) and what the hw is capable of
* (supported bitmap below).
*
* init is a 16-bit bitmap used to make sure the user selected a correct
* configuration as per the specification.
*
* supported is a 16-bit bitmap used to reflect the hw capabilities.
*/
typedef struct {
uint16_t map, init, supported;
} RISCVSATPMap;
struct RISCVCPUConfig {
bool ext_i;
bool ext_e;
@ -434,6 +450,8 @@ struct RISCVCPUConfig {
bool ext_zkt;
bool ext_ifencei;
bool ext_icsr;
bool ext_icbom;
bool ext_icboz;
bool ext_zicond;
bool ext_zihintpause;
bool ext_smstateen;
@ -486,6 +504,8 @@ struct RISCVCPUConfig {
char *vext_spec;
uint16_t vlen;
uint16_t elen;
uint16_t cbom_blocksize;
uint16_t cboz_blocksize;
bool mmu;
bool pmp;
bool epmp;
@ -493,6 +513,10 @@ struct RISCVCPUConfig {
bool misa_w;
bool short_isa_string;
#ifndef CONFIG_USER_ONLY
RISCVSATPMap satp_mode;
#endif
};
typedef struct RISCVCPUConfig RISCVCPUConfig;
@ -794,9 +818,14 @@ enum riscv_pmu_event_idx {
/* CSR function table */
extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
extern const bool valid_vm_1_10_32[], valid_vm_1_10_64[];
void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
uint8_t satp_mode_max_from_map(uint32_t map);
const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit);
#endif /* RISCV_CPU_H */

View File

@ -1141,16 +1141,16 @@ static const target_ulong hip_writable_mask = MIP_VSSIP;
static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
static const target_ulong vsip_writable_mask = MIP_VSSIP;
static const char valid_vm_1_10_32[16] = {
[VM_1_10_MBARE] = 1,
[VM_1_10_SV32] = 1
const bool valid_vm_1_10_32[16] = {
[VM_1_10_MBARE] = true,
[VM_1_10_SV32] = true
};
static const char valid_vm_1_10_64[16] = {
[VM_1_10_MBARE] = 1,
[VM_1_10_SV39] = 1,
[VM_1_10_SV48] = 1,
[VM_1_10_SV57] = 1
const bool valid_vm_1_10_64[16] = {
[VM_1_10_MBARE] = true,
[VM_1_10_SV39] = true,
[VM_1_10_SV48] = true,
[VM_1_10_SV57] = true
};
/* Machine Information Registers */
@ -1230,13 +1230,11 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
static int validate_vm(CPURISCVState *env, target_ulong vm)
static bool validate_vm(CPURISCVState *env, target_ulong vm)
{
if (riscv_cpu_mxl(env) == MXL_RV32) {
return valid_vm_1_10_32[vm & 0xf];
} else {
return valid_vm_1_10_64[vm & 0xf];
}
RISCVCPU *cpu = RISCV_CPU(env_cpu(env));
return (vm & 0xf) <= satp_mode_max_from_map(cpu->cfg.satp_mode.map);
}
static RISCVException write_mstatus(CPURISCVState *env, int csrno,
@ -2669,7 +2667,8 @@ static RISCVException read_satp(CPURISCVState *env, int csrno,
static RISCVException write_satp(CPURISCVState *env, int csrno,
target_ulong val)
{
target_ulong vm, mask;
target_ulong mask;
bool vm;
if (!riscv_cpu_cfg(env)->mmu) {
return RISCV_EXCP_NONE;

View File

@ -97,6 +97,11 @@ DEF_HELPER_FLAGS_2(fcvt_h_l, TCG_CALL_NO_RWG, i64, env, tl)
DEF_HELPER_FLAGS_2(fcvt_h_lu, TCG_CALL_NO_RWG, i64, env, tl)
DEF_HELPER_FLAGS_2(fclass_h, TCG_CALL_NO_RWG_SE, tl, env, i64)
/* Cache-block operations */
DEF_HELPER_2(cbo_clean_flush, void, env, tl)
DEF_HELPER_2(cbo_inval, void, env, tl)
DEF_HELPER_2(cbo_zero, void, env, tl)
/* Special functions */
DEF_HELPER_2(csrr, tl, env, int)
DEF_HELPER_3(csrw, void, env, int, tl)

View File

@ -134,6 +134,7 @@ addi ............ ..... 000 ..... 0010011 @i
slti ............ ..... 010 ..... 0010011 @i
sltiu ............ ..... 011 ..... 0010011 @i
xori ............ ..... 100 ..... 0010011 @i
# cbo.prefetch_{i,r,m} instructions are ori with rd=x0 and not decoded.
ori ............ ..... 110 ..... 0010011 @i
andi ............ ..... 111 ..... 0010011 @i
slli 00000. ...... ..... 001 ..... 0010011 @sh
@ -179,7 +180,20 @@ sraw 0100000 ..... ..... 101 ..... 0111011 @r
# *** RV128I Base Instruction Set (in addition to RV64I) ***
ldu ............ ..... 111 ..... 0000011 @i
lq ............ ..... 010 ..... 0001111 @i
{
[
# *** RV32 Zicbom Standard Extension ***
cbo_clean 0000000 00001 ..... 010 00000 0001111 @sfence_vm
cbo_flush 0000000 00010 ..... 010 00000 0001111 @sfence_vm
cbo_inval 0000000 00000 ..... 010 00000 0001111 @sfence_vm
# *** RV32 Zicboz Standard Extension ***
cbo_zero 0000000 00100 ..... 010 00000 0001111 @sfence_vm
]
# *** RVI128 lq ***
lq ............ ..... 010 ..... 0001111 @i
}
sq ............ ..... 100 ..... 0100011 @s
addid ............ ..... 000 ..... 1011011 @i
sllid 000000 ...... ..... 001 ..... 1011011 @sh6

View File

@ -0,0 +1,57 @@
/*
* RISC-V translation routines for the RISC-V CBO Extension.
*
* Copyright (c) 2021 Philipp Tomsich, philipp.tomsich@vrull.eu
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/>.
*/
#define REQUIRE_ZICBOM(ctx) do { \
if (!ctx->cfg_ptr->ext_icbom) { \
return false; \
} \
} while (0)
#define REQUIRE_ZICBOZ(ctx) do { \
if (!ctx->cfg_ptr->ext_icboz) { \
return false; \
} \
} while (0)
static bool trans_cbo_clean(DisasContext *ctx, arg_cbo_clean *a)
{
REQUIRE_ZICBOM(ctx);
gen_helper_cbo_clean_flush(cpu_env, cpu_gpr[a->rs1]);
return true;
}
static bool trans_cbo_flush(DisasContext *ctx, arg_cbo_flush *a)
{
REQUIRE_ZICBOM(ctx);
gen_helper_cbo_clean_flush(cpu_env, cpu_gpr[a->rs1]);
return true;
}
static bool trans_cbo_inval(DisasContext *ctx, arg_cbo_inval *a)
{
REQUIRE_ZICBOM(ctx);
gen_helper_cbo_inval(cpu_env, cpu_gpr[a->rs1]);
return true;
}
static bool trans_cbo_zero(DisasContext *ctx, arg_cbo_zero *a)
{
REQUIRE_ZICBOZ(ctx);
gen_helper_cbo_zero(cpu_env, cpu_gpr[a->rs1]);
return true;
}

View File

@ -3,6 +3,7 @@
*
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
* Copyright (c) 2017-2018 SiFive, Inc.
* Copyright (c) 2022 VRULL GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -123,6 +124,140 @@ target_ulong helper_csrrw_i128(CPURISCVState *env, int csr,
return int128_getlo(rv);
}
/*
* check_zicbo_envcfg
*
* Raise virtual exceptions and illegal instruction exceptions for
* Zicbo[mz] instructions based on the settings of [mhs]envcfg as
* specified in section 2.5.1 of the CMO specification.
*/
static void check_zicbo_envcfg(CPURISCVState *env, target_ulong envbits,
uintptr_t ra)
{
#ifndef CONFIG_USER_ONLY
if ((env->priv < PRV_M) && !get_field(env->menvcfg, envbits)) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, ra);
}
if (riscv_cpu_virt_enabled(env) &&
(((env->priv < PRV_H) && !get_field(env->henvcfg, envbits)) ||
((env->priv < PRV_S) && !get_field(env->senvcfg, envbits)))) {
riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, ra);
}
if ((env->priv < PRV_S) && !get_field(env->senvcfg, envbits)) {
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, ra);
}
#endif
}
void helper_cbo_zero(CPURISCVState *env, target_ulong address)
{
RISCVCPU *cpu = env_archcpu(env);
uint16_t cbozlen = cpu->cfg.cboz_blocksize;
int mmu_idx = cpu_mmu_index(env, false);
uintptr_t ra = GETPC();
void *mem;
check_zicbo_envcfg(env, MENVCFG_CBZE, ra);
/* Mask off low-bits to align-down to the cache-block. */
address &= ~(cbozlen - 1);
/*
* cbo.zero requires MMU_DATA_STORE access. Do a probe_write()
* to raise any exceptions, including PMP.
*/
mem = probe_write(env, address, cbozlen, mmu_idx, ra);
if (likely(mem)) {
memset(mem, 0, cbozlen);
} else {
/*
* This means that we're dealing with an I/O page. Section 4.2
* of cmobase v1.0.1 says:
*
* "Cache-block zero instructions store zeros independently
* of whether data from the underlying memory locations are
* cacheable."
*
* Write zeros in address + cbozlen regardless of not being
* a RAM page.
*/
for (int i = 0; i < cbozlen; i++) {
cpu_stb_mmuidx_ra(env, address + i, 0, mmu_idx, ra);
}
}
}
/*
* check_zicbom_access
*
* Check access permissions (LOAD, STORE or FETCH as specified in
* section 2.5.2 of the CMO specification) for Zicbom, raising
* either store page-fault (non-virtualized) or store guest-page
* fault (virtualized).
*/
static void check_zicbom_access(CPURISCVState *env,
target_ulong address,
uintptr_t ra)
{
RISCVCPU *cpu = env_archcpu(env);
int mmu_idx = cpu_mmu_index(env, false);
uint16_t cbomlen = cpu->cfg.cbom_blocksize;
void *phost;
int ret;
/* Mask off low-bits to align-down to the cache-block. */
address &= ~(cbomlen - 1);
/*
* Section 2.5.2 of cmobase v1.0.1:
*
* "A cache-block management instruction is permitted to
* access the specified cache block whenever a load instruction
* or store instruction is permitted to access the corresponding
* physical addresses. If neither a load instruction nor store
* instruction is permitted to access the physical addresses,
* but an instruction fetch is permitted to access the physical
* addresses, whether a cache-block management instruction is
* permitted to access the cache block is UNSPECIFIED."
*/
ret = probe_access_flags(env, address, cbomlen, MMU_DATA_LOAD,
mmu_idx, true, &phost, ra);
if (ret != TLB_INVALID_MASK) {
/* Success: readable */
return;
}
/*
* Since not readable, must be writable. On failure, store
* fault/store guest amo fault will be raised by
* riscv_cpu_tlb_fill(). PMP exceptions will be caught
* there as well.
*/
probe_write(env, address, cbomlen, mmu_idx, ra);
}
void helper_cbo_clean_flush(CPURISCVState *env, target_ulong address)
{
uintptr_t ra = GETPC();
check_zicbo_envcfg(env, MENVCFG_CBCFE, ra);
check_zicbom_access(env, address, ra);
/* We don't emulate the cache-hierarchy, so we're done. */
}
void helper_cbo_inval(CPURISCVState *env, target_ulong address)
{
uintptr_t ra = GETPC();
check_zicbo_envcfg(env, MENVCFG_CBIE, ra);
check_zicbom_access(env, address, ra);
/* We don't emulate the cache-hierarchy, so we're done. */
}
#ifndef CONFIG_USER_ONLY
target_ulong helper_sret(CPURISCVState *env)

View File

@ -1080,6 +1080,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
#include "insn_trans/trans_rvb.c.inc"
#include "insn_trans/trans_rvzicond.c.inc"
#include "insn_trans/trans_rvzawrs.c.inc"
#include "insn_trans/trans_rvzicbo.c.inc"
#include "insn_trans/trans_rvzfh.c.inc"
#include "insn_trans/trans_rvk.c.inc"
#include "insn_trans/trans_privileged.c.inc"