aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorPaul Brook <paul@codesourcery.com>2012-03-30 18:02:50 +0100
committerRiku Voipio <riku.voipio@linaro.org>2012-04-06 19:25:57 +0300
commitd8fd2954996255ba6ad610917e7849832d0120b7 (patch)
tree8278d793ca64380475ce207fc0baf374ac5f522a /linux-user
parentef8b0c0474aa7eab5172e866dc37428b41ff2934 (diff)
Userspace ARM BE8 support
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 endianness switching requires messing with data accesses, preferably with TCG cooperation, and is orthogonal to BE8 support. Signed-off-by: Paul Brook <paul@codesourcery.com> [PMM: various changes, mostly as per my suggestions in code review: * rebase * use EF_ defines rather than hardcoded constants * make bswap_code a bool for future VMSTATE macro compatibility * update comment in cpu.h about TB flags bit field usage * factor out load-code-and-swap into arm_ld*_code functions and get_user_code* macros * fix stray trailing space at end of line * added braces in disas.c to satisfy checkpatch ] Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/elfload.c1
-rw-r--r--linux-user/main.c34
-rw-r--r--linux-user/qemu.h1
3 files changed, 31 insertions, 5 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 4ce97434e5..f3b1552e9e 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1576,6 +1576,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;
diff --git a/linux-user/main.c b/linux-user/main.c
index 23ad357b50..191b75060d 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -33,6 +33,7 @@
#include "tcg.h"
#include "qemu-timer.h"
#include "envlist.h"
+#include "elf.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
@@ -474,6 +475,22 @@ void cpu_loop(CPUX86State *env)
#ifdef TARGET_ARM
+#define get_user_code_u32(x, gaddr, doswap) \
+ ({ abi_long __r = get_user_u32((x), (gaddr)); \
+ if (!__r && (doswap)) { \
+ (x) = bswap32(x); \
+ } \
+ __r; \
+ })
+
+#define get_user_code_u16(x, gaddr, doswap) \
+ ({ abi_long __r = get_user_u16((x), (gaddr)); \
+ if (!__r && (doswap)) { \
+ (x) = bswap16(x); \
+ } \
+ __r; \
+ })
+
/*
* See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
* Input:
@@ -707,7 +724,7 @@ void cpu_loop(CPUARMState *env)
/* we handle the FPU emulation here, as Linux */
/* we get the opcode */
/* FIXME - what to do if get_user() fails? */
- get_user_u32(opcode, env->regs[15]);
+ get_user_code_u32(opcode, env->regs[15], env->bswap_code);
rc = EmulateAll(opcode, &ts->fpa, env);
if (rc == 0) { /* illegal instruction */
@@ -777,23 +794,25 @@ void cpu_loop(CPUARMState *env)
if (trapnr == EXCP_BKPT) {
if (env->thumb) {
/* FIXME - what to do if get_user() fails? */
- get_user_u16(insn, env->regs[15]);
+ get_user_code_u16(insn, env->regs[15], env->bswap_code);
n = insn & 0xff;
env->regs[15] += 2;
} else {
/* FIXME - what to do if get_user() fails? */
- get_user_u32(insn, env->regs[15]);
+ get_user_code_u32(insn, env->regs[15], env->bswap_code);
n = (insn & 0xf) | ((insn >> 4) & 0xff0);
env->regs[15] += 4;
}
} else {
if (env->thumb) {
/* FIXME - what to do if get_user() fails? */
- get_user_u16(insn, env->regs[15] - 2);
+ get_user_code_u16(insn, env->regs[15] - 2,
+ env->bswap_code);
n = insn & 0xff;
} else {
/* FIXME - what to do if get_user() fails? */
- get_user_u32(insn, env->regs[15] - 4);
+ get_user_code_u32(insn, env->regs[15] - 4,
+ env->bswap_code);
n = insn & 0xffffff;
}
}
@@ -3657,6 +3676,11 @@ int main(int argc, char **argv, char **envp)
for(i = 0; i < 16; i++) {
env->regs[i] = regs->uregs[i];
}
+ /* Enable BE8. */
+ if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
+ && (info->elf_flags & EF_ARM_BE8)) {
+ env->bswap_code = 1;
+ }
}
#elif defined(TARGET_UNICORE32)
{
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index dd74cc0510..7b299b7bc3 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -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;