tcg/aarch64: Support raising sigbus for user-only

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2021-08-03 20:07:57 +00:00
parent b1ee3c6725
commit f85ab3d2e5
2 changed files with 74 additions and 19 deletions

View File

@ -10,6 +10,7 @@
* See the COPYING file in the top-level directory for details. * See the COPYING file in the top-level directory for details.
*/ */
#include "../tcg-ldst.c.inc"
#include "../tcg-pool.c.inc" #include "../tcg-pool.c.inc"
#include "qemu/bitops.h" #include "qemu/bitops.h"
@ -443,6 +444,7 @@ typedef enum {
I3404_ANDI = 0x12000000, I3404_ANDI = 0x12000000,
I3404_ORRI = 0x32000000, I3404_ORRI = 0x32000000,
I3404_EORI = 0x52000000, I3404_EORI = 0x52000000,
I3404_ANDSI = 0x72000000,
/* Move wide immediate instructions. */ /* Move wide immediate instructions. */
I3405_MOVN = 0x12800000, I3405_MOVN = 0x12800000,
@ -1328,8 +1330,9 @@ static void tcg_out_goto_long(TCGContext *s, const tcg_insn_unit *target)
if (offset == sextract64(offset, 0, 26)) { if (offset == sextract64(offset, 0, 26)) {
tcg_out_insn(s, 3206, B, offset); tcg_out_insn(s, 3206, B, offset);
} else { } else {
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target); /* Choose X9 as a call-clobbered non-LR temporary. */
tcg_out_insn(s, 3207, BR, TCG_REG_TMP); tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X9, (intptr_t)target);
tcg_out_insn(s, 3207, BR, TCG_REG_X9);
} }
} }
@ -1541,9 +1544,14 @@ static void tcg_out_cltz(TCGContext *s, TCGType ext, TCGReg d,
} }
} }
#ifdef CONFIG_SOFTMMU static void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target)
#include "../tcg-ldst.c.inc" {
ptrdiff_t offset = tcg_pcrel_diff(s, target);
tcg_debug_assert(offset == sextract64(offset, 0, 21));
tcg_out_insn(s, 3406, ADR, rd, offset);
}
#ifdef CONFIG_SOFTMMU
/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr, /* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
* MemOpIdx oi, uintptr_t ra) * MemOpIdx oi, uintptr_t ra)
*/ */
@ -1577,13 +1585,6 @@ static void * const qemu_st_helpers[MO_SIZE + 1] = {
#endif #endif
}; };
static inline void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target)
{
ptrdiff_t offset = tcg_pcrel_diff(s, target);
tcg_debug_assert(offset == sextract64(offset, 0, 21));
tcg_out_insn(s, 3406, ADR, rd, offset);
}
static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb) static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
{ {
MemOpIdx oi = lb->oi; MemOpIdx oi = lb->oi;
@ -1714,15 +1715,58 @@ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, MemOp opc,
tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0); tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0);
} }
#else
static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addr_reg,
unsigned a_bits)
{
unsigned a_mask = (1 << a_bits) - 1;
TCGLabelQemuLdst *label = new_ldst_label(s);
label->is_ld = is_ld;
label->addrlo_reg = addr_reg;
/* tst addr, #mask */
tcg_out_logicali(s, I3404_ANDSI, 0, TCG_REG_XZR, addr_reg, a_mask);
label->label_ptr[0] = s->code_ptr;
/* b.ne slow_path */
tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0);
label->raddr = tcg_splitwx_to_rx(s->code_ptr);
}
static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
{
if (!reloc_pc19(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
return false;
}
tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_X1, l->addrlo_reg);
tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_X0, TCG_AREG0);
/* "Tail call" to the helper, with the return address back inline. */
tcg_out_adr(s, TCG_REG_LR, l->raddr);
tcg_out_goto_long(s, (const void *)(l->is_ld ? helper_unaligned_ld
: helper_unaligned_st));
return true;
}
static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
return tcg_out_fail_alignment(s, l);
}
static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
{
return tcg_out_fail_alignment(s, l);
}
#endif /* CONFIG_SOFTMMU */ #endif /* CONFIG_SOFTMMU */
static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp memop, TCGType ext, static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp memop, TCGType ext,
TCGReg data_r, TCGReg addr_r, TCGReg data_r, TCGReg addr_r,
TCGType otype, TCGReg off_r) TCGType otype, TCGReg off_r)
{ {
/* Byte swapping is left to middle-end expansion. */
tcg_debug_assert((memop & MO_BSWAP) == 0);
switch (memop & MO_SSIZE) { switch (memop & MO_SSIZE) {
case MO_UB: case MO_UB:
tcg_out_ldst_r(s, I3312_LDRB, data_r, addr_r, otype, off_r); tcg_out_ldst_r(s, I3312_LDRB, data_r, addr_r, otype, off_r);
@ -1756,9 +1800,6 @@ static void tcg_out_qemu_st_direct(TCGContext *s, MemOp memop,
TCGReg data_r, TCGReg addr_r, TCGReg data_r, TCGReg addr_r,
TCGType otype, TCGReg off_r) TCGType otype, TCGReg off_r)
{ {
/* Byte swapping is left to middle-end expansion. */
tcg_debug_assert((memop & MO_BSWAP) == 0);
switch (memop & MO_SIZE) { switch (memop & MO_SIZE) {
case MO_8: case MO_8:
tcg_out_ldst_r(s, I3312_STRB, data_r, addr_r, otype, off_r); tcg_out_ldst_r(s, I3312_STRB, data_r, addr_r, otype, off_r);
@ -1782,6 +1823,10 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
{ {
MemOp memop = get_memop(oi); MemOp memop = get_memop(oi);
const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32; const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
/* Byte swapping is left to middle-end expansion. */
tcg_debug_assert((memop & MO_BSWAP) == 0);
#ifdef CONFIG_SOFTMMU #ifdef CONFIG_SOFTMMU
unsigned mem_index = get_mmuidx(oi); unsigned mem_index = get_mmuidx(oi);
tcg_insn_unit *label_ptr; tcg_insn_unit *label_ptr;
@ -1792,6 +1837,10 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
add_qemu_ldst_label(s, true, oi, ext, data_reg, addr_reg, add_qemu_ldst_label(s, true, oi, ext, data_reg, addr_reg,
s->code_ptr, label_ptr); s->code_ptr, label_ptr);
#else /* !CONFIG_SOFTMMU */ #else /* !CONFIG_SOFTMMU */
unsigned a_bits = get_alignment_bits(memop);
if (a_bits) {
tcg_out_test_alignment(s, true, addr_reg, a_bits);
}
if (USE_GUEST_BASE) { if (USE_GUEST_BASE) {
tcg_out_qemu_ld_direct(s, memop, ext, data_reg, tcg_out_qemu_ld_direct(s, memop, ext, data_reg,
TCG_REG_GUEST_BASE, otype, addr_reg); TCG_REG_GUEST_BASE, otype, addr_reg);
@ -1807,6 +1856,10 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
{ {
MemOp memop = get_memop(oi); MemOp memop = get_memop(oi);
const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32; const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
/* Byte swapping is left to middle-end expansion. */
tcg_debug_assert((memop & MO_BSWAP) == 0);
#ifdef CONFIG_SOFTMMU #ifdef CONFIG_SOFTMMU
unsigned mem_index = get_mmuidx(oi); unsigned mem_index = get_mmuidx(oi);
tcg_insn_unit *label_ptr; tcg_insn_unit *label_ptr;
@ -1817,6 +1870,10 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
add_qemu_ldst_label(s, false, oi, (memop & MO_SIZE)== MO_64, add_qemu_ldst_label(s, false, oi, (memop & MO_SIZE)== MO_64,
data_reg, addr_reg, s->code_ptr, label_ptr); data_reg, addr_reg, s->code_ptr, label_ptr);
#else /* !CONFIG_SOFTMMU */ #else /* !CONFIG_SOFTMMU */
unsigned a_bits = get_alignment_bits(memop);
if (a_bits) {
tcg_out_test_alignment(s, false, addr_reg, a_bits);
}
if (USE_GUEST_BASE) { if (USE_GUEST_BASE) {
tcg_out_qemu_st_direct(s, memop, data_reg, tcg_out_qemu_st_direct(s, memop, data_reg,
TCG_REG_GUEST_BASE, otype, addr_reg); TCG_REG_GUEST_BASE, otype, addr_reg);

View File

@ -151,9 +151,7 @@ typedef enum {
void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t); void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS #define TCG_TARGET_NEED_LDST_LABELS
#endif
#define TCG_TARGET_NEED_POOL_LABELS #define TCG_TARGET_NEED_POOL_LABELS
#endif /* AARCH64_TCG_TARGET_H */ #endif /* AARCH64_TCG_TARGET_H */