All of lore.kernel.org
 help / color / mirror / Atom feed
From: Palmer Dabbelt <palmerdabbelt@google.com>
To: Peter Maydell <peter.maydell@linaro.org>
Cc: qemu-riscv@nongnu.org,          qemu-devel@nongnu.org,
	Alistair Francis <alistair.francis@wdc.com>,
	Palmer Dabbelt <palmerdabbelt@google.com>
Subject: [PULL 30/38] target/riscv: Implement second stage MMU
Date: Mon,  2 Mar 2020 16:48:40 -0800	[thread overview]
Message-ID: <20200303004848.136788-31-palmerdabbelt@google.com> (raw)
In-Reply-To: <20200303004848.136788-1-palmerdabbelt@google.com>

From: Alistair Francis <alistair.francis@wdc.com>

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Palmer Dabbelt <palmerdabbelt@google.com>
Signed-off-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 8ae1038bcd..584b0c71fb 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)) {
@@ -531,14 +607,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;
 }
 
@@ -592,17 +677,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)) {
@@ -610,9 +715,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) &&
@@ -622,6 +773,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);
@@ -629,9 +781,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.265.gbab2e86ba0-goog



  parent reply	other threads:[~2020-03-03  1:02 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-03  0:48 [PULL] RISC-V Patches for the 5.0 Soft Freeze, Part 3 Palmer Dabbelt
2020-03-03  0:48 ` [PULL 01/38] target/riscv: Convert MIP CSR to target_ulong Palmer Dabbelt
2020-03-03  0:48 ` [PULL 02/38] target/riscv: Add the Hypervisor extension Palmer Dabbelt
2020-03-03  0:48 ` [PULL 03/38] target/riscv: Add the Hypervisor CSRs to CPUState Palmer Dabbelt
2020-03-03  0:48 ` [PULL 04/38] target/riscv: Add support for the new execption numbers Palmer Dabbelt
2020-03-05 16:44   ` Peter Maydell
2020-03-05 16:44     ` Peter Maydell
2020-03-05 16:46     ` Alistair Francis
2020-03-05 16:46       ` Alistair Francis
2020-03-05 16:51     ` Palmer Dabbelt
2020-03-03  0:48 ` [PULL 05/38] target/riscv: Rename the H irqs to VS irqs Palmer Dabbelt
2020-03-03  0:48 ` [PULL 06/38] target/riscv: Add the virtulisation mode Palmer Dabbelt
2020-03-03  0:48 ` [PULL 07/38] target/riscv: Add the force HS exception mode Palmer Dabbelt
2020-03-03  0:48 ` [PULL 08/38] target/riscv: Fix CSR perm checking for HS mode Palmer Dabbelt
2020-03-03  0:48 ` [PULL 09/38] target/riscv: Print priv and virt in disas log Palmer Dabbelt
2020-03-03  0:48 ` [PULL 10/38] target/riscv: Dump Hypervisor registers if enabled Palmer Dabbelt
2020-03-03  0:48 ` [PULL 11/38] target/riscv: Add Hypervisor CSR access functions Palmer Dabbelt
2020-03-03  0:48 ` [PULL 12/38] target/riscv: Add Hypervisor virtual CSRs accesses Palmer Dabbelt
2020-03-03  0:48 ` [PULL 13/38] target/riscv: Add Hypervisor machine " Palmer Dabbelt
2020-03-03  0:48 ` [PULL 14/38] target/riscv: Add virtual register swapping function Palmer Dabbelt
2020-03-03  0:48 ` [PULL 15/38] target/riscv: Set VS bits in mideleg for Hyp extension Palmer Dabbelt
2020-03-03  0:48 ` [PULL 16/38] target/riscv: Extend the MIE CSR to support virtulisation Palmer Dabbelt
2020-03-03  0:48 ` [PULL 17/38] target/riscv: Extend the SIP " Palmer Dabbelt
2020-03-03  0:48 ` [PULL 18/38] target/riscv: Add support for virtual interrupt setting Palmer Dabbelt
2020-03-03  0:48 ` [PULL 19/38] target/ricsv: Flush the TLB on virtulisation mode changes Palmer Dabbelt
2020-03-03  0:48 ` [PULL 20/38] target/riscv: Generate illegal instruction on WFI when V=1 Palmer Dabbelt
2020-03-03  0:48 ` [PULL 21/38] target/riscv: Add hypvervisor trap support Palmer Dabbelt
2020-03-03  0:48 ` [PULL 22/38] target/riscv: Add Hypervisor trap return support Palmer Dabbelt
2020-03-03  0:48 ` [PULL 23/38] target/riscv: Add hfence instructions Palmer Dabbelt
2020-03-03  0:48 ` [PULL 24/38] target/riscv: Remove the hret instruction Palmer Dabbelt
2020-03-03  0:48 ` [PULL 25/38] target/riscv: Only set TB flags with FP status if enabled Palmer Dabbelt
2020-03-03  0:48 ` [PULL 26/38] target/riscv: Disable guest FP support based on virtual status Palmer Dabbelt
2020-03-03  0:48 ` [PULL 27/38] target/riscv: Mark both sstatus and msstatus_hs as dirty Palmer Dabbelt
2020-03-03  0:48 ` [PULL 28/38] target/riscv: Respect MPRV and SPRV for floating point ops Palmer Dabbelt
2020-03-03  0:48 ` [PULL 29/38] target/riscv: Allow specifying MMU stage Palmer Dabbelt
2020-03-03  0:48 ` Palmer Dabbelt [this message]
2020-03-03  0:48 ` [PULL 31/38] target/riscv: Raise the new execptions when 2nd stage translation fails Palmer Dabbelt
2020-03-03  0:48 ` [PULL 32/38] target/riscv: Set htval and mtval2 on execptions Palmer Dabbelt
2020-03-03  0:48 ` [PULL 33/38] target/riscv: Add support for the 32-bit MSTATUSH CSR Palmer Dabbelt
2020-03-03  0:48 ` [PULL 34/38] target/riscv: Add the MSTATUS_MPV_ISSET helper macro Palmer Dabbelt
2020-03-03  0:48 ` [PULL 35/38] target/riscv: Allow enabling the Hypervisor extension Palmer Dabbelt
2020-03-03  0:48 ` [PULL 36/38] riscv: virt: Allow PCI address 0 Palmer Dabbelt
2020-03-03  0:48 ` [PULL 37/38] target/riscv: Emulate TIME CSRs for privileged mode Palmer Dabbelt
2020-03-03  0:48 ` [PULL 38/38] hw/riscv: Provide rdtime callback for TCG in CLINT emulation Palmer Dabbelt
2020-03-03 12:03 ` [PULL] RISC-V Patches for the 5.0 Soft Freeze, Part 3 Peter Maydell

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=20200303004848.136788-31-palmerdabbelt@google.com \
    --to=palmerdabbelt@google.com \
    --cc=alistair.francis@wdc.com \
    --cc=peter.maydell@linaro.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.