Message ID | 20200605041733.415188-13-richard.henderson@linaro.org |
---|---|
State | New |
Headers | show |
Series | target-arm: Implement ARMv8.5-MemTag, user mode | expand |
On Fri, 5 Jun 2020 at 05:17, Richard Henderson <richard.henderson@linaro.org> wrote: > > A proper syndrome is required to fill in the proper si_code. > Use page_get_flags to determine permission vs translation > for user-only. > > Signed-off-by: Richard Henderson <richard.henderson@linaro.org> > --- > linux-user/aarch64/cpu_loop.c | 23 ++++++++++++++++++++--- > target/arm/tlb_helper.c | 27 +++++++++++++++++++++------ > 2 files changed, 41 insertions(+), 9 deletions(-) > > diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c > index 3cca637bb9..ce56e15be2 100644 > --- a/linux-user/aarch64/cpu_loop.c > +++ b/linux-user/aarch64/cpu_loop.c > @@ -75,7 +75,7 @@ > void cpu_loop(CPUARMState *env) > { > CPUState *cs = env_cpu(env); > - int trapnr; > + int trapnr, ec, fsc; > abi_long ret; > target_siginfo_t info; > > @@ -116,9 +116,26 @@ void cpu_loop(CPUARMState *env) > case EXCP_DATA_ABORT: > info.si_signo = TARGET_SIGSEGV; > info.si_errno = 0; > - /* XXX: check env->error_code */ > - info.si_code = TARGET_SEGV_MAPERR; > info._sifields._sigfault._addr = env->exception.vaddress; > + > + /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */ > + ec = extract32(env->exception.syndrome, 26, 6); ec = syn_get_ec(env->exception.syndrome); (though it's in internals.h which implies moving it I guess). > + assert(ec == 0x24 || ec == 0x20); assert(ec == EC_DATAABORT || ec == EC_INSNABORT); > + > + /* Both EC have the same format for FSC, or close enough. */ > + fsc = extract32(env->exception.syndrome, 0, 6); > + switch (fsc) { > + case 0x04 ... 0x07: /* Translation fault, level {0-3} */ > + info.si_code = TARGET_SEGV_MAPERR; > + break; > + case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */ > + case 0x0d ... 0x0f: /* Permission fault, level {1-3} */ > + info.si_code = TARGET_SEGV_ACCERR; > + break; > + default: > + g_assert_not_reached(); > + } > + > queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); > break; > case EXCP_UNALIGNED: > diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c > index d4e6d37f4f..35d84ac24f 100644 > --- a/target/arm/tlb_helper.c > +++ b/target/arm/tlb_helper.c > @@ -10,8 +10,6 @@ > #include "internals.h" > #include "exec/exec-all.h" > > -#if !defined(CONFIG_USER_ONLY) > - > static inline uint32_t merge_syn_data_abort(uint32_t template_syn, > unsigned int target_el, > bool same_el, bool ea, > @@ -51,6 +49,8 @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn, > return syn; > } > > +#if !defined(CONFIG_USER_ONLY) > + > static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr, > MMUAccessType access_type, > int mmu_idx, ARMMMUFaultInfo *fi) > @@ -138,13 +138,28 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, > ARMCPU *cpu = ARM_CPU(cs); > > #ifdef CONFIG_USER_ONLY > + int flags, fsc, exc; > + unsigned syn; > + > cpu->env.exception.vaddress = address; > - if (access_type == MMU_INST_FETCH) { > - cs->exception_index = EXCP_PREFETCH_ABORT; > + > + flags = page_get_flags(useronly_clean_ptr(address)); > + if (flags & PAGE_VALID) { > + fsc = 0xf; /* permission fault, level 3 */ > } else { > - cs->exception_index = EXCP_DATA_ABORT; > + fsc = 0x7; /* translation fault, level 3 */ > } > - cpu_loop_exit_restore(cs, retaddr); > + > + cpu_restore_state(cs, retaddr, true); > + if (access_type == MMU_INST_FETCH) { > + exc = EXCP_PREFETCH_ABORT; > + syn = syn_insn_abort(0, 0, 0, fsc); > + } else { > + exc = EXCP_DATA_ABORT; > + syn = merge_syn_data_abort(cpu->env.exception.syndrome, 1, 0, 0, 0, > + access_type == MMU_DATA_STORE, fsc); > + } > + raise_exception(&cpu->env, exc, syn, 1); Should we call arm_deliver_fault() the way the other series does for linux-user alignment faults ? thanks -- PMM
diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 3cca637bb9..ce56e15be2 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -75,7 +75,7 @@ void cpu_loop(CPUARMState *env) { CPUState *cs = env_cpu(env); - int trapnr; + int trapnr, ec, fsc; abi_long ret; target_siginfo_t info; @@ -116,9 +116,26 @@ void cpu_loop(CPUARMState *env) case EXCP_DATA_ABORT: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; - /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->exception.vaddress; + + /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */ + ec = extract32(env->exception.syndrome, 26, 6); + assert(ec == 0x24 || ec == 0x20); + + /* Both EC have the same format for FSC, or close enough. */ + fsc = extract32(env->exception.syndrome, 0, 6); + switch (fsc) { + case 0x04 ... 0x07: /* Translation fault, level {0-3} */ + info.si_code = TARGET_SEGV_MAPERR; + break; + case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */ + case 0x0d ... 0x0f: /* Permission fault, level {1-3} */ + info.si_code = TARGET_SEGV_ACCERR; + break; + default: + g_assert_not_reached(); + } + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_UNALIGNED: diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c index d4e6d37f4f..35d84ac24f 100644 --- a/target/arm/tlb_helper.c +++ b/target/arm/tlb_helper.c @@ -10,8 +10,6 @@ #include "internals.h" #include "exec/exec-all.h" -#if !defined(CONFIG_USER_ONLY) - static inline uint32_t merge_syn_data_abort(uint32_t template_syn, unsigned int target_el, bool same_el, bool ea, @@ -51,6 +49,8 @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn, return syn; } +#if !defined(CONFIG_USER_ONLY) + static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type, int mmu_idx, ARMMMUFaultInfo *fi) @@ -138,13 +138,28 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, ARMCPU *cpu = ARM_CPU(cs); #ifdef CONFIG_USER_ONLY + int flags, fsc, exc; + unsigned syn; + cpu->env.exception.vaddress = address; - if (access_type == MMU_INST_FETCH) { - cs->exception_index = EXCP_PREFETCH_ABORT; + + flags = page_get_flags(useronly_clean_ptr(address)); + if (flags & PAGE_VALID) { + fsc = 0xf; /* permission fault, level 3 */ } else { - cs->exception_index = EXCP_DATA_ABORT; + fsc = 0x7; /* translation fault, level 3 */ } - cpu_loop_exit_restore(cs, retaddr); + + cpu_restore_state(cs, retaddr, true); + if (access_type == MMU_INST_FETCH) { + exc = EXCP_PREFETCH_ABORT; + syn = syn_insn_abort(0, 0, 0, fsc); + } else { + exc = EXCP_DATA_ABORT; + syn = merge_syn_data_abort(cpu->env.exception.syndrome, 1, 0, 0, 0, + access_type == MMU_DATA_STORE, fsc); + } + raise_exception(&cpu->env, exc, syn, 1); #else hwaddr phys_addr; target_ulong page_size;
A proper syndrome is required to fill in the proper si_code. Use page_get_flags to determine permission vs translation for user-only. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/aarch64/cpu_loop.c | 23 ++++++++++++++++++++--- target/arm/tlb_helper.c | 27 +++++++++++++++++++++------ 2 files changed, 41 insertions(+), 9 deletions(-) -- 2.25.1