Fix BE32 usermode address XOR
This commit is contained in:
parent
7e64e620d2
commit
e3d0a33ab8
@ -2167,17 +2167,17 @@ ARMCPU *cpu_arm_init(struct uc_struct *uc)
|
|||||||
|
|
||||||
qemu_init_vcpu(cs);
|
qemu_init_vcpu(cs);
|
||||||
|
|
||||||
// UC_MODE_BIG_ENDIAN means big endian code and big endian
|
// UC_MODE_BIG_ENDIAN means big endian code and big endian data (BE32), which
|
||||||
// data (BE32), which is only supported before ARMv7-A.
|
// is only supported before ARMv7-A (and it only makes sense in qemu usermode!).
|
||||||
//
|
//
|
||||||
// UC_MODE_ARMBE8 shouldn't exist in fact. We do this for
|
// UC_MODE_ARMBE8 & BE32 difference shouldn't exist in fact. We do this for
|
||||||
// backward compatibility.
|
// backward compatibility.
|
||||||
//
|
//
|
||||||
// UC_MODE_ARMBE8 -> little endian code, big endian data
|
// UC_MODE_ARMBE8 -> little endian code, big endian data
|
||||||
// UC_MODE_ARMBE8 | UC_MODE_BIG_ENDIAN -> big endian code, big endian data
|
// UC_MODE_ARMBE8 | UC_MODE_BIG_ENDIAN -> big endian code, big endian data
|
||||||
//
|
//
|
||||||
// In QEMU, all arm instruction fetch **should be** little endian, however
|
// In QEMU system, all arm instruction fetch **should be** little endian, however
|
||||||
// we hack it to support BE32.
|
// we hack it to support (usermode) BE32.
|
||||||
//
|
//
|
||||||
// Reference:
|
// Reference:
|
||||||
// https://developer.arm.com/documentation/ddi0406/c/Application-Level-Architecture/Application-Level-Memory-Model/Endian-support/Instruction-endianness?lang=en
|
// https://developer.arm.com/documentation/ddi0406/c/Application-Level-Architecture/Application-Level-Memory-Model/Endian-support/Instruction-endianness?lang=en
|
||||||
|
@ -918,7 +918,9 @@ static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, MemOp op)
|
|||||||
tcg_gen_extu_i32_tl(tcg_ctx, addr, a32);
|
tcg_gen_extu_i32_tl(tcg_ctx, addr, a32);
|
||||||
|
|
||||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */
|
/* Not needed for user-mode BE32, where we use MO_BE instead. */
|
||||||
if (!IS_USER_ONLY && s->sctlr_b && (op & MO_SIZE) < MO_32) {
|
// Unicorn: By default UC_MODE_BIG_MODE is BE32 mode, which in fact qemu-usermode.
|
||||||
|
// Thus, we only do this in BE8 (qemu system) mode.
|
||||||
|
if ( (s->uc->mode & UC_MODE_ARMBE8) && s->sctlr_b && (op & MO_SIZE) < MO_32) {
|
||||||
tcg_gen_xori_tl(tcg_ctx, addr, addr, 4 - (1 << (op & MO_SIZE)));
|
tcg_gen_xori_tl(tcg_ctx, addr, addr, 4 - (1 << (op & MO_SIZE)));
|
||||||
}
|
}
|
||||||
return addr;
|
return addr;
|
||||||
@ -974,7 +976,9 @@ static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val)
|
|||||||
{
|
{
|
||||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */
|
/* Not needed for user-mode BE32, where we use MO_BE instead. */
|
||||||
if (!IS_USER_ONLY && s->sctlr_b) {
|
// Unicorn: By default UC_MODE_BIG_MODE is BE32 mode, which in fact qemu-usermode.
|
||||||
|
// Thus, we only do this in BE8 (qemu system) mode.
|
||||||
|
if ( (s->uc->mode & UC_MODE_ARMBE8) && s->sctlr_b) {
|
||||||
tcg_gen_rotri_i64(tcg_ctx, val, val, 32);
|
tcg_gen_rotri_i64(tcg_ctx, val, val, 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1002,7 +1006,9 @@ static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
|
|||||||
TCGv addr = gen_aa32_addr(s, a32, opc);
|
TCGv addr = gen_aa32_addr(s, a32, opc);
|
||||||
|
|
||||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */
|
/* Not needed for user-mode BE32, where we use MO_BE instead. */
|
||||||
if (!IS_USER_ONLY && s->sctlr_b) {
|
// Unicorn: By default UC_MODE_BIG_MODE is BE32 mode, which in fact qemu-usermode.
|
||||||
|
// Thus, we only do this in BE8 (qemu system) mode.
|
||||||
|
if ( (s->uc->mode & UC_MODE_ARMBE8) && s->sctlr_b) {
|
||||||
TCGv_i64 tmp = tcg_temp_new_i64(tcg_ctx);
|
TCGv_i64 tmp = tcg_temp_new_i64(tcg_ctx);
|
||||||
tcg_gen_rotri_i64(tcg_ctx, tmp, val, 32);
|
tcg_gen_rotri_i64(tcg_ctx, tmp, val, 32);
|
||||||
tcg_gen_qemu_st_i64(tcg_ctx, tmp, addr, index, opc);
|
tcg_gen_qemu_st_i64(tcg_ctx, tmp, addr, index, opc);
|
||||||
|
@ -727,6 +727,29 @@ static void test_arm_switch_endian()
|
|||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_armeb_ldrb(void)
|
||||||
|
{
|
||||||
|
uc_engine *uc;
|
||||||
|
const char test_code[] = "\xe5\xd2\x10\x00"; // ldrb r1, [r2]
|
||||||
|
uint64_t data_address = 0x800000;
|
||||||
|
int r1 = 0x1234;
|
||||||
|
int r2 = data_address;
|
||||||
|
|
||||||
|
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM | UC_MODE_BIG_ENDIAN, test_code, sizeof(test_code) - 1, UC_CPU_ARM_1176);
|
||||||
|
|
||||||
|
OK(uc_mem_map(uc, data_address, 1024 * 1024, UC_PROT_ALL));
|
||||||
|
OK(uc_mem_write(uc, data_address, "\x66\x67\x68\x69", 4));
|
||||||
|
OK(uc_reg_write(uc, UC_ARM_REG_R2, &r2));
|
||||||
|
|
||||||
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(test_code) - 1, 0, 0));
|
||||||
|
|
||||||
|
OK(uc_reg_read(uc, UC_ARM_REG_R1, &r1));
|
||||||
|
|
||||||
|
TEST_CHECK(r1 == 0x66);
|
||||||
|
|
||||||
|
OK(uc_close(uc));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_LIST = {{"test_arm_nop", test_arm_nop},
|
TEST_LIST = {{"test_arm_nop", test_arm_nop},
|
||||||
{"test_arm_thumb_sub", test_arm_thumb_sub},
|
{"test_arm_thumb_sub", test_arm_thumb_sub},
|
||||||
{"test_armeb_sub", test_armeb_sub},
|
{"test_armeb_sub", test_armeb_sub},
|
||||||
@ -748,4 +771,5 @@ TEST_LIST = {{"test_arm_nop", test_arm_nop},
|
|||||||
{"test_arm_read_sctlr", test_arm_read_sctlr},
|
{"test_arm_read_sctlr", test_arm_read_sctlr},
|
||||||
{"test_arm_be_cpsr_sctlr", test_arm_be_cpsr_sctlr},
|
{"test_arm_be_cpsr_sctlr", test_arm_be_cpsr_sctlr},
|
||||||
{"test_arm_switch_endian", test_arm_switch_endian},
|
{"test_arm_switch_endian", test_arm_switch_endian},
|
||||||
|
{"test_armeb_ldrb", test_armeb_ldrb},
|
||||||
{NULL, NULL}};
|
{NULL, NULL}};
|
Loading…
Reference in New Issue
Block a user