@@ -138,7 +138,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
/* Disassemble this for me please... (debugging). 'flags' has the following
values:
i386 - 1 means 16 bit code, 2 means 64 bit code
- arm - nonzero means thumb code
+ arm - bit 0 = thumb, bit 1 = reverse endian
ppc - nonzero means little endian
other targets - unused
*/
@@ -169,10 +169,17 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
disasm_info.mach = bfd_mach_i386_i386;
print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
- if (flags)
+ if (flags & 1)
print_insn = print_insn_thumb1;
else
print_insn = print_insn_arm;
+ if (flags & 2) {
+#ifdef TARGET_WORDS_BIGENDIAN
+ disasm_info.endian = BFD_ENDIAN_LITTLE;
+#else
+ disasm_info.endian = BFD_ENDIAN_BIG;
+#endif
+ }
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#ifdef TARGET_SPARC64
@@ -1553,6 +1553,7 @@ static void load_elf_image(const char *image_name, int image_fd,
info->start_data = -1;
info->end_data = 0;
info->brk = 0;
+ info->elf_flags = ehdr->e_flags;
for (i = 0; i < ehdr->e_phnum; i++) {
struct elf_phdr *eppnt = phdr + i;
@@ -767,11 +767,15 @@ void cpu_loop(CPUARMState *env)
if (env->thumb) {
/* FIXME - what to do if get_user() fails? */
get_user_u16(insn, env->regs[15]);
+ if (env->bswap_code)
+ insn = bswap16(insn);
n = insn & 0xff;
env->regs[15] += 2;
} else {
/* FIXME - what to do if get_user() fails? */
get_user_u32(insn, env->regs[15]);
+ if (env->bswap_code)
+ insn = bswap32(insn);
n = (insn & 0xf) | ((insn >> 4) & 0xff0);
env->regs[15] += 4;
}
@@ -779,10 +783,14 @@ void cpu_loop(CPUARMState *env)
if (env->thumb) {
/* FIXME - what to do if get_user() fails? */
get_user_u16(insn, env->regs[15] - 2);
+ if (env->bswap_code)
+ insn = bswap16(insn);
n = insn & 0xff;
} else {
/* FIXME - what to do if get_user() fails? */
get_user_u32(insn, env->regs[15] - 4);
+ if (env->bswap_code)
+ insn = bswap32(insn);
n = insn & 0xffffff;
}
}
@@ -3648,6 +3656,10 @@ int main(int argc, char **argv, char **envp)
for(i = 0; i < 16; i++) {
env->regs[i] = regs->uregs[i];
}
+ /* Enable BE8. */
+ if ((info->elf_flags >> 24) >= 4 && (info->elf_flags & 0x800000)) {
+ env->bswap_code = 1;
+ }
}
#elif defined(TARGET_UNICORE32)
{
@@ -51,6 +51,7 @@ struct image_info {
abi_ulong auxv_len;
abi_ulong arg_start;
abi_ulong arg_end;
+ uint32_t elf_flags;
int personality;
#ifdef CONFIG_USE_FDPIC
abi_ulong loadmap_addr;
@@ -216,6 +216,9 @@ typedef struct CPUARMState {
uint32_t cregs[16];
} iwmmxt;
+ /* For mixed endian mode. */
+ int bswap_code;
+
#if defined(CONFIG_USER_ONLY)
/* For usermode syscall translation. */
int eabi;
@@ -490,6 +493,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
#define ARM_TBFLAG_VFPEN_MASK (1 << ARM_TBFLAG_VFPEN_SHIFT)
#define ARM_TBFLAG_CONDEXEC_SHIFT 8
#define ARM_TBFLAG_CONDEXEC_MASK (0xff << ARM_TBFLAG_CONDEXEC_SHIFT)
+#define ARM_TBFLAG_BSWAP_CODE_SHIFT 16
+#define ARM_TBFLAG_BSWAP_CODE_MASK (1 << ARM_TBFLAG_BSWAP_CODE_SHIFT)
/* Bits 31..16 are currently unused. */
/* some convenience accessor macros */
@@ -505,6 +510,8 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
(((F) & ARM_TBFLAG_VFPEN_MASK) >> ARM_TBFLAG_VFPEN_SHIFT)
#define ARM_TBFLAG_CONDEXEC(F) \
(((F) & ARM_TBFLAG_CONDEXEC_MASK) >> ARM_TBFLAG_CONDEXEC_SHIFT)
+#define ARM_TBFLAG_BSWAP_CODE(F) \
+ (((F) & ARM_TBFLAG_BSWAP_CODE_MASK) >> ARM_TBFLAG_BSWAP_CODE_SHIFT)
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
@@ -515,7 +522,8 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
*flags = (env->thumb << ARM_TBFLAG_THUMB_SHIFT)
| (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
| (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
- | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT);
+ | (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
+ | (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
if (arm_feature(env, ARM_FEATURE_M)) {
privmode = !((env->v7m.exception == 0) && (env->v7m.control & 1));
} else {
@@ -846,6 +846,9 @@ static void do_interrupt_v7m(CPUARMState *env)
if (semihosting_enabled) {
int nr;
nr = lduw_code(env->regs[15]) & 0xff;
+ if (env->bswap_code) {
+ nr = bswap16(nr);
+ }
if (nr == 0xab) {
env->regs[15] += 2;
env->regs[0] = do_arm_semihosting(env);
@@ -917,8 +920,14 @@ void do_interrupt(CPUARMState *env)
/* Check for semihosting interrupt. */
if (env->thumb) {
mask = lduw_code(env->regs[15] - 2) & 0xff;
+ if (env->bswap_code) {
+ mask = bswap16(mask);
+ }
} else {
mask = ldl_code(env->regs[15] - 4) & 0xffffff;
+ if (env->bswap_code) {
+ mask = bswap32(mask);
+ }
}
/* Only intercept calls from privileged modes, to provide some
semblance of security. */
@@ -939,6 +948,9 @@ void do_interrupt(CPUARMState *env)
/* See if this is a semihosting syscall. */
if (env->thumb && semihosting_enabled) {
mask = lduw_code(env->regs[15]) & 0xff;
+ if (env->bswap_code) {
+ mask = bswap16(mask);
+ }
if (mask == 0xab
&& (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
env->regs[15] += 2;
@@ -59,6 +59,7 @@ typedef struct DisasContext {
struct TranslationBlock *tb;
int singlestep_enabled;
int thumb;
+ int bswap_code;
#if !defined(CONFIG_USER_ONLY)
int user;
#endif
@@ -6706,6 +6707,9 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
TCGv_i64 tmp64;
insn = ldl_code(s->pc);
+ if (s->bswap_code) {
+ insn = bswap32(insn);
+ }
s->pc += 4;
/* M variants do not implement ARM mode. */
@@ -8134,6 +8138,9 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
}
insn = lduw_code(s->pc);
+ if (s->bswap_code) {
+ insn = bswap16(insn);
+ }
s->pc += 2;
insn |= (uint32_t)insn_hw1 << 16;
@@ -9164,6 +9171,9 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
}
insn = lduw_code(s->pc);
+ if (s->bswap_code) {
+ insn = bswap16(insn);
+ }
s->pc += 2;
switch (insn >> 12) {
@@ -9855,6 +9865,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
dc->singlestep_enabled = env->singlestep_enabled;
dc->condjmp = 0;
dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
+ dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags);
dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
#if !defined(CONFIG_USER_ONLY)
@@ -10088,7 +10099,8 @@ done_generating:
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
qemu_log("----------------\n");
qemu_log("IN: %s\n", lookup_symbol(pc_start));
- log_target_disas(pc_start, dc->pc - pc_start, dc->thumb);
+ log_target_disas(pc_start, dc->pc - pc_start,
+ dc->thumb | (dc->bswap_code << 1));
qemu_log("\n");
}
#endif
Add support for ARM BE8 userspace binaries. i.e. big-endian data and little-endian code. In principle LE8 mode is also possible, but AFAIK has never actually been implemented/used. System emulation doesn't have any useable big-endian board models, but should in principle work once you fix that. Dynamic iendianness switching requires messing with data accesses, preferably with TCG cooperation, and is orthogonal to BE8 support. Signed-off-by: Paul Brook <paul@codesourcery.com> --- disas.c | 11 +++++++++-- linux-user/elfload.c | 1 + linux-user/main.c | 12 ++++++++++++ linux-user/qemu.h | 1 + target-arm/cpu.h | 10 +++++++++- target-arm/helper.c | 12 ++++++++++++ target-arm/translate.c | 14 +++++++++++++- 7 files changed, 57 insertions(+), 4 deletions(-)