hw/riscv: add RISC-V IOMMU base emulation
The RISC-V IOMMU specification is now ratified as-per the RISC-V international process. The latest frozen specifcation can be found at: https://github.com/riscv-non-isa/riscv-iommu/releases/download/v1.0/riscv-iommu.pdf Add the foundation of the device emulation for RISC-V IOMMU. It includes support for s-stage (sv32, sv39, sv48, sv57 caps) and g-stage (sv32x4, sv39x4, sv48x4, sv57x4 caps). Other capabilities like ATS and DBG support will be added incrementally in the next patches. Co-developed-by: Sebastien Boeuf <seb@rivosinc.com> Signed-off-by: Sebastien Boeuf <seb@rivosinc.com> Signed-off-by: Tomasz Jeznach <tjeznach@rivosinc.com> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Jason Chien <jason.chien@sifive.com> Message-ID: <20241016204038.649340-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
e21b3b243f
commit
0c54acb824
@ -1,3 +1,6 @@
|
|||||||
|
config RISCV_IOMMU
|
||||||
|
bool
|
||||||
|
|
||||||
config RISCV_NUMA
|
config RISCV_NUMA
|
||||||
bool
|
bool
|
||||||
|
|
||||||
@ -47,6 +50,7 @@ config RISCV_VIRT
|
|||||||
select SERIAL_MM
|
select SERIAL_MM
|
||||||
select RISCV_ACLINT
|
select RISCV_ACLINT
|
||||||
select RISCV_APLIC
|
select RISCV_APLIC
|
||||||
|
select RISCV_IOMMU
|
||||||
select RISCV_IMSIC
|
select RISCV_IMSIC
|
||||||
select SIFIVE_PLIC
|
select SIFIVE_PLIC
|
||||||
select SIFIVE_TEST
|
select SIFIVE_TEST
|
||||||
|
@ -10,5 +10,6 @@ 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_SPIKE', if_true: files('spike.c'))
|
||||||
riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.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'))
|
riscv_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c'))
|
||||||
|
riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files('riscv-iommu.c'))
|
||||||
|
|
||||||
hw_arch += {'riscv': riscv_ss}
|
hw_arch += {'riscv': riscv_ss}
|
||||||
|
@ -69,6 +69,14 @@ struct riscv_iommu_pq_record {
|
|||||||
/* 5.3 IOMMU Capabilities (64bits) */
|
/* 5.3 IOMMU Capabilities (64bits) */
|
||||||
#define RISCV_IOMMU_REG_CAP 0x0000
|
#define RISCV_IOMMU_REG_CAP 0x0000
|
||||||
#define RISCV_IOMMU_CAP_VERSION GENMASK_ULL(7, 0)
|
#define RISCV_IOMMU_CAP_VERSION GENMASK_ULL(7, 0)
|
||||||
|
#define RISCV_IOMMU_CAP_SV32 BIT_ULL(8)
|
||||||
|
#define RISCV_IOMMU_CAP_SV39 BIT_ULL(9)
|
||||||
|
#define RISCV_IOMMU_CAP_SV48 BIT_ULL(10)
|
||||||
|
#define RISCV_IOMMU_CAP_SV57 BIT_ULL(11)
|
||||||
|
#define RISCV_IOMMU_CAP_SV32X4 BIT_ULL(16)
|
||||||
|
#define RISCV_IOMMU_CAP_SV39X4 BIT_ULL(17)
|
||||||
|
#define RISCV_IOMMU_CAP_SV48X4 BIT_ULL(18)
|
||||||
|
#define RISCV_IOMMU_CAP_SV57X4 BIT_ULL(19)
|
||||||
#define RISCV_IOMMU_CAP_MSI_FLAT BIT_ULL(22)
|
#define RISCV_IOMMU_CAP_MSI_FLAT BIT_ULL(22)
|
||||||
#define RISCV_IOMMU_CAP_MSI_MRIF BIT_ULL(23)
|
#define RISCV_IOMMU_CAP_MSI_MRIF BIT_ULL(23)
|
||||||
#define RISCV_IOMMU_CAP_T2GPA BIT_ULL(26)
|
#define RISCV_IOMMU_CAP_T2GPA BIT_ULL(26)
|
||||||
@ -80,7 +88,9 @@ struct riscv_iommu_pq_record {
|
|||||||
|
|
||||||
/* 5.4 Features control register (32bits) */
|
/* 5.4 Features control register (32bits) */
|
||||||
#define RISCV_IOMMU_REG_FCTL 0x0008
|
#define RISCV_IOMMU_REG_FCTL 0x0008
|
||||||
|
#define RISCV_IOMMU_FCTL_BE BIT(0)
|
||||||
#define RISCV_IOMMU_FCTL_WSI BIT(1)
|
#define RISCV_IOMMU_FCTL_WSI BIT(1)
|
||||||
|
#define RISCV_IOMMU_FCTL_GXL BIT(2)
|
||||||
|
|
||||||
/* 5.5 Device-directory-table pointer (64bits) */
|
/* 5.5 Device-directory-table pointer (64bits) */
|
||||||
#define RISCV_IOMMU_REG_DDTP 0x0010
|
#define RISCV_IOMMU_REG_DDTP 0x0010
|
||||||
@ -175,6 +185,10 @@ enum {
|
|||||||
|
|
||||||
/* 5.27 Interrupt cause to vector (64bits) */
|
/* 5.27 Interrupt cause to vector (64bits) */
|
||||||
#define RISCV_IOMMU_REG_ICVEC 0x02F8
|
#define RISCV_IOMMU_REG_ICVEC 0x02F8
|
||||||
|
#define RISCV_IOMMU_ICVEC_CIV GENMASK_ULL(3, 0)
|
||||||
|
#define RISCV_IOMMU_ICVEC_FIV GENMASK_ULL(7, 4)
|
||||||
|
#define RISCV_IOMMU_ICVEC_PMIV GENMASK_ULL(11, 8)
|
||||||
|
#define RISCV_IOMMU_ICVEC_PIV GENMASK_ULL(15, 12)
|
||||||
|
|
||||||
/* 5.28 MSI Configuration table (32 * 64bits) */
|
/* 5.28 MSI Configuration table (32 * 64bits) */
|
||||||
#define RISCV_IOMMU_REG_MSI_CONFIG 0x0300
|
#define RISCV_IOMMU_REG_MSI_CONFIG 0x0300
|
||||||
@ -203,6 +217,8 @@ struct riscv_iommu_dc {
|
|||||||
#define RISCV_IOMMU_DC_TC_DTF BIT_ULL(4)
|
#define RISCV_IOMMU_DC_TC_DTF BIT_ULL(4)
|
||||||
#define RISCV_IOMMU_DC_TC_PDTV BIT_ULL(5)
|
#define RISCV_IOMMU_DC_TC_PDTV BIT_ULL(5)
|
||||||
#define RISCV_IOMMU_DC_TC_PRPR BIT_ULL(6)
|
#define RISCV_IOMMU_DC_TC_PRPR BIT_ULL(6)
|
||||||
|
#define RISCV_IOMMU_DC_TC_GADE BIT_ULL(7)
|
||||||
|
#define RISCV_IOMMU_DC_TC_SADE BIT_ULL(8)
|
||||||
#define RISCV_IOMMU_DC_TC_DPE BIT_ULL(9)
|
#define RISCV_IOMMU_DC_TC_DPE BIT_ULL(9)
|
||||||
#define RISCV_IOMMU_DC_TC_SBE BIT_ULL(10)
|
#define RISCV_IOMMU_DC_TC_SBE BIT_ULL(10)
|
||||||
#define RISCV_IOMMU_DC_TC_SXL BIT_ULL(11)
|
#define RISCV_IOMMU_DC_TC_SXL BIT_ULL(11)
|
||||||
@ -309,9 +325,11 @@ enum riscv_iommu_fq_causes {
|
|||||||
|
|
||||||
/* Translation attributes fields */
|
/* Translation attributes fields */
|
||||||
#define RISCV_IOMMU_PC_TA_V BIT_ULL(0)
|
#define RISCV_IOMMU_PC_TA_V BIT_ULL(0)
|
||||||
|
#define RISCV_IOMMU_PC_TA_RESERVED GENMASK_ULL(63, 32)
|
||||||
|
|
||||||
/* First stage context fields */
|
/* First stage context fields */
|
||||||
#define RISCV_IOMMU_PC_FSC_PPN GENMASK_ULL(43, 0)
|
#define RISCV_IOMMU_PC_FSC_PPN GENMASK_ULL(43, 0)
|
||||||
|
#define RISCV_IOMMU_PC_FSC_RESERVED GENMASK_ULL(59, 44)
|
||||||
|
|
||||||
enum riscv_iommu_fq_ttypes {
|
enum riscv_iommu_fq_ttypes {
|
||||||
RISCV_IOMMU_FQ_TTYPE_NONE = 0,
|
RISCV_IOMMU_FQ_TTYPE_NONE = 0,
|
||||||
|
2021
hw/riscv/riscv-iommu.c
Normal file
2021
hw/riscv/riscv-iommu.c
Normal file
File diff suppressed because it is too large
Load Diff
126
hw/riscv/riscv-iommu.h
Normal file
126
hw/riscv/riscv-iommu.h
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* QEMU emulation of an RISC-V IOMMU
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022-2023 Rivos Inc.
|
||||||
|
*
|
||||||
|
* 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 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HW_RISCV_IOMMU_STATE_H
|
||||||
|
#define HW_RISCV_IOMMU_STATE_H
|
||||||
|
|
||||||
|
#include "qom/object.h"
|
||||||
|
#include "hw/riscv/iommu.h"
|
||||||
|
|
||||||
|
struct RISCVIOMMUState {
|
||||||
|
/*< private >*/
|
||||||
|
DeviceState parent_obj;
|
||||||
|
|
||||||
|
/*< public >*/
|
||||||
|
uint32_t version; /* Reported interface version number */
|
||||||
|
uint32_t pid_bits; /* process identifier width */
|
||||||
|
uint32_t bus; /* PCI bus mapping for non-root endpoints */
|
||||||
|
|
||||||
|
uint64_t cap; /* IOMMU supported capabilities */
|
||||||
|
uint64_t fctl; /* IOMMU enabled features */
|
||||||
|
uint64_t icvec_avail_vectors; /* Available interrupt vectors in ICVEC */
|
||||||
|
|
||||||
|
bool enable_off; /* Enable out-of-reset OFF mode (DMA disabled) */
|
||||||
|
bool enable_msi; /* Enable MSI remapping */
|
||||||
|
bool enable_s_stage; /* Enable S/VS-Stage translation */
|
||||||
|
bool enable_g_stage; /* Enable G-Stage translation */
|
||||||
|
|
||||||
|
/* IOMMU Internal State */
|
||||||
|
uint64_t ddtp; /* Validated Device Directory Tree Root Pointer */
|
||||||
|
|
||||||
|
dma_addr_t cq_addr; /* Command queue base physical address */
|
||||||
|
dma_addr_t fq_addr; /* Fault/event queue base physical address */
|
||||||
|
dma_addr_t pq_addr; /* Page request queue base physical address */
|
||||||
|
|
||||||
|
uint32_t cq_mask; /* Command queue index bit mask */
|
||||||
|
uint32_t fq_mask; /* Fault/event queue index bit mask */
|
||||||
|
uint32_t pq_mask; /* Page request queue index bit mask */
|
||||||
|
|
||||||
|
/* interrupt notifier */
|
||||||
|
void (*notify)(RISCVIOMMUState *iommu, unsigned vector);
|
||||||
|
|
||||||
|
/* IOMMU State Machine */
|
||||||
|
QemuThread core_proc; /* Background processing thread */
|
||||||
|
QemuCond core_cond; /* Background processing wake up signal */
|
||||||
|
unsigned core_exec; /* Processing thread execution actions */
|
||||||
|
|
||||||
|
/* IOMMU target address space */
|
||||||
|
AddressSpace *target_as;
|
||||||
|
MemoryRegion *target_mr;
|
||||||
|
|
||||||
|
/* MSI / MRIF access trap */
|
||||||
|
AddressSpace trap_as;
|
||||||
|
MemoryRegion trap_mr;
|
||||||
|
|
||||||
|
GHashTable *ctx_cache; /* Device translation Context Cache */
|
||||||
|
|
||||||
|
/* MMIO Hardware Interface */
|
||||||
|
MemoryRegion regs_mr;
|
||||||
|
uint8_t *regs_rw; /* register state (user write) */
|
||||||
|
uint8_t *regs_wc; /* write-1-to-clear mask */
|
||||||
|
uint8_t *regs_ro; /* read-only mask */
|
||||||
|
|
||||||
|
QLIST_ENTRY(RISCVIOMMUState) iommus;
|
||||||
|
QLIST_HEAD(, RISCVIOMMUSpace) spaces;
|
||||||
|
};
|
||||||
|
|
||||||
|
void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
|
/* private helpers */
|
||||||
|
|
||||||
|
/* Register helper functions */
|
||||||
|
static inline uint32_t riscv_iommu_reg_mod32(RISCVIOMMUState *s,
|
||||||
|
unsigned idx, uint32_t set, uint32_t clr)
|
||||||
|
{
|
||||||
|
uint32_t val = ldl_le_p(s->regs_rw + idx);
|
||||||
|
stl_le_p(s->regs_rw + idx, (val & ~clr) | set);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_iommu_reg_set32(RISCVIOMMUState *s, unsigned idx,
|
||||||
|
uint32_t set)
|
||||||
|
{
|
||||||
|
stl_le_p(s->regs_rw + idx, set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t riscv_iommu_reg_get32(RISCVIOMMUState *s, unsigned idx)
|
||||||
|
{
|
||||||
|
return ldl_le_p(s->regs_rw + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_iommu_reg_mod64(RISCVIOMMUState *s, unsigned idx,
|
||||||
|
uint64_t set, uint64_t clr)
|
||||||
|
{
|
||||||
|
uint64_t val = ldq_le_p(s->regs_rw + idx);
|
||||||
|
stq_le_p(s->regs_rw + idx, (val & ~clr) | set);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void riscv_iommu_reg_set64(RISCVIOMMUState *s, unsigned idx,
|
||||||
|
uint64_t set)
|
||||||
|
{
|
||||||
|
stq_le_p(s->regs_rw + idx, set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t riscv_iommu_reg_get64(RISCVIOMMUState *s,
|
||||||
|
unsigned idx)
|
||||||
|
{
|
||||||
|
return ldq_le_p(s->regs_rw + idx);
|
||||||
|
}
|
||||||
|
#endif
|
14
hw/riscv/trace-events
Normal file
14
hw/riscv/trace-events
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# See documentation at docs/devel/tracing.rst
|
||||||
|
|
||||||
|
# riscv-iommu.c
|
||||||
|
riscv_iommu_new(const char *id, unsigned b, unsigned d, unsigned f) "%s: device attached %04x:%02x.%d"
|
||||||
|
riscv_iommu_flt(const char *id, unsigned b, unsigned d, unsigned f, uint64_t reason, uint64_t iova) "%s: fault %04x:%02x.%u reason: 0x%"PRIx64" iova: 0x%"PRIx64
|
||||||
|
riscv_iommu_pri(const char *id, unsigned b, unsigned d, unsigned f, uint64_t iova) "%s: page request %04x:%02x.%u iova: 0x%"PRIx64
|
||||||
|
riscv_iommu_dma(const char *id, unsigned b, unsigned d, unsigned f, unsigned pasid, const char *dir, uint64_t iova, uint64_t phys) "%s: translate %04x:%02x.%u #%u %s 0x%"PRIx64" -> 0x%"PRIx64
|
||||||
|
riscv_iommu_msi(const char *id, unsigned b, unsigned d, unsigned f, uint64_t iova, uint64_t phys) "%s: translate %04x:%02x.%u MSI 0x%"PRIx64" -> 0x%"PRIx64
|
||||||
|
riscv_iommu_mrif_notification(const char *id, uint32_t nid, uint64_t phys) "%s: sent MRIF notification 0x%x to 0x%"PRIx64
|
||||||
|
riscv_iommu_cmd(const char *id, uint64_t l, uint64_t u) "%s: command 0x%"PRIx64" 0x%"PRIx64
|
||||||
|
riscv_iommu_notifier_add(const char *id) "%s: dev-iotlb notifier added"
|
||||||
|
riscv_iommu_notifier_del(const char *id) "%s: dev-iotlb notifier removed"
|
||||||
|
riscv_iommu_notify_int_vector(uint32_t cause, uint32_t vector) "Interrupt cause 0x%x sent via vector 0x%x"
|
||||||
|
riscv_iommu_icvec_write(uint32_t orig, uint32_t actual) "ICVEC write: incoming 0x%x actual 0x%x"
|
1
hw/riscv/trace.h
Normal file
1
hw/riscv/trace.h
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "trace/trace-hw_riscv.h"
|
36
include/hw/riscv/iommu.h
Normal file
36
include/hw/riscv/iommu.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* QEMU emulation of an RISC-V IOMMU
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022-2023 Rivos Inc.
|
||||||
|
*
|
||||||
|
* 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 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HW_RISCV_IOMMU_H
|
||||||
|
#define HW_RISCV_IOMMU_H
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qom/object.h"
|
||||||
|
|
||||||
|
#define TYPE_RISCV_IOMMU "riscv-iommu"
|
||||||
|
OBJECT_DECLARE_SIMPLE_TYPE(RISCVIOMMUState, RISCV_IOMMU)
|
||||||
|
typedef struct RISCVIOMMUState RISCVIOMMUState;
|
||||||
|
|
||||||
|
#define TYPE_RISCV_IOMMU_MEMORY_REGION "riscv-iommu-mr"
|
||||||
|
typedef struct RISCVIOMMUSpace RISCVIOMMUSpace;
|
||||||
|
|
||||||
|
#define TYPE_RISCV_IOMMU_PCI "riscv-iommu-pci"
|
||||||
|
OBJECT_DECLARE_SIMPLE_TYPE(RISCVIOMMUStatePci, RISCV_IOMMU_PCI)
|
||||||
|
typedef struct RISCVIOMMUStatePci RISCVIOMMUStatePci;
|
||||||
|
|
||||||
|
#endif
|
@ -3475,6 +3475,7 @@ if have_system
|
|||||||
'hw/pci-host',
|
'hw/pci-host',
|
||||||
'hw/ppc',
|
'hw/ppc',
|
||||||
'hw/rtc',
|
'hw/rtc',
|
||||||
|
'hw/riscv',
|
||||||
'hw/s390x',
|
'hw/s390x',
|
||||||
'hw/scsi',
|
'hw/scsi',
|
||||||
'hw/sd',
|
'hw/sd',
|
||||||
|
Loading…
Reference in New Issue
Block a user