[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v1 25/27] target/riscv: Implement second stage MMU
From: |
Alistair Francis |
Subject: |
[Qemu-devel] [PATCH v1 25/27] target/riscv: Implement second stage MMU |
Date: |
Fri, 7 Jun 2019 14:56:39 -0700 |
Signed-off-by: Alistair Francis <address@hidden>
---
target/riscv/cpu_helper.c | 87 +++++++++++++++++++++++++++++++++++----
1 file changed, 78 insertions(+), 9 deletions(-)
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 6ff4272da2..ece3eadf66 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -293,13 +293,40 @@ static int get_physical_address(CPURISCVState *env,
hwaddr *physical,
* (riscv_cpu_do_interrupt) is correct */
int mode = mmu_idx;
-
+ bool use_background = false;
+
+ /*
+ * Check if we should use the background registers for the two
+ * stage translation. We don't need to check if we actually need
+ * two stage translation as that happened before this function
+ * was called. Background registers will be used if the guest has
+ * forced a two stage translation to be on (in HS or M mode).
+ */
if (mode == PRV_M && access_type != MMU_INST_FETCH) {
if (get_field(env->mstatus, MSTATUS_MPRV)) {
mode = get_field(env->mstatus, MSTATUS_MPP);
+
+ if (riscv_has_ext(env, RVH) &&
+ get_field(env->mstatus, MSTATUS_MPV)) {
+ use_background = true;
+ }
+ }
+ }
+
+ if (mode == PRV_S && access_type != MMU_INST_FETCH &&
+ riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
+ if (get_field(env->hstatus, HSTATUS_SPRV)) {
+ mode = get_field(env->mstatus, SSTATUS_SPP);
+ use_background = true;
}
}
+ if (first_stage == false) {
+ /* We are in stage 2 translation, this is similar to stage 1. */
+ /* Stage 2 is always taken as U-mode */
+ mode = PRV_U;
+ }
+
if (mode == PRV_M || !riscv_feature(env, RISCV_FEATURE_MMU)) {
*physical = addr;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
@@ -309,13 +336,30 @@ static int get_physical_address(CPURISCVState *env,
hwaddr *physical,
*prot = 0;
target_ulong base;
- int levels, ptidxbits, ptesize, vm, sum;
- int mxr = get_field(env->mstatus, MSTATUS_MXR);
+ int levels, ptidxbits, ptesize, vm, sum, mxr, widened;
+
+ if (first_stage == true) {
+ mxr = get_field(env->mstatus, MSTATUS_MXR);
+ } else {
+ mxr = get_field(env->bsstatus, MSTATUS_MXR);
+ }
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- base = get_field(env->satp, SATP_PPN) << PGSHIFT;
+ if (first_stage == true) {
+ if (use_background) {
+ base = get_field(env->bsatp, SATP_PPN) << PGSHIFT;
+ vm = get_field(env->bsatp, SATP_MODE);
+ } else {
+ base = get_field(env->satp, SATP_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP_MODE);
+ }
+ widened = 0;
+ } else {
+ base = get_field(env->hgatp, HGATP_PPN) << PGSHIFT;
+ vm = get_field(env->hgatp, HGATP_MODE);
+ widened = 2;
+ }
sum = get_field(env->mstatus, MSTATUS_SUM);
- vm = get_field(env->satp, SATP_MODE);
switch (vm) {
case VM_1_10_SV32:
levels = 2; ptidxbits = 10; ptesize = 4; break;
@@ -333,6 +377,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr
*physical,
g_assert_not_reached();
}
} else {
+ widened = 0;
base = env->sptbr << PGSHIFT;
sum = !get_field(env->mstatus, MSTATUS_PUM);
vm = get_field(env->mstatus, MSTATUS_VM);
@@ -353,7 +398,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr
*physical,
}
CPUState *cs = CPU(riscv_env_get_cpu(env));
- int va_bits = PGSHIFT + levels * ptidxbits;
+ int va_bits = PGSHIFT + levels * ptidxbits + widened;
target_ulong mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1;
target_ulong masked_msbs = (addr >> (va_bits - 1)) & mask;
if (masked_msbs != 0 && masked_msbs != mask) {
@@ -367,11 +412,30 @@ static int get_physical_address(CPURISCVState *env,
hwaddr *physical,
restart:
#endif
for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
- target_ulong idx = (addr >> (PGSHIFT + ptshift)) &
+ target_ulong idx;
+ if (i == 0) {
+ idx = (addr >> (PGSHIFT + ptshift)) &
+ ((1 << (ptidxbits + widened)) - 1);
+ } else {
+ idx = (addr >> (PGSHIFT + ptshift)) &
((1 << ptidxbits) - 1);
+ }
/* check that physical address of PTE is legal */
- target_ulong pte_addr = base + idx * ptesize;
+ target_ulong pte_addr;
+
+ if (two_stage && first_stage) {
+ hwaddr vbase;
+
+ /* Do the second stage translation on the base PTE address. */
+ get_physical_address(env, &vbase, prot, base, access_type,
+ mmu_idx, false, true);
+
+ pte_addr = vbase + idx * ptesize;
+ } else {
+ pte_addr = base + idx * ptesize;
+ }
+
#if defined(TARGET_RISCV32)
target_ulong pte = ldl_phys(cs->as, pte_addr);
#elif defined(TARGET_RISCV64)
@@ -457,7 +521,12 @@ restart:
/* for superpage mappings, make a fake leaf PTE for the TLB's
benefit. */
target_ulong vpn = addr >> PGSHIFT;
- *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT;
+ if (i == 0) {
+ *physical = (ppn | (vpn & ((1L << (ptshift + widened)) - 1)))
<<
+ PGSHIFT;
+ } else {
+ *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT;
+ }
/* set permissions on the TLB entry */
if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) {
--
2.21.0
- [Qemu-devel] [PATCH v1 13/27] target/ricsv: Flush the TLB on virtulisation mode changes, (continued)
- [Qemu-devel] [PATCH v1 13/27] target/ricsv: Flush the TLB on virtulisation mode changes, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 14/27] target/riscv: Generate illegal instruction on WFI when V=1, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 18/27] target/riscv: Add Hypervisor trap return support, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 15/27] riscv: plic: Remove unused interrupt functions, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 17/27] target/riscv: Add hypvervisor trap support, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 11/27] target/riscv: Add background CSRs accesses, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 16/27] riscv: plic: Always set sip.SEIP bit for HS, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 19/27] target/riscv: Add hfence instructions, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 22/27] target/riscv: Respect MPRV and SPRV for floating point ops, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 21/27] target/riscv: Mark both sstatus and bsstatus as dirty, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 25/27] target/riscv: Implement second stage MMU,
Alistair Francis <=
- [Qemu-devel] [PATCH v1 24/27] target/riscv: Allow specifying number of MMU stages, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 23/27] target/riscv: Allow specifying MMU stage, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 20/27] target/riscv: Disable guest FP support based on backgrond status, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 27/27] target/riscv: Allow enabling the Hypervisor extension, Alistair Francis, 2019/06/07
- [Qemu-devel] [PATCH v1 26/27] target/riscv: Call the second stage MMU in virtualisation mode, Alistair Francis, 2019/06/07