From e3d0a33ab83c9dd65134da0c0a10a6a91173a08c Mon Sep 17 00:00:00 2001 From: lazymio Date: Tue, 5 Apr 2022 11:55:58 +0200 Subject: [PATCH] Fix BE32 usermode address XOR --- qemu/target/arm/cpu.c | 10 +++++----- qemu/target/arm/translate.c | 12 +++++++++--- tests/unit/test_arm.c | 24 ++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/qemu/target/arm/cpu.c b/qemu/target/arm/cpu.c index a47d74cb..dce2f45b 100644 --- a/qemu/target/arm/cpu.c +++ b/qemu/target/arm/cpu.c @@ -2167,17 +2167,17 @@ ARMCPU *cpu_arm_init(struct uc_struct *uc) qemu_init_vcpu(cs); - // UC_MODE_BIG_ENDIAN means big endian code and big endian - // data (BE32), which is only supported before ARMv7-A. + // UC_MODE_BIG_ENDIAN means big endian code and big endian data (BE32), which + // 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. // // UC_MODE_ARMBE8 -> little 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 - // we hack it to support BE32. + // In QEMU system, all arm instruction fetch **should be** little endian, however + // we hack it to support (usermode) BE32. // // Reference: // https://developer.arm.com/documentation/ddi0406/c/Application-Level-Architecture/Application-Level-Memory-Model/Endian-support/Instruction-endianness?lang=en diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index 426995e4..d93a438e 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -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); /* 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))); } return addr; @@ -974,7 +976,9 @@ static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val) { TCGContext *tcg_ctx = s->uc->tcg_ctx; /* 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); } } @@ -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); /* 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); tcg_gen_rotri_i64(tcg_ctx, tmp, val, 32); tcg_gen_qemu_st_i64(tcg_ctx, tmp, addr, index, opc); diff --git a/tests/unit/test_arm.c b/tests/unit/test_arm.c index cd3e0b65..bb0c3b51 100644 --- a/tests/unit/test_arm.c +++ b/tests/unit/test_arm.c @@ -727,6 +727,29 @@ static void test_arm_switch_endian() 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_arm_thumb_sub", test_arm_thumb_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_be_cpsr_sctlr", test_arm_be_cpsr_sctlr}, {"test_arm_switch_endian", test_arm_switch_endian}, + {"test_armeb_ldrb", test_armeb_ldrb}, {NULL, NULL}}; \ No newline at end of file