From: Alistair Francis <alistair.francis@wdc.com>
To: qemu-devel@nongnu.org, qemu-riscv@nongnu.org
Cc: alistair.francis@wdc.com, palmer@dabbelt.com, alistair23@gmail.com
Subject: [PATCH v2 30/35] target/riscv: Implement second stage MMU
Date: Fri, 31 Jan 2020 17:02:56 -0800 [thread overview]
Message-ID: <552ea58f47f89564da0d25851c3ac36937455c7f.1580518859.git.alistair.francis@wdc.com> (raw)
In-Reply-To: <cover.1580518859.git.alistair.francis@wdc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com>
---
target/riscv/cpu.h | 1 +
target/riscv/cpu_helper.c | 193 ++++++++++++++++++++++++++++++++++----
2 files changed, 175 insertions(+), 19 deletions(-)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index aa04e5cca7..a8534fdf2b 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -104,6 +104,7 @@ struct CPURISCVState {
target_ulong frm;
target_ulong badaddr;
+ target_ulong guest_phys_fault_addr;
target_ulong priv_ver;
target_ulong misa;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index cd2d9341b9..5f96631637 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -285,11 +285,12 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
* @mmu_idx: Indicates current privilege level
* @first_stage: Are we in first stage translation?
* Second stage is used for hypervisor guest translation
+ * @two_stage: Are we going to perform two stage translation
*/
static int get_physical_address(CPURISCVState *env, hwaddr *physical,
int *prot, target_ulong addr,
int access_type, int mmu_idx,
- bool first_stage)
+ bool first_stage, bool two_stage)
{
/* NOTE: the env->pc value visible here will not be
* correct, but the value visible to the exception handler
@@ -297,13 +298,40 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
MemTxResult res;
MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
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;
@@ -313,13 +341,30 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
*prot = 0;
hwaddr 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->vsstatus, MSTATUS_MXR);
+ }
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
+ if (first_stage == true) {
+ if (use_background) {
+ base = (hwaddr)get_field(env->vsatp, SATP_PPN) << PGSHIFT;
+ vm = get_field(env->vsatp, SATP_MODE);
+ } else {
+ base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
+ vm = get_field(env->satp, SATP_MODE);
+ }
+ widened = 0;
+ } else {
+ base = (hwaddr)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;
@@ -337,6 +382,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
g_assert_not_reached();
}
} else {
+ widened = 0;
base = (hwaddr)(env->sptbr) << PGSHIFT;
sum = !get_field(env->mstatus, MSTATUS_PUM);
vm = get_field(env->mstatus, MSTATUS_VM);
@@ -357,9 +403,16 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
}
CPUState *cs = env_cpu(env);
- int va_bits = PGSHIFT + levels * ptidxbits;
- target_ulong mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1;
- target_ulong masked_msbs = (addr >> (va_bits - 1)) & mask;
+ int va_bits = PGSHIFT + levels * ptidxbits + widened;
+ target_ulong mask, masked_msbs;
+
+ if (TARGET_LONG_BITS > (va_bits - 1)) {
+ mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1;
+ } else {
+ mask = 0;
+ }
+ masked_msbs = (addr >> (va_bits - 1)) & mask;
+
if (masked_msbs != 0 && masked_msbs != mask) {
return TRANSLATE_FAIL;
}
@@ -371,11 +424,29 @@ 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 */
- hwaddr pte_addr = base + idx * ptesize;
+ hwaddr 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 (riscv_feature(env, RISCV_FEATURE_PMP) &&
!pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong),
@@ -472,7 +543,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)) {
@@ -529,14 +605,23 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
RISCVCPU *cpu = RISCV_CPU(cs);
+ CPURISCVState *env = &cpu->env;
hwaddr phys_addr;
int prot;
int mmu_idx = cpu_mmu_index(&cpu->env, false);
- if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx,
- true)) {
+ if (get_physical_address(env, &phys_addr, &prot, addr, 0, mmu_idx,
+ true, riscv_cpu_virt_enabled(env))) {
return -1;
}
+
+ if (riscv_cpu_virt_enabled(env)) {
+ if (get_physical_address(env, &phys_addr, &prot, phys_addr,
+ 0, mmu_idx, false, true)) {
+ return -1;
+ }
+ }
+
return phys_addr;
}
@@ -590,17 +675,37 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
#ifndef CONFIG_USER_ONLY
+ vaddr im_address;
hwaddr pa = 0;
int prot;
bool pmp_violation = false;
+ bool m_mode_two_stage = false;
+ bool hs_mode_two_stage = false;
+ bool first_stage_error = true;
int ret = TRANSLATE_FAIL;
int mode = mmu_idx;
+ env->guest_phys_fault_addr = 0;
+
qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
__func__, address, access_type, mmu_idx);
- ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx,
- true);
+ /*
+ * Determine if we are in M mode and MPRV is set or in HS mode and SPRV is
+ * set and we want to access a virtulisation address.
+ */
+ if (riscv_has_ext(env, RVH)) {
+ m_mode_two_stage = env->priv == PRV_M &&
+ access_type != MMU_INST_FETCH &&
+ get_field(env->mstatus, MSTATUS_MPRV) &&
+ get_field(env->mstatus, MSTATUS_MPV);
+
+ hs_mode_two_stage = env->priv == PRV_S &&
+ !riscv_cpu_virt_enabled(env) &&
+ access_type != MMU_INST_FETCH &&
+ get_field(env->hstatus, HSTATUS_SPRV) &&
+ get_field(env->hstatus, HSTATUS_SPV);
+ }
if (mode == PRV_M && access_type != MMU_INST_FETCH) {
if (get_field(env->mstatus, MSTATUS_MPRV)) {
@@ -608,9 +713,55 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
}
}
- qemu_log_mask(CPU_LOG_MMU,
- "%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
- " prot %d\n", __func__, address, ret, pa, prot);
+ if (riscv_cpu_virt_enabled(env) || m_mode_two_stage || hs_mode_two_stage) {
+ /* Two stage lookup */
+ ret = get_physical_address(env, &pa, &prot, address, access_type,
+ mmu_idx, true, true);
+
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s 1st-stage address=%" VADDR_PRIx " ret %d physical "
+ TARGET_FMT_plx " prot %d\n",
+ __func__, address, ret, pa, prot);
+
+ if (ret != TRANSLATE_FAIL) {
+ /* Second stage lookup */
+ im_address = pa;
+
+ ret = get_physical_address(env, &pa, &prot, im_address,
+ access_type, mmu_idx, false, true);
+
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s 2nd-stage address=%" VADDR_PRIx " ret %d physical "
+ TARGET_FMT_plx " prot %d\n",
+ __func__, im_address, ret, pa, prot);
+
+ if (riscv_feature(env, RISCV_FEATURE_PMP) &&
+ (ret == TRANSLATE_SUCCESS) &&
+ !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
+ ret = TRANSLATE_PMP_FAIL;
+ }
+
+ if (ret != TRANSLATE_SUCCESS) {
+ /*
+ * Guest physical address translation failed, this is a HS
+ * level exception
+ */
+ first_stage_error = false;
+ env->guest_phys_fault_addr = (im_address |
+ (address &
+ (TARGET_PAGE_SIZE - 1))) >> 2;
+ }
+ }
+ } else {
+ /* Single stage lookup */
+ ret = get_physical_address(env, &pa, &prot, address, access_type,
+ mmu_idx, true, false);
+
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s address=%" VADDR_PRIx " ret %d physical "
+ TARGET_FMT_plx " prot %d\n",
+ __func__, address, ret, pa, prot);
+ }
if (riscv_feature(env, RISCV_FEATURE_PMP) &&
(ret == TRANSLATE_SUCCESS) &&
@@ -620,6 +771,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
if (ret == TRANSLATE_PMP_FAIL) {
pmp_violation = true;
}
+
if (ret == TRANSLATE_SUCCESS) {
tlb_set_page(cs, address & TARGET_PAGE_MASK, pa & TARGET_PAGE_MASK,
prot, mmu_idx, TARGET_PAGE_SIZE);
@@ -627,9 +779,12 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
} else if (probe) {
return false;
} else {
- raise_mmu_exception(env, address, access_type, pmp_violation, true);
+ raise_mmu_exception(env, address, access_type, pmp_violation, first_stage_error);
riscv_raise_exception(env, cs->exception_index, retaddr);
}
+
+ return true;
+
#else
switch (access_type) {
case MMU_INST_FETCH:
--
2.25.0
next prev parent reply other threads:[~2020-02-01 1:32 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-01 1:01 [PATCH v2 00/35] Add RISC-V Hypervisor Extension v0.5 Alistair Francis
2020-02-01 1:01 ` [PATCH v2 01/35] target/riscv: Convert MIP CSR to target_ulong Alistair Francis
2020-02-01 1:01 ` [PATCH v2 02/35] target/riscv: Add the Hypervisor extension Alistair Francis
2020-02-01 1:01 ` [PATCH v2 03/35] target/riscv: Add the Hypervisor CSRs to CPUState Alistair Francis
2020-02-01 1:01 ` [PATCH v2 04/35] target/riscv: Add support for the new execption numbers Alistair Francis
2020-02-01 1:01 ` [PATCH v2 05/35] target/riscv: Rename the H irqs to VS irqs Alistair Francis
2020-02-01 1:01 ` [PATCH v2 06/35] target/riscv: Add the virtulisation mode Alistair Francis
2020-02-01 1:01 ` [PATCH v2 07/35] target/riscv: Add the force HS exception mode Alistair Francis
2020-02-10 21:46 ` Palmer Dabbelt
2020-02-01 1:01 ` [PATCH v2 08/35] target/riscv: Fix CSR perm checking for HS mode Alistair Francis
2020-02-01 1:01 ` [PATCH v2 09/35] target/riscv: Print priv and virt in disas log Alistair Francis
2020-02-01 1:02 ` [PATCH v2 10/35] target/riscv: Dump Hypervisor registers if enabled Alistair Francis
2020-02-01 1:02 ` [PATCH v2 11/35] target/riscv: Add Hypervisor CSR access functions Alistair Francis
2020-02-01 1:02 ` [PATCH v2 12/35] target/riscv: Add Hypervisor virtual CSRs accesses Alistair Francis
2020-02-01 1:02 ` [PATCH v2 13/35] target/riscv: Add Hypervisor machine " Alistair Francis
2020-02-01 1:02 ` [PATCH v2 14/35] target/riscv: Add virtual register swapping function Alistair Francis
2020-02-01 1:02 ` [PATCH v2 15/35] target/riscv: Set VS bits in mideleg for Hyp extension Alistair Francis
2020-02-01 1:02 ` [PATCH v2 16/35] target/riscv: Extend the MIE CSR to support virtulisation Alistair Francis
2020-02-01 1:02 ` [PATCH v2 17/35] target/riscv: Extend the SIP " Alistair Francis
2020-02-01 1:02 ` [PATCH v2 18/35] target/riscv: Add support for virtual interrupt setting Alistair Francis
2020-02-01 1:02 ` [PATCH v2 19/35] target/ricsv: Flush the TLB on virtulisation mode changes Alistair Francis
2020-02-01 1:02 ` [PATCH v2 20/35] target/riscv: Generate illegal instruction on WFI when V=1 Alistair Francis
2020-02-01 1:02 ` [PATCH v2 21/35] target/riscv: Add hypvervisor trap support Alistair Francis
2020-02-12 20:03 ` Palmer Dabbelt
2020-02-01 1:02 ` [PATCH v2 22/35] target/riscv: Add Hypervisor trap return support Alistair Francis
2020-02-01 1:02 ` [PATCH v2 23/35] target/riscv: Add hfence instructions Alistair Francis
2020-02-01 1:02 ` [PATCH v2 24/35] target/riscv: Remove the hret instruction Alistair Francis
2020-02-01 1:02 ` [PATCH v2 25/35] target/riscv: Only set TB flags with FP status if enabled Alistair Francis
2020-02-13 18:31 ` Palmer Dabbelt
2020-02-01 1:02 ` [PATCH v2 26/35] target/riscv: Disable guest FP support based on virtual status Alistair Francis
2020-02-13 18:39 ` Palmer Dabbelt
2020-02-01 1:02 ` [PATCH v2 27/35] target/riscv: Mark both sstatus and msstatus_hs as dirty Alistair Francis
2020-02-13 18:44 ` Palmer Dabbelt
2020-02-01 1:02 ` [PATCH v2 28/35] target/riscv: Respect MPRV and SPRV for floating point ops Alistair Francis
2020-02-01 1:02 ` [PATCH v2 29/35] target/riscv: Allow specifying MMU stage Alistair Francis
2020-02-01 1:02 ` Alistair Francis [this message]
2020-02-01 1:02 ` [PATCH v2 31/35] target/riscv: Raise the new execptions when 2nd stage translation fails Alistair Francis
2020-02-01 1:03 ` [PATCH v2 32/35] target/riscv: Set htval and mtval2 on execptions Alistair Francis
2020-02-01 1:03 ` [PATCH v2 33/35] target/riscv: Add support for the 32-bit MSTATUSH CSR Alistair Francis
2020-02-17 19:04 ` Palmer Dabbelt
2020-02-01 1:03 ` [PATCH v2 34/35] target/riscv: Add the MSTATUS_MPV_ISSET helper macro Alistair Francis
2020-02-01 1:03 ` [PATCH v2 35/35] target/riscv: Allow enabling the Hypervisor extension Alistair Francis
2020-02-10 18:50 ` [PATCH v2 00/35] Add RISC-V Hypervisor Extension v0.5 Palmer Dabbelt
2020-02-10 19:52 ` Alistair Francis
2020-02-17 19:11 ` Palmer Dabbelt
2020-02-18 18:11 ` Alistair Francis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=552ea58f47f89564da0d25851c3ac36937455c7f.1580518859.git.alistair.francis@wdc.com \
--to=alistair.francis@wdc.com \
--cc=alistair23@gmail.com \
--cc=palmer@dabbelt.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).