target/arm: Default handling of BTYPE during translation

The branch target exception for guarded pages has high priority,
and only 8 instructions are valid for that case.  Perform this
check before doing any other decode.

Clear BTYPE after all insns that neither set BTYPE nor exit via
exception (DISAS_NORETURN).

Not yet handled are insns that exit via DISAS_NORETURN for some
other reason, like direct branches.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20190128223118.5255-7-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2019-02-05 16:52:37 +00:00 committed by Peter Maydell
parent 1bafc2ba7e
commit 51bf0d7aa9
3 changed files with 152 additions and 2 deletions

View File

@ -268,6 +268,7 @@ enum arm_exception_class {
EC_FPIDTRAP = 0x08,
EC_PACTRAP = 0x09,
EC_CP14RRTTRAP = 0x0c,
EC_BTITRAP = 0x0d,
EC_ILLEGALSTATE = 0x0e,
EC_AA32_SVC = 0x11,
EC_AA32_HVC = 0x12,
@ -439,6 +440,11 @@ static inline uint32_t syn_pactrap(void)
return EC_PACTRAP << ARM_EL_EC_SHIFT;
}
static inline uint32_t syn_btitrap(int btype)
{
return (EC_BTITRAP << ARM_EL_EC_SHIFT) | btype;
}
static inline uint32_t syn_insn_abort(int same_el, int ea, int s1ptw, int fsc)
{
return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (same_el << ARM_EL_EC_SHIFT)

View File

@ -128,6 +128,16 @@ static inline int get_a64_user_mem_index(DisasContext *s)
return arm_to_core_mmu_idx(useridx);
}
static void reset_btype(DisasContext *s)
{
if (s->btype != 0) {
TCGv_i32 zero = tcg_const_i32(0);
tcg_gen_st_i32(zero, cpu_env, offsetof(CPUARMState, btype));
tcg_temp_free_i32(zero);
s->btype = 0;
}
}
void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
fprintf_function cpu_fprintf, int flags)
{
@ -13756,6 +13766,90 @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
}
}
/**
* is_guarded_page:
* @env: The cpu environment
* @s: The DisasContext
*
* Return true if the page is guarded.
*/
static bool is_guarded_page(CPUARMState *env, DisasContext *s)
{
#ifdef CONFIG_USER_ONLY
return false; /* FIXME */
#else
uint64_t addr = s->base.pc_first;
int mmu_idx = arm_to_core_mmu_idx(s->mmu_idx);
unsigned int index = tlb_index(env, mmu_idx, addr);
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
/*
* We test this immediately after reading an insn, which means
* that any normal page must be in the TLB. The only exception
* would be for executing from flash or device memory, which
* does not retain the TLB entry.
*
* FIXME: Assume false for those, for now. We could use
* arm_cpu_get_phys_page_attrs_debug to re-read the page
* table entry even for that case.
*/
return (tlb_hit(entry->addr_code, addr) &&
env->iotlb[mmu_idx][index].attrs.target_tlb_bit0);
#endif
}
/**
* btype_destination_ok:
* @insn: The instruction at the branch destination
* @bt: SCTLR_ELx.BT
* @btype: PSTATE.BTYPE, and is non-zero
*
* On a guarded page, there are a limited number of insns
* that may be present at the branch target:
* - branch target identifiers,
* - paciasp, pacibsp,
* - BRK insn
* - HLT insn
* Anything else causes a Branch Target Exception.
*
* Return true if the branch is compatible, false to raise BTITRAP.
*/
static bool btype_destination_ok(uint32_t insn, bool bt, int btype)
{
if ((insn & 0xfffff01fu) == 0xd503201fu) {
/* HINT space */
switch (extract32(insn, 5, 7)) {
case 0b011001: /* PACIASP */
case 0b011011: /* PACIBSP */
/*
* If SCTLR_ELx.BT, then PACI*SP are not compatible
* with btype == 3. Otherwise all btype are ok.
*/
return !bt || btype != 3;
case 0b100000: /* BTI */
/* Not compatible with any btype. */
return false;
case 0b100010: /* BTI c */
/* Not compatible with btype == 3 */
return btype != 3;
case 0b100100: /* BTI j */
/* Not compatible with btype == 2 */
return btype != 2;
case 0b100110: /* BTI jc */
/* Compatible with any btype. */
return true;
}
} else {
switch (insn & 0xffe0001fu) {
case 0xd4200000u: /* BRK */
case 0xd4400000u: /* HLT */
/* Give priority to the breakpoint exception. */
return true;
}
}
return false;
}
/* C3.1 A64 instruction index by encoding */
static void disas_a64_insn(CPUARMState *env, DisasContext *s)
{
@ -13767,6 +13861,43 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
s->fp_access_checked = false;
if (dc_isar_feature(aa64_bti, s)) {
if (s->base.num_insns == 1) {
/*
* At the first insn of the TB, compute s->guarded_page.
* We delayed computing this until successfully reading
* the first insn of the TB, above. This (mostly) ensures
* that the softmmu tlb entry has been populated, and the
* page table GP bit is available.
*
* Note that we need to compute this even if btype == 0,
* because this value is used for BR instructions later
* where ENV is not available.
*/
s->guarded_page = is_guarded_page(env, s);
/* First insn can have btype set to non-zero. */
tcg_debug_assert(s->btype >= 0);
/*
* Note that the Branch Target Exception has fairly high
* priority -- below debugging exceptions but above most
* everything else. This allows us to handle this now
* instead of waiting until the insn is otherwise decoded.
*/
if (s->btype != 0
&& s->guarded_page
&& !btype_destination_ok(insn, s->bt, s->btype)) {
gen_exception_insn(s, 4, EXCP_UDEF, syn_btitrap(s->btype),
default_exception_el(s));
return;
}
} else {
/* Not the first insn: btype must be 0. */
tcg_debug_assert(s->btype == 0);
}
}
switch (extract32(insn, 25, 4)) {
case 0x0: case 0x1: case 0x3: /* UNALLOCATED */
unallocated_encoding(s);
@ -13803,6 +13934,14 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
/* if we allocated any temporaries, free them here */
free_tmp_a64(s);
/*
* After execution of most insns, btype is reset to 0.
* Note that we set btype == -1 when the insn sets btype.
*/
if (s->btype > 0 && s->base.is_jmp != DISAS_NORETURN) {
reset_btype(s);
}
}
static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,

View File

@ -71,8 +71,13 @@ typedef struct DisasContext {
bool pauth_active;
/* True with v8.5-BTI and SCTLR_ELx.BT* set. */
bool bt;
/* A copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. */
uint8_t btype;
/*
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
* < 0, set by the current instruction.
*/
int8_t btype;
/* True if this page is guarded. */
bool guarded_page;
/* Bottom two bits of XScale c15_cpar coprocessor access control reg */
int c15_cpar;
/* TCG op of the current insn_start. */