From 8c0f0a60d48a6f62c20f4ce77dceb82047d3d57f Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 25 Mar 2014 23:21:50 +0000 Subject: linux-user: Assert stack used for auxvec, envp, argv Assert that the amount of stack space used for auxvec, envp & argv exactly matches the amount allocated. This catches if DLINFO_ITEMS isn't updated when another NEW_AUX_ENT is added. Signed-off-by: James Hogan Cc: Riku Voipio Cc: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/elfload.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux-user/elfload.c') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index d2380b6ccb..ecf6f350e3 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -1455,6 +1455,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, info->auxv_len = sp_auxv - sp; sp = loader_build_argptr(envc, argc, sp, p, 0); + /* Check the right amount of stack was allocated for auxvec, envp & argv. */ + assert(sp_auxv - sp == size); return sp; } -- cgit 1.4.1 From 43ce393ee5f7b96d2ac22fedc40d6b6fb3f65a3e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 2 May 2014 14:45:12 +0100 Subject: linux-user/elfload.c: Fix incorrect ARM HWCAP bits The ELF HWCAP bits for ARM features THUMBEE, NEON, VFPv3 and VFPv3D16 are all off by one compared to the kernel definitions. Fix this discrepancy and add in the missing CRUNCH bit which was the cause of the off-by-one error. (We don't emulate any of the CPUs which have that weird hardware, so it's otherwise uninteresting to us.) Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- linux-user/elfload.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'linux-user/elfload.c') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index ecf6f350e3..18ea1b34a1 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -346,10 +346,11 @@ enum ARM_HWCAP_ARM_EDSP = 1 << 7, ARM_HWCAP_ARM_JAVA = 1 << 8, ARM_HWCAP_ARM_IWMMXT = 1 << 9, - ARM_HWCAP_ARM_THUMBEE = 1 << 10, - ARM_HWCAP_ARM_NEON = 1 << 11, - ARM_HWCAP_ARM_VFPv3 = 1 << 12, - ARM_HWCAP_ARM_VFPv3D16 = 1 << 13, + ARM_HWCAP_ARM_CRUNCH = 1 << 10, + ARM_HWCAP_ARM_THUMBEE = 1 << 11, + ARM_HWCAP_ARM_NEON = 1 << 12, + ARM_HWCAP_ARM_VFPv3 = 1 << 13, + ARM_HWCAP_ARM_VFPv3D16 = 1 << 14, }; #ifndef TARGET_AARCH64 -- cgit 1.4.1 From 24682654654a2e7b50afc27880f4098e5fca3742 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 2 May 2014 14:45:13 +0100 Subject: linux-user/elfload.c: Update ARM HWCAP bits The kernel has added support for a number of new ARM HWCAP bits; add them to QEMU, including support for setting them where we have a corresponding CPU feature bit. We were also incorrectly setting the VFPv3D16 HWCAP -- this means "only 16 D registers", not "supports 16-bit floating point format"; since QEMU always has 32 D registers for VFPv3, we can just remove the line that incorrectly set this bit. The kernel does not set the HWCAP_FPA even if it is providing FPA emulation via nwfpe, so don't set this bit in QEMU either. Signed-off-by: Peter Maydell Cc: qemu-stable@nongnu.org Signed-off-by: Riku Voipio --- linux-user/elfload.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'linux-user/elfload.c') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 18ea1b34a1..d372300886 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -351,6 +351,13 @@ enum ARM_HWCAP_ARM_NEON = 1 << 12, ARM_HWCAP_ARM_VFPv3 = 1 << 13, ARM_HWCAP_ARM_VFPv3D16 = 1 << 14, + ARM_HWCAP_ARM_TLS = 1 << 15, + ARM_HWCAP_ARM_VFPv4 = 1 << 16, + ARM_HWCAP_ARM_IDIVA = 1 << 17, + ARM_HWCAP_ARM_IDIVT = 1 << 18, + ARM_HWCAP_ARM_VFPD32 = 1 << 19, + ARM_HWCAP_ARM_LPAE = 1 << 20, + ARM_HWCAP_ARM_EVTSTRM = 1 << 21, }; #ifndef TARGET_AARCH64 @@ -428,17 +435,28 @@ static uint32_t get_elf_hwcap(void) hwcaps |= ARM_HWCAP_ARM_HALF; hwcaps |= ARM_HWCAP_ARM_THUMB; hwcaps |= ARM_HWCAP_ARM_FAST_MULT; - hwcaps |= ARM_HWCAP_ARM_FPA; /* probe for the extra features */ #define GET_FEATURE(feat, hwcap) \ do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0) + /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */ + GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP); GET_FEATURE(ARM_FEATURE_VFP, ARM_HWCAP_ARM_VFP); GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT); GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE); GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON); GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPv3); - GET_FEATURE(ARM_FEATURE_VFP_FP16, ARM_HWCAP_ARM_VFPv3D16); + GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS); + GET_FEATURE(ARM_FEATURE_VFP4, ARM_HWCAP_ARM_VFPv4); + GET_FEATURE(ARM_FEATURE_ARM_DIV, ARM_HWCAP_ARM_IDIVA); + GET_FEATURE(ARM_FEATURE_THUMB_DIV, ARM_HWCAP_ARM_IDIVT); + /* All QEMU's VFPv3 CPUs have 32 registers, see VFP_DREG in translate.c. + * Note that the ARM_HWCAP_ARM_VFPv3D16 bit is always the inverse of + * ARM_HWCAP_ARM_VFPD32 (and so always clear for QEMU); it is unrelated + * to our VFP_FP16 feature bit. + */ + GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPD32); + GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE); #undef GET_FEATURE return hwcaps; -- cgit 1.4.1 From 24e76ff06bcd0936ee8b04b15dca42efb7d614d1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 2 May 2014 14:45:14 +0100 Subject: linux-user/elfload.c: Fix A64 code which was incorrectly acting like A32 The ARM target-specific code in elfload.c was incorrectly allowing the 64-bit ARM target to use most of the existing 32-bit definitions: most noticably this meant that our HWCAP bits passed to the guest were wrong, and register handling when dumping core was totally broken. Fix this by properly separating the 64 and 32 bit code, since they have more differences than similarities. Signed-off-by: Peter Maydell Cc: qemu-stable@nongnu.org Signed-off-by: Riku Voipio --- linux-user/elfload.c | 86 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 13 deletions(-) (limited to 'linux-user/elfload.c') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index d372300886..ad07c43e75 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -267,17 +267,15 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en #ifdef TARGET_ARM +#ifndef TARGET_AARCH64 +/* 32 bit ARM definitions */ + #define ELF_START_MMAP 0x80000000 #define elf_check_arch(x) ((x) == ELF_MACHINE) #define ELF_ARCH ELF_MACHINE - -#ifdef TARGET_AARCH64 -#define ELF_CLASS ELFCLASS64 -#else #define ELF_CLASS ELFCLASS32 -#endif static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) @@ -285,10 +283,6 @@ static inline void init_thread(struct target_pt_regs *regs, abi_long stack = infop->start_stack; memset(regs, 0, sizeof(*regs)); -#ifdef TARGET_AARCH64 - regs->pc = infop->entry & ~0x3ULL; - regs->sp = stack; -#else regs->ARM_cpsr = 0x10; if (infop->entry & 1) regs->ARM_cpsr |= CPSR_T; @@ -302,7 +296,6 @@ static inline void init_thread(struct target_pt_regs *regs, /* For uClinux PIC binaries. */ /* XXX: Linux does this only on ARM with no MMU (do we care ?) */ regs->ARM_r10 = infop->start_data; -#endif } #define ELF_NREG 18 @@ -360,7 +353,6 @@ enum ARM_HWCAP_ARM_EVTSTRM = 1 << 21, }; -#ifndef TARGET_AARCH64 /* The commpage only exists for 32 bit kernels */ #define TARGET_HAS_VALIDATE_GUEST_SPACE @@ -422,7 +414,6 @@ static int validate_guest_space(unsigned long guest_base, return 1; /* All good */ } -#endif #define ELF_HWCAP get_elf_hwcap() @@ -462,7 +453,76 @@ static uint32_t get_elf_hwcap(void) return hwcaps; } -#endif +#else +/* 64 bit ARM definitions */ +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ((x) == ELF_MACHINE) + +#define ELF_ARCH ELF_MACHINE +#define ELF_CLASS ELFCLASS64 +#define ELF_PLATFORM "aarch64" + +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + abi_long stack = infop->start_stack; + memset(regs, 0, sizeof(*regs)); + + regs->pc = infop->entry & ~0x3ULL; + regs->sp = stack; +} + +#define ELF_NREG 34 +typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; + +static void elf_core_copy_regs(target_elf_gregset_t *regs, + const CPUARMState *env) +{ + int i; + + for (i = 0; i < 32; i++) { + (*regs)[i] = tswapreg(env->xregs[i]); + } + (*regs)[32] = tswapreg(env->pc); + (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env)); +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +enum { + ARM_HWCAP_A64_FP = 1 << 0, + ARM_HWCAP_A64_ASIMD = 1 << 1, + ARM_HWCAP_A64_EVTSTRM = 1 << 2, + ARM_HWCAP_A64_AES = 1 << 3, + ARM_HWCAP_A64_PMULL = 1 << 4, + ARM_HWCAP_A64_SHA1 = 1 << 5, + ARM_HWCAP_A64_SHA2 = 1 << 6, + ARM_HWCAP_A64_CRC32 = 1 << 7, +}; + +#define ELF_HWCAP get_elf_hwcap() + +static uint32_t get_elf_hwcap(void) +{ + ARMCPU *cpu = ARM_CPU(thread_cpu); + uint32_t hwcaps = 0; + + hwcaps |= ARM_HWCAP_A64_FP; + hwcaps |= ARM_HWCAP_A64_ASIMD; + + /* probe for the extra features */ +#define GET_FEATURE(feat, hwcap) \ + do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0) + GET_FEATURE(ARM_FEATURE_V8_AES, ARM_HWCAP_A64_PMULL); +#undef GET_FEATURE + + return hwcaps; +} + +#endif /* not TARGET_AARCH64 */ +#endif /* TARGET_ARM */ #ifdef TARGET_UNICORE32 -- cgit 1.4.1 From ad6919dc0ab3b8ae26d772e883aa8e709785d249 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 2 May 2014 14:45:15 +0100 Subject: linux-user/elfload.c: Support ARM HWCAP2 flags The ARM kernel has chosen to spill into the HWCAP2 ELF feature bit flags early, even though it hasn't yet exhausted all 32 bits of the HWCAP word. Add support for setting this in the same way we do for HWCAP. Signed-off-by: Peter Maydell Signed-off-by: Riku Voipio --- include/elf.h | 1 + linux-user/elfload.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'linux-user/elfload.c') diff --git a/include/elf.h b/include/elf.h index 667af6fc63..1599ab22d8 100644 --- a/include/elf.h +++ b/include/elf.h @@ -254,6 +254,7 @@ typedef int64_t Elf64_Sxword; #define AT_SECURE 23 /* boolean, was exec suid-like? */ #define AT_BASE_PLATFORM 24 /* string identifying real platforms */ #define AT_RANDOM 25 /* address of 16 random bytes */ +#define AT_HWCAP2 26 /* extension of AT_HWCAP */ #define AT_EXECFN 31 /* filename of the executable */ #define AT_SYSINFO 32 /* address of kernel entry point */ #define AT_SYSINFO_EHDR 33 /* address of kernel vdso */ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index ad07c43e75..995f999768 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -20,6 +20,7 @@ #undef ARCH_DLINFO #undef ELF_PLATFORM #undef ELF_HWCAP +#undef ELF_HWCAP2 #undef ELF_CLASS #undef ELF_DATA #undef ELF_ARCH @@ -353,6 +354,14 @@ enum ARM_HWCAP_ARM_EVTSTRM = 1 << 21, }; +enum { + ARM_HWCAP2_ARM_AES = 1 << 0, + ARM_HWCAP2_ARM_PMULL = 1 << 1, + ARM_HWCAP2_ARM_SHA1 = 1 << 2, + ARM_HWCAP2_ARM_SHA2 = 1 << 3, + ARM_HWCAP2_ARM_CRC32 = 1 << 4, +}; + /* The commpage only exists for 32 bit kernels */ #define TARGET_HAS_VALIDATE_GUEST_SPACE @@ -416,6 +425,7 @@ static int validate_guest_space(unsigned long guest_base, } #define ELF_HWCAP get_elf_hwcap() +#define ELF_HWCAP2 get_elf_hwcap2() static uint32_t get_elf_hwcap(void) { @@ -448,11 +458,22 @@ static uint32_t get_elf_hwcap(void) */ GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPD32); GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE); -#undef GET_FEATURE return hwcaps; } +static uint32_t get_elf_hwcap2(void) +{ + ARMCPU *cpu = ARM_CPU(thread_cpu); + uint32_t hwcaps = 0; + + GET_FEATURE(ARM_FEATURE_V8_AES, ARM_HWCAP2_ARM_AES); + GET_FEATURE(ARM_FEATURE_CRC, ARM_HWCAP2_ARM_CRC32); + return hwcaps; +} + +#undef GET_FEATURE + #else /* 64 bit ARM definitions */ #define ELF_START_MMAP 0x80000000 @@ -1485,6 +1506,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, size += 2; #ifdef DLINFO_ARCH_ITEMS size += DLINFO_ARCH_ITEMS * 2; +#endif +#ifdef ELF_HWCAP2 + size += 2; #endif size += envc + argc + 2; size += 1; /* argc itself */ @@ -1519,6 +1543,10 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc, NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK)); NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes); +#ifdef ELF_HWCAP2 + NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2); +#endif + if (k_platform) NEW_AUX_ENT(AT_PLATFORM, u_platform); #ifdef ARCH_DLINFO -- cgit 1.4.1