target-arm: Add S2 translation to 64bit S1 PTWs

Add support for applying S2 translation to 64bit S1
page-table walks.

Backports commit 37785977627295162bff58b1f8777d94e20f4c5b from qemu
This commit is contained in:
Edgar E. Iglesias 2018-02-17 13:36:38 -05:00 committed by Lioncash
parent 716f1ac28c
commit 085a94faac
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
2 changed files with 51 additions and 6 deletions

View file

@ -15,6 +15,12 @@ static bool get_phys_addr(CPUARMState *env, target_ulong address,
target_ulong *page_size, uint32_t *fsr,
ARMMMUFaultInfo *fi);
static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot,
target_ulong *page_size_ptr, uint32_t *fsr,
ARMMMUFaultInfo *fi);
/* Definitions for the PMCCNTR and PMCR registers */
#define PMCRD 0x8
#define PMCRC 0x4
@ -5558,6 +5564,32 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx,
return true;
}
/* Translate a S1 pagetable walk through S2 if needed. */
static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
hwaddr addr, MemTxAttrs txattrs,
uint32_t *fsr,
ARMMMUFaultInfo *fi)
{
if ((mmu_idx == ARMMMUIdx_S1NSE0 || mmu_idx == ARMMMUIdx_S1NSE1) &&
!regime_translation_disabled(env, ARMMMUIdx_S2NS)) {
target_ulong s2size;
hwaddr s2pa;
int s2prot;
int ret;
ret = get_phys_addr_lpae(env, addr, 0, ARMMMUIdx_S2NS, &s2pa,
&txattrs, &s2prot, &s2size, fsr, fi);
if (ret) {
fi->s2addr = addr;
fi->stage2 = true;
fi->s1ptw = true;
return ~0;
}
addr = s2pa;
}
return addr;
}
/* All loads done in the course of a page table walk go through here.
* TODO: rather than ignoring errors from physical memory reads (which
* are external aborts in ARM terminology) we should propagate this
@ -5567,17 +5599,25 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx,
*/
static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure)
{
MemTxAttrs attrs = {};
MemTxAttrs attrs = {0};
attrs.secure = is_secure;
return address_space_ldl(cs->as, addr, attrs, NULL);
}
static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure)
static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure,
ARMMMUIdx mmu_idx, uint32_t *fsr,
ARMMMUFaultInfo *fi)
{
MemTxAttrs attrs = {};
ARMCPU *cpu = ARM_CPU(cs->uc, cs);
CPUARMState *env = &cpu->env;
MemTxAttrs attrs = {0};
attrs.secure = is_secure;
addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi);
if (fi->s1ptw) {
return 0;
}
return address_space_ldq(cs->as, addr, attrs, NULL);
}
@ -6136,7 +6176,10 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
descaddr |= (address >> (stride * (4 - level))) & descmask;
descaddr &= ~7ULL;
nstable = extract32(tableattrs, 4, 1);
descriptor = arm_ldq_ptw(cs, descaddr, !nstable);
descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fsr, fi);
if (fi->s1ptw) {
goto do_fault;
}
if (!(descriptor & 1) ||
(!(descriptor & 2) && (level == 3))) {
/* Invalid, or the Reserved level 3 encoding */
@ -6221,6 +6264,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
do_fault:
/* Long-descriptor format IFSR/DFSR value */
*fsr = (1 << 9) | (fault_type << 2) | level;
/* Tag the error as S2 for failed S1 PTW at S2 or ordinary S2. */
fi->stage2 = fi->s1ptw || (mmu_idx == ARMMMUIdx_S2NS);
return true;
}

View file

@ -104,10 +104,10 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
* information; this is always true for exceptions reported to EL1.
*/
if (is_write == 2) {
syn = syn_insn_abort(same_el, 0, 0, syn);
syn = syn_insn_abort(same_el, 0, fi.s1ptw, syn);
exc = EXCP_PREFETCH_ABORT;
} else {
syn = syn_data_abort(same_el, 0, 0, 0, is_write == 1, syn);
syn = syn_data_abort(same_el, 0, 0, fi.s1ptw, is_write == 1, syn);
if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) {
fsr |= (1 << 11);
}