From c4ab7899f273d602086ea231c8e200b64a0da7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Minier?= Date: Tue, 29 Dec 2009 22:06:13 +0100 Subject: [PATCH 1/4] linux-user: adapt uname machine to emulated CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch for linux-user adapts the output of the emulated uname() syscall to match the configured CPU. Tested with x86, x86-64 and arm emulation. Signed-off-by: Riku Voipio Signed-off-by: Loïc Minier --- Makefile.target | 2 +- linux-user/cpu-uname.c | 72 ++++++++++++++++++++++++++++++++++++++++++ linux-user/cpu-uname.h | 1 + linux-user/syscall.c | 3 +- 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 linux-user/cpu-uname.c create mode 100644 linux-user/cpu-uname.h diff --git a/Makefile.target b/Makefile.target index 5c0ef1f8c8..9dfc4c2407 100644 --- a/Makefile.target +++ b/Makefile.target @@ -95,7 +95,7 @@ $(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \ - elfload.o linuxload.o uaccess.o gdbstub.o + elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o obj-$(TARGET_HAS_BFLT) += flatload.o obj-$(TARGET_HAS_ELFLOAD32) += elfload32.o diff --git a/linux-user/cpu-uname.c b/linux-user/cpu-uname.c new file mode 100644 index 0000000000..23afedeb9b --- /dev/null +++ b/linux-user/cpu-uname.c @@ -0,0 +1,72 @@ +/* + * cpu to uname machine name map + * + * Copyright (c) 2009 Loïc Minier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include + +#include "qemu.h" +//#include "qemu-common.h" +#include "cpu-uname.h" + +/* return highest utsname machine name for emulated instruction set + * + * NB: the default emulated CPU ("any") might not match any existing CPU, e.g. + * on ARM it has all features turned on, so there is no perfect arch string to + * return here */ +const char *cpu_to_uname_machine(void *cpu_env) +{ +#ifdef TARGET_ARM + /* utsname machine name on linux arm is CPU arch name + endianness, e.g. + * armv7l; to get a list of CPU arch names from the linux source, use: + * grep arch_name: -A1 linux/arch/arm/mm/proc-*.S + * see arch/arm/kernel/setup.c: setup_processor() + * + * to test by CPU id, compare cpu_env->cp15.c0_cpuid to ARM_CPUID_* + * defines and to test by CPU feature, use arm_feature(cpu_env, + * ARM_FEATURE_*) */ + + /* in theory, endianness is configurable on some ARM CPUs, but this isn't + * used in user mode emulation */ +#ifdef TARGET_WORDS_BIGENDIAN +#define utsname_suffix "b" +#else +#define utsname_suffix "l" +#endif + if (arm_feature(cpu_env, ARM_FEATURE_V7)) + return "armv7" utsname_suffix; + if (arm_feature(cpu_env, ARM_FEATURE_V6)) + return "armv6" utsname_suffix; + /* earliest emulated CPU is ARMv5TE; qemu can emulate the 1026, but not its + * Jazelle support */ + return "armv5te" utsname_suffix; +#elif defined(TARGET_X86_64) + return "x86-64"; +#elif defined(TARGET_I386) + /* see arch/x86/kernel/cpu/bugs.c: check_bugs(), 386, 486, 586, 686 */ + uint32_t cpuid_version = ((CPUX86State *)cpu_env)->cpuid_version; + int family = ((cpuid_version >> 8) & 0x0f) + ((cpuid_version >> 20) & 0xff); + if (family == 4) + return "i486"; + if (family == 5) + return "i586"; + return "i686"; +#else + /* default is #define-d in each arch/ subdir */ + return UNAME_MACHINE; +#endif +} diff --git a/linux-user/cpu-uname.h b/linux-user/cpu-uname.h new file mode 100644 index 0000000000..32492de71a --- /dev/null +++ b/linux-user/cpu-uname.h @@ -0,0 +1 @@ +const char *cpu_to_uname_machine(void *cpu_env); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index f2dd39eb3b..9fb493fba6 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -82,6 +82,7 @@ #include #include #include "linux_loop.h" +#include "cpu-uname.h" #include "qemu.h" #include "qemu-common.h" @@ -5739,7 +5740,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!is_error(ret)) { /* Overrite the native machine name with whatever is being emulated. */ - strcpy (buf->machine, UNAME_MACHINE); + strcpy (buf->machine, cpu_to_uname_machine(cpu_env)); /* Allow the user to override the reported release. */ if (qemu_uname_release && *qemu_uname_release) strcpy (buf->release, qemu_uname_release); From 26bc95a037ef5e65afacc89082725a34ba23fdbd Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Wed, 20 Jan 2010 12:56:27 +0200 Subject: [PATCH 2/4] fix locking error with current_tb Signed-off-by: Riku Voipio --- exec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exec.c b/exec.c index 76831a194f..431e104a1c 100644 --- a/exec.c +++ b/exec.c @@ -1537,15 +1537,15 @@ static void cpu_unlink_tb(CPUState *env) TranslationBlock *tb; static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED; + spin_lock(&interrupt_lock); tb = env->current_tb; /* if the cpu is currently executing code, we must unlink it and all the potentially executing TB */ if (tb) { - spin_lock(&interrupt_lock); env->current_tb = NULL; tb_reset_jump_recursive(tb); - spin_unlock(&interrupt_lock); } + spin_unlock(&interrupt_lock); } /* mask must never be zero, except for A20 change call */ From d3219c7bd08056344f077bdc81eee71bcfc8b1c8 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Mon, 25 Jan 2010 14:30:49 +0200 Subject: [PATCH 3/4] linux-user: remove signal handler before calling abort() Qemu may hang in host_signal_handler after qemu has done a seppuku with cpu_abort(). But at this stage we are not really interested in target process coredump anymore, so unregister host_signal_handler to die grafefully. Signed-off-by: Riku Voipio --- exec.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/exec.c b/exec.c index 431e104a1c..eeb17d09fb 100644 --- a/exec.c +++ b/exec.c @@ -40,6 +40,7 @@ #include "kvm.h" #if defined(CONFIG_USER_ONLY) #include +#include #endif //#define DEBUG_TB_INVALIDATE @@ -1692,6 +1693,14 @@ void cpu_abort(CPUState *env, const char *fmt, ...) } va_end(ap2); va_end(ap); +#if defined(CONFIG_USER_ONLY) + { + struct sigaction act; + sigfillset(&act.sa_mask); + act.sa_handler = SIG_DFL; + sigaction(SIGABRT, &act, NULL); + } +#endif abort(); } From f101cd885ec148761738638ae42f7c5162b6d445 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Mon, 25 Jan 2010 15:17:32 +0200 Subject: [PATCH 4/4] target-arm: refactor cp15.c13 register access Access the cp15.c13 TLS registers directly with TCG ops instead of with a slow helper. If the the cp15 read/write was not TLS register access, fall back to the cp15 helper. This makes accessing __thread variables in linux-user when apps are compiled with -mtp=cp15 possible. legal cp15 register to acces from linux-user are already checked in cp15_user_ok. While at it, make the cp15.c13 Thread ID registers available only on ARMv6K and newer. Signed-off-by: Riku Voipio --- target-arm/helper.c | 16 ------------ target-arm/translate.c | 55 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index b3aec99442..27001e86a6 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -511,7 +511,6 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) { cpu_abort(env, "cp15 insn %08x\n", insn); - return 0; } /* These should probably raise undefined insn exceptions. */ @@ -1491,15 +1490,6 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val) tlb_flush(env, 0); env->cp15.c13_context = val; break; - case 2: - env->cp15.c13_tls1 = val; - break; - case 3: - env->cp15.c13_tls2 = val; - break; - case 4: - env->cp15.c13_tls3 = val; - break; default: goto bad_reg; } @@ -1779,12 +1769,6 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn) return env->cp15.c13_fcse; case 1: return env->cp15.c13_context; - case 2: - return env->cp15.c13_tls1; - case 3: - return env->cp15.c13_tls2; - case 4: - return env->cp15.c13_tls3; default: goto bad_reg; } diff --git a/target-arm/translate.c b/target-arm/translate.c index 5cf3e06ba6..786c3294da 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -2455,6 +2455,57 @@ static int cp15_user_ok(uint32_t insn) return 0; } +static int cp15_tls_load_store(CPUState *env, DisasContext *s, uint32_t insn, uint32_t rd) +{ + TCGv tmp; + int cpn = (insn >> 16) & 0xf; + int cpm = insn & 0xf; + int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38); + + if (!arm_feature(env, ARM_FEATURE_V6K)) + return 0; + + if (!(cpn == 13 && cpm == 0)) + return 0; + + if (insn & ARM_CP_RW_BIT) { + tmp = new_tmp(); + switch (op) { + case 2: + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls1)); + break; + case 3: + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls2)); + break; + case 4: + tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls3)); + break; + default: + dead_tmp(tmp); + return 0; + } + store_reg(s, rd, tmp); + + } else { + tmp = load_reg(s, rd); + switch (op) { + case 2: + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls1)); + break; + case 3: + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls2)); + break; + case 4: + tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, cp15.c13_tls3)); + break; + default: + return 0; + } + dead_tmp(tmp); + } + return 1; +} + /* Disassemble system coprocessor (cp15) instruction. Return nonzero if instruction is not defined. */ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) @@ -2489,6 +2540,10 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn) return 0; } rd = (insn >> 12) & 0xf; + + if (cp15_tls_load_store(env, s, insn, rd)) + return 0; + tmp2 = tcg_const_i32(insn); if (insn & ARM_CP_RW_BIT) { tmp = new_tmp();