Message ID | 67e93a4f45693067abb03441e159b1f4a0a48276.1566603412.git.alistair.francis@wdc.com |
---|---|
State | New |
Headers | show |
Series | Add RISC-V Hypervisor Extension v0.4 | expand |
On Fri, 23 Aug 2019 16:38:52 PDT (-0700), Alistair Francis wrote: > Signed-off-by: Alistair Francis <alistair.francis@wdc.com> > --- > target/riscv/cpu_helper.c | 96 +++++++++++++++++++++++++++++++++++---- > 1 file changed, 86 insertions(+), 10 deletions(-) > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > index 8b9871f9ea..188d5cb39f 100644 > --- a/target/riscv/cpu_helper.c > +++ b/target/riscv/cpu_helper.c > @@ -337,13 +337,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; > @@ -353,13 +380,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->vsstatus, 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->vsatp, SATP_PPN) << PGSHIFT; > + vm = get_field(env->vsatp, 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; > @@ -377,6 +421,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); > @@ -397,9 +442,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; > } > @@ -411,17 +463,36 @@ 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 (riscv_feature(env, RISCV_FEATURE_PMP) && > !pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong), > 1 << MMU_DATA_LOAD, PRV_S)) { > return TRANSLATE_PMP_FAIL; > } > + > #if defined(TARGET_RISCV32) > target_ulong pte = ldl_phys(cs->as, pte_addr); > #elif defined(TARGET_RISCV64) > @@ -507,7 +578,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)) { Reviewed-by: Palmer Dabbelt <palmer@sifive.com>
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 8b9871f9ea..188d5cb39f 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -337,13 +337,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; @@ -353,13 +380,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->vsstatus, 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->vsatp, SATP_PPN) << PGSHIFT; + vm = get_field(env->vsatp, 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; @@ -377,6 +421,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); @@ -397,9 +442,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; } @@ -411,17 +463,36 @@ 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 (riscv_feature(env, RISCV_FEATURE_PMP) && !pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong), 1 << MMU_DATA_LOAD, PRV_S)) { return TRANSLATE_PMP_FAIL; } + #if defined(TARGET_RISCV32) target_ulong pte = ldl_phys(cs->as, pte_addr); #elif defined(TARGET_RISCV64) @@ -507,7 +578,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)) {
Signed-off-by: Alistair Francis <alistair.francis@wdc.com> --- target/riscv/cpu_helper.c | 96 +++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 10 deletions(-)