aboutsummaryrefslogtreecommitdiff
path: root/hw/riscv/riscv-iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/riscv/riscv-iommu.c')
-rw-r--r--hw/riscv/riscv-iommu.c137
1 files changed, 100 insertions, 37 deletions
diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c
index 41f3e6c..8bf920d 100644
--- a/hw/riscv/riscv-iommu.c
+++ b/hw/riscv/riscv-iommu.c
@@ -94,10 +94,9 @@ static uint8_t riscv_iommu_get_icvec_vector(uint32_t icvec, uint32_t vec_type)
static void riscv_iommu_notify(RISCVIOMMUState *s, int vec_type)
{
- const uint32_t fctl = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_FCTL);
uint32_t ipsr, icvec, vector;
- if (fctl & RISCV_IOMMU_FCTL_WSI || !s->notify) {
+ if (!s->notify) {
return;
}
@@ -392,9 +391,26 @@ static int riscv_iommu_spa_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
/* Address range check before first level lookup */
if (!sc[pass].step) {
- const uint64_t va_mask = (1ULL << (va_skip + va_bits)) - 1;
- if ((addr & va_mask) != addr) {
- return RISCV_IOMMU_FQ_CAUSE_DMA_DISABLED;
+ const uint64_t va_len = va_skip + va_bits;
+ const uint64_t va_mask = (1ULL << va_len) - 1;
+
+ if (pass == S_STAGE && va_len > 32) {
+ target_ulong mask, masked_msbs;
+
+ mask = (1L << (TARGET_LONG_BITS - (va_len - 1))) - 1;
+ masked_msbs = (addr >> (va_len - 1)) & mask;
+
+ if (masked_msbs != 0 && masked_msbs != mask) {
+ return (iotlb->perm & IOMMU_WO) ?
+ RISCV_IOMMU_FQ_CAUSE_WR_FAULT_S :
+ RISCV_IOMMU_FQ_CAUSE_RD_FAULT_S;
+ }
+ } else {
+ if ((addr & va_mask) != addr) {
+ return (iotlb->perm & IOMMU_WO) ?
+ RISCV_IOMMU_FQ_CAUSE_WR_FAULT_VS :
+ RISCV_IOMMU_FQ_CAUSE_RD_FAULT_VS;
+ }
}
}
@@ -2113,11 +2129,53 @@ static const MemoryRegionOps riscv_iommu_trap_ops = {
}
};
+void riscv_iommu_set_cap_igs(RISCVIOMMUState *s, riscv_iommu_igs_mode mode)
+{
+ s->cap = set_field(s->cap, RISCV_IOMMU_CAP_IGS, mode);
+}
+
+static void riscv_iommu_instance_init(Object *obj)
+{
+ RISCVIOMMUState *s = RISCV_IOMMU(obj);
+
+ /* Enable translation debug interface */
+ s->cap = RISCV_IOMMU_CAP_DBG;
+
+ /* Report QEMU target physical address space limits */
+ s->cap = set_field(s->cap, RISCV_IOMMU_CAP_PAS,
+ TARGET_PHYS_ADDR_SPACE_BITS);
+
+ /* TODO: method to report supported PID bits */
+ s->pid_bits = 8; /* restricted to size of MemTxAttrs.pid */
+ s->cap |= RISCV_IOMMU_CAP_PD8;
+
+ /* register storage */
+ s->regs_rw = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
+ s->regs_ro = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
+ s->regs_wc = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
+
+ /* Mark all registers read-only */
+ memset(s->regs_ro, 0xff, RISCV_IOMMU_REG_SIZE);
+
+ /* Device translation context cache */
+ s->ctx_cache = g_hash_table_new_full(riscv_iommu_ctx_hash,
+ riscv_iommu_ctx_equal,
+ g_free, NULL);
+
+ s->iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash,
+ riscv_iommu_iot_equal,
+ g_free, NULL);
+
+ s->iommus.le_next = NULL;
+ s->iommus.le_prev = NULL;
+ QLIST_INIT(&s->spaces);
+}
+
static void riscv_iommu_realize(DeviceState *dev, Error **errp)
{
RISCVIOMMUState *s = RISCV_IOMMU(dev);
- s->cap = s->version & RISCV_IOMMU_CAP_VERSION;
+ s->cap |= s->version & RISCV_IOMMU_CAP_VERSION;
if (s->enable_msi) {
s->cap |= RISCV_IOMMU_CAP_MSI_FLAT | RISCV_IOMMU_CAP_MSI_MRIF;
}
@@ -2132,29 +2190,11 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
s->cap |= RISCV_IOMMU_CAP_SV32X4 | RISCV_IOMMU_CAP_SV39X4 |
RISCV_IOMMU_CAP_SV48X4 | RISCV_IOMMU_CAP_SV57X4;
}
- /* Enable translation debug interface */
- s->cap |= RISCV_IOMMU_CAP_DBG;
-
- /* Report QEMU target physical address space limits */
- s->cap = set_field(s->cap, RISCV_IOMMU_CAP_PAS,
- TARGET_PHYS_ADDR_SPACE_BITS);
-
- /* TODO: method to report supported PID bits */
- s->pid_bits = 8; /* restricted to size of MemTxAttrs.pid */
- s->cap |= RISCV_IOMMU_CAP_PD8;
/* Out-of-reset translation mode: OFF (DMA disabled) BARE (passthrough) */
s->ddtp = set_field(0, RISCV_IOMMU_DDTP_MODE, s->enable_off ?
RISCV_IOMMU_DDTP_MODE_OFF : RISCV_IOMMU_DDTP_MODE_BARE);
- /* register storage */
- s->regs_rw = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
- s->regs_ro = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
- s->regs_wc = g_new0(uint8_t, RISCV_IOMMU_REG_SIZE);
-
- /* Mark all registers read-only */
- memset(s->regs_ro, 0xff, RISCV_IOMMU_REG_SIZE);
-
/*
* Register complete MMIO space, including MSI/PBA registers.
* Note, PCIDevice implementation will add overlapping MR for MSI/PBA,
@@ -2212,19 +2252,6 @@ static void riscv_iommu_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&s->trap_mr, OBJECT(dev), &riscv_iommu_trap_ops, s,
"riscv-iommu-trap", ~0ULL);
address_space_init(&s->trap_as, &s->trap_mr, "riscv-iommu-trap-as");
-
- /* Device translation context cache */
- s->ctx_cache = g_hash_table_new_full(riscv_iommu_ctx_hash,
- riscv_iommu_ctx_equal,
- g_free, NULL);
-
- s->iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash,
- riscv_iommu_iot_equal,
- g_free, NULL);
-
- s->iommus.le_next = NULL;
- s->iommus.le_prev = NULL;
- QLIST_INIT(&s->spaces);
}
static void riscv_iommu_unrealize(DeviceState *dev)
@@ -2235,6 +2262,41 @@ static void riscv_iommu_unrealize(DeviceState *dev)
g_hash_table_unref(s->ctx_cache);
}
+void riscv_iommu_reset(RISCVIOMMUState *s)
+{
+ uint32_t reg_clr;
+ int ddtp_mode;
+
+ /*
+ * Clear DDTP while setting DDTP_mode back to user
+ * initial setting.
+ */
+ ddtp_mode = s->enable_off ?
+ RISCV_IOMMU_DDTP_MODE_OFF : RISCV_IOMMU_DDTP_MODE_BARE;
+ s->ddtp = set_field(0, RISCV_IOMMU_DDTP_MODE, ddtp_mode);
+ riscv_iommu_reg_set64(s, RISCV_IOMMU_REG_DDTP, s->ddtp);
+
+ reg_clr = RISCV_IOMMU_CQCSR_CQEN | RISCV_IOMMU_CQCSR_CIE |
+ RISCV_IOMMU_CQCSR_CQON | RISCV_IOMMU_CQCSR_BUSY;
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_CQCSR, 0, reg_clr);
+
+ reg_clr = RISCV_IOMMU_FQCSR_FQEN | RISCV_IOMMU_FQCSR_FIE |
+ RISCV_IOMMU_FQCSR_FQON | RISCV_IOMMU_FQCSR_BUSY;
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_FQCSR, 0, reg_clr);
+
+ reg_clr = RISCV_IOMMU_PQCSR_PQEN | RISCV_IOMMU_PQCSR_PIE |
+ RISCV_IOMMU_PQCSR_PQON | RISCV_IOMMU_PQCSR_BUSY;
+ riscv_iommu_reg_mod32(s, RISCV_IOMMU_REG_PQCSR, 0, reg_clr);
+
+ riscv_iommu_reg_mod64(s, RISCV_IOMMU_REG_TR_REQ_CTL, 0,
+ RISCV_IOMMU_TR_REQ_CTL_GO_BUSY);
+
+ riscv_iommu_reg_set32(s, RISCV_IOMMU_REG_IPSR, 0);
+
+ g_hash_table_remove_all(s->ctx_cache);
+ g_hash_table_remove_all(s->iot_cache);
+}
+
static const Property riscv_iommu_properties[] = {
DEFINE_PROP_UINT32("version", RISCVIOMMUState, version,
RISCV_IOMMU_SPEC_DOT_VER),
@@ -2265,6 +2327,7 @@ static const TypeInfo riscv_iommu_info = {
.name = TYPE_RISCV_IOMMU,
.parent = TYPE_DEVICE,
.instance_size = sizeof(RISCVIOMMUState),
+ .instance_init = riscv_iommu_instance_init,
.class_init = riscv_iommu_class_init,
};