target/hppa: Implement B,GATE insn

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2017-12-15 14:37:26 -06:00
parent c643603a85
commit 43e056522f
3 changed files with 57 additions and 0 deletions

View File

@ -354,6 +354,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
extern const MemoryRegionOps hppa_io_eir_ops;
extern const struct VMStateDescription vmstate_hppa_cpu;
void hppa_cpu_alarm_timer(void *);
int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr);
#endif
void QEMU_NORETURN hppa_dynamic_excp(CPUHPPAState *env, int excp, uintptr_t ra);

View File

@ -122,6 +122,7 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
break;
default: /* execute: promote to privilege level type & 3 */
prot = x_prot;
break;
}
/* ??? Check PSW_P and ent->access_prot. This can remove PAGE_WRITE. */
@ -335,4 +336,11 @@ target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
}
return phys;
}
/* Return the ar_type of the TLB at VADDR, or -1. */
int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr)
{
hppa_tlb_entry *ent = hppa_find_tlb(env, vaddr);
return ent ? ent->ar_type : -1;
}
#endif /* CONFIG_USER_ONLY */

View File

@ -3782,6 +3782,53 @@ static DisasJumpType trans_bl(DisasContext *ctx, uint32_t insn,
return do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
}
static DisasJumpType trans_b_gate(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
unsigned n = extract32(insn, 1, 1);
unsigned link = extract32(insn, 21, 5);
target_sreg disp = assemble_17(insn);
target_ureg dest = iaoq_dest(ctx, disp);
/* Make sure the caller hasn't done something weird with the queue.
* ??? This is not quite the same as the PSW[B] bit, which would be
* expensive to track. Real hardware will trap for
* b gateway
* b gateway+4 (in delay slot of first branch)
* However, checking for a non-sequential instruction queue *will*
* diagnose the security hole
* b gateway
* b evil
* in which instructions at evil would run with increased privs.
*/
if (ctx->iaoq_b == -1 || ctx->iaoq_b != ctx->iaoq_f + 4) {
return gen_illegal(ctx);
}
#ifndef CONFIG_USER_ONLY
if (ctx->tb_flags & PSW_C) {
CPUHPPAState *env = ctx->cs->env_ptr;
int type = hppa_artype_for_page(env, ctx->base.pc_next);
/* If we could not find a TLB entry, then we need to generate an
ITLB miss exception so the kernel will provide it.
The resulting TLB fill operation will invalidate this TB and
we will re-translate, at which point we *will* be able to find
the TLB entry and determine if this is in fact a gateway page. */
if (type < 0) {
return gen_excp(ctx, EXCP_ITLB_MISS);
}
/* No change for non-gateway pages or for priv decrease. */
if (type >= 4 && type - 4 < ctx->privilege) {
dest = deposit32(dest, 0, 2, type - 4);
}
} else {
dest &= -4; /* priv = 0 */
}
#endif
return do_dbranch(ctx, dest, link, n);
}
static DisasJumpType trans_bl_long(DisasContext *ctx, uint32_t insn,
const DisasInsn *di)
{
@ -3860,6 +3907,7 @@ static const DisasInsn table_branch[] = {
{ 0xe8004000u, 0xfc00fffdu, trans_blr },
{ 0xe800c000u, 0xfc00fffdu, trans_bv },
{ 0xe800d000u, 0xfc00dffcu, trans_bve },
{ 0xe8002000u, 0xfc00e000u, trans_b_gate },
};
static DisasJumpType trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,