summaryrefslogtreecommitdiffstats
path: root/qemu/linux-user/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/linux-user/main.c')
-rw-r--r--qemu/linux-user/main.c561
1 files changed, 427 insertions, 134 deletions
diff --git a/qemu/linux-user/main.c b/qemu/linux-user/main.c
index fdee98135..5f3ec9747 100644
--- a/qemu/linux-user/main.c
+++ b/qemu/linux-user/main.c
@@ -16,36 +16,45 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
+#include "qemu/osdep.h"
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/resource.h>
#include "qemu.h"
-#include "qemu-common.h"
+#include "qemu/path.h"
+#include "qemu/cutils.h"
+#include "qemu/help_option.h"
#include "cpu.h"
#include "tcg.h"
#include "qemu/timer.h"
#include "qemu/envlist.h"
#include "elf.h"
+#include "exec/log.h"
char *exec_path;
int singlestep;
-const char *filename;
-const char *argv0;
-int gdbstub_port;
-envlist_t *envlist;
+static const char *filename;
+static const char *argv0;
+static int gdbstub_port;
+static envlist_t *envlist;
static const char *cpu_model;
unsigned long mmap_min_addr;
-#if defined(CONFIG_USE_GUEST_BASE)
unsigned long guest_base;
int have_guest_base;
+
+#define EXCP_DUMP(env, fmt, ...) \
+do { \
+ CPUState *cs = ENV_GET_CPU(env); \
+ fprintf(stderr, fmt , ## __VA_ARGS__); \
+ cpu_dump_state(cs, stderr, fprintf, 0); \
+ if (qemu_log_separate()) { \
+ qemu_log(fmt, ## __VA_ARGS__); \
+ log_cpu_state(cs, 0); \
+ } \
+} while (0)
+
#if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64)
/*
* When running 32-on-64 we should make sure we can fit all of the possible
@@ -63,9 +72,8 @@ unsigned long reserved_va = 0xf7000000;
#else
unsigned long reserved_va;
#endif
-#endif
-static void usage(void);
+static void usage(int exitcode);
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release;
@@ -107,7 +115,7 @@ static int pending_cpus;
/* Make sure everything is in a consistent state for calling fork(). */
void fork_start(void)
{
- pthread_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
+ qemu_mutex_lock(&tcg_ctx.tb_ctx.tb_lock);
pthread_mutex_lock(&exclusive_lock);
mmap_fork_start();
}
@@ -129,11 +137,11 @@ void fork_end(int child)
pthread_mutex_init(&cpu_list_mutex, NULL);
pthread_cond_init(&exclusive_cond, NULL);
pthread_cond_init(&exclusive_resume, NULL);
- pthread_mutex_init(&tcg_ctx.tb_ctx.tb_lock, NULL);
+ qemu_mutex_init(&tcg_ctx.tb_ctx.tb_lock);
gdbserver_fork(thread_cpu);
} else {
pthread_mutex_unlock(&exclusive_lock);
- pthread_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
+ qemu_mutex_unlock(&tcg_ctx.tb_ctx.tb_lock);
}
}
@@ -217,7 +225,7 @@ void cpu_list_unlock(void)
uint64_t cpu_get_tsc(CPUX86State *env)
{
- return cpu_get_real_ticks();
+ return cpu_get_host_ticks();
}
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
@@ -418,8 +426,8 @@ void cpu_loop(CPUX86State *env)
break;
default:
pc = env->segs[R_CS].base + env->eip;
- fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
- (long)pc, trapnr);
+ EXCP_DUMP(env, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
+ (long)pc, trapnr);
abort();
}
process_pending_signals(env);
@@ -429,22 +437,54 @@ void cpu_loop(CPUX86State *env)
#ifdef TARGET_ARM
-#define get_user_code_u32(x, gaddr, doswap) \
+#define get_user_code_u32(x, gaddr, env) \
({ abi_long __r = get_user_u32((x), (gaddr)); \
- if (!__r && (doswap)) { \
+ if (!__r && bswap_code(arm_sctlr_b(env))) { \
(x) = bswap32(x); \
} \
__r; \
})
-#define get_user_code_u16(x, gaddr, doswap) \
+#define get_user_code_u16(x, gaddr, env) \
({ abi_long __r = get_user_u16((x), (gaddr)); \
- if (!__r && (doswap)) { \
+ if (!__r && bswap_code(arm_sctlr_b(env))) { \
(x) = bswap16(x); \
} \
__r; \
})
+#define get_user_data_u32(x, gaddr, env) \
+ ({ abi_long __r = get_user_u32((x), (gaddr)); \
+ if (!__r && arm_cpu_bswap_data(env)) { \
+ (x) = bswap32(x); \
+ } \
+ __r; \
+ })
+
+#define get_user_data_u16(x, gaddr, env) \
+ ({ abi_long __r = get_user_u16((x), (gaddr)); \
+ if (!__r && arm_cpu_bswap_data(env)) { \
+ (x) = bswap16(x); \
+ } \
+ __r; \
+ })
+
+#define put_user_data_u32(x, gaddr, env) \
+ ({ typeof(x) __x = (x); \
+ if (arm_cpu_bswap_data(env)) { \
+ __x = bswap32(__x); \
+ } \
+ put_user_u32(__x, (gaddr)); \
+ })
+
+#define put_user_data_u16(x, gaddr, env) \
+ ({ typeof(x) __x = (x); \
+ if (arm_cpu_bswap_data(env)) { \
+ __x = bswap16(__x); \
+ } \
+ put_user_u16(__x, (gaddr)); \
+ })
+
#ifdef TARGET_ABI32
/* Commpage handling -- there is no commpage for AArch64 */
@@ -507,7 +547,7 @@ static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
env->regs[0] = -1;
cpsr &= ~CPSR_C;
}
- cpsr_write(env, cpsr, CPSR_C);
+ cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
end_exclusive();
return;
@@ -556,7 +596,7 @@ do_kernel_trap(CPUARMState *env)
env->regs[0] = -1;
cpsr &= ~CPSR_C;
}
- cpsr_write(env, cpsr, CPSR_C);
+ cpsr_write(env, cpsr, CPSR_C, CPSRWriteByInstr);
end_exclusive();
break;
case 0xffff0fe0: /* __kernel_get_tls */
@@ -604,11 +644,11 @@ static int do_strex(CPUARMState *env)
segv = get_user_u8(val, addr);
break;
case 1:
- segv = get_user_u16(val, addr);
+ segv = get_user_data_u16(val, addr, env);
break;
case 2:
case 3:
- segv = get_user_u32(val, addr);
+ segv = get_user_data_u32(val, addr, env);
break;
default:
abort();
@@ -619,12 +659,16 @@ static int do_strex(CPUARMState *env)
}
if (size == 3) {
uint32_t valhi;
- segv = get_user_u32(valhi, addr + 4);
+ segv = get_user_data_u32(valhi, addr + 4, env);
if (segv) {
env->exception.vaddress = addr + 4;
goto done;
}
- val = deposit64(val, 32, 32, valhi);
+ if (arm_cpu_bswap_data(env)) {
+ val = deposit64((uint64_t)valhi, 32, 32, val);
+ } else {
+ val = deposit64(val, 32, 32, valhi);
+ }
}
if (val != env->exclusive_val) {
goto fail;
@@ -636,11 +680,11 @@ static int do_strex(CPUARMState *env)
segv = put_user_u8(val, addr);
break;
case 1:
- segv = put_user_u16(val, addr);
+ segv = put_user_data_u16(val, addr, env);
break;
case 2:
case 3:
- segv = put_user_u32(val, addr);
+ segv = put_user_data_u32(val, addr, env);
break;
}
if (segv) {
@@ -649,7 +693,7 @@ static int do_strex(CPUARMState *env)
}
if (size == 3) {
val = env->regs[(env->exclusive_info >> 12) & 0xf];
- segv = put_user_u32(val, addr + 4);
+ segv = put_user_data_u32(val, addr + 4, env);
if (segv) {
env->exception.vaddress = addr + 4;
goto done;
@@ -686,7 +730,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_code_u32(opcode, env->regs[15], env->bswap_code);
+ get_user_code_u32(opcode, env->regs[15], env);
rc = EmulateAll(opcode, &ts->fpa, env);
if (rc == 0) { /* illegal instruction */
@@ -756,25 +800,23 @@ void cpu_loop(CPUARMState *env)
if (trapnr == EXCP_BKPT) {
if (env->thumb) {
/* FIXME - what to do if get_user() fails? */
- get_user_code_u16(insn, env->regs[15], env->bswap_code);
+ get_user_code_u16(insn, env->regs[15], env);
n = insn & 0xff;
env->regs[15] += 2;
} else {
/* FIXME - what to do if get_user() fails? */
- get_user_code_u32(insn, env->regs[15], env->bswap_code);
+ get_user_code_u32(insn, env->regs[15], env);
n = (insn & 0xf) | ((insn >> 4) & 0xff0);
env->regs[15] += 4;
}
} else {
if (env->thumb) {
/* FIXME - what to do if get_user() fails? */
- get_user_code_u16(insn, env->regs[15] - 2,
- env->bswap_code);
+ get_user_code_u16(insn, env->regs[15] - 2, env);
n = insn & 0xff;
} else {
/* FIXME - what to do if get_user() fails? */
- get_user_code_u32(insn, env->regs[15] - 4,
- env->bswap_code);
+ get_user_code_u32(insn, env->regs[15] - 4, env);
n = insn & 0xffffff;
}
}
@@ -865,11 +907,12 @@ void cpu_loop(CPUARMState *env)
if (do_kernel_trap(env))
goto error;
break;
+ case EXCP_YIELD:
+ /* nothing to do here for user-mode, just resume guest code */
+ break;
default:
error:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
- trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
abort();
}
process_pending_signals(env);
@@ -1054,10 +1097,14 @@ void cpu_loop(CPUARMState *env)
queue_signal(env, info.si_signo, &info);
}
break;
+ case EXCP_SEMIHOST:
+ env->xregs[0] = do_arm_semihosting(env);
+ break;
+ case EXCP_YIELD:
+ /* nothing to do here for user-mode, just resume guest code */
+ break;
default:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
- trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
abort();
}
process_pending_signals(env);
@@ -1147,8 +1194,7 @@ void cpu_loop(CPUUniCore32State *env)
}
error:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
abort();
}
#endif
@@ -1413,7 +1459,7 @@ void cpu_loop (CPUSPARCState *env)
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -1424,7 +1470,7 @@ void cpu_loop (CPUSPARCState *env)
#ifdef TARGET_PPC
static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
{
- return cpu_get_real_ticks();
+ return cpu_get_host_ticks();
}
uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
@@ -1466,17 +1512,6 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
return -1;
}
-#define EXCP_DUMP(env, fmt, ...) \
-do { \
- CPUState *cs = ENV_GET_CPU(env); \
- fprintf(stderr, fmt , ## __VA_ARGS__); \
- cpu_dump_state(cs, stderr, fprintf, 0); \
- qemu_log(fmt, ## __VA_ARGS__); \
- if (qemu_log_enabled()) { \
- log_cpu_state(cs, 0); \
- } \
-} while (0)
-
static int do_store_exclusive(CPUPPCState *env)
{
target_ulong addr;
@@ -1649,7 +1684,7 @@ void cpu_loop(CPUPPCState *env)
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->nip - 4;
+ info._sifields._sigfault._addr = env->nip;
queue_signal(env, info.si_signo, &info);
break;
case POWERPC_EXCP_PROGRAM: /* Program exception */
@@ -2635,9 +2670,7 @@ done_syscall:
break;
default:
error:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
- trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
abort();
}
process_pending_signals(env);
@@ -2660,11 +2693,11 @@ void cpu_loop(CPUOpenRISCState *env)
switch (trapnr) {
case EXCP_RESET:
- qemu_log("\nReset request, exit, pc is %#x\n", env->pc);
- exit(1);
+ qemu_log_mask(CPU_LOG_INT, "\nReset request, exit, pc is %#x\n", env->pc);
+ exit(EXIT_FAILURE);
break;
case EXCP_BUSERR:
- qemu_log("\nBus error, exit, pc is %#x\n", env->pc);
+ qemu_log_mask(CPU_LOG_INT, "\nBus error, exit, pc is %#x\n", env->pc);
gdbsig = TARGET_SIGBUS;
break;
case EXCP_DPF:
@@ -2673,25 +2706,25 @@ void cpu_loop(CPUOpenRISCState *env)
gdbsig = TARGET_SIGSEGV;
break;
case EXCP_TICK:
- qemu_log("\nTick time interrupt pc is %#x\n", env->pc);
+ qemu_log_mask(CPU_LOG_INT, "\nTick time interrupt pc is %#x\n", env->pc);
break;
case EXCP_ALIGN:
- qemu_log("\nAlignment pc is %#x\n", env->pc);
+ qemu_log_mask(CPU_LOG_INT, "\nAlignment pc is %#x\n", env->pc);
gdbsig = TARGET_SIGBUS;
break;
case EXCP_ILLEGAL:
- qemu_log("\nIllegal instructionpc is %#x\n", env->pc);
+ qemu_log_mask(CPU_LOG_INT, "\nIllegal instructionpc is %#x\n", env->pc);
gdbsig = TARGET_SIGILL;
break;
case EXCP_INT:
- qemu_log("\nExternal interruptpc is %#x\n", env->pc);
+ qemu_log_mask(CPU_LOG_INT, "\nExternal interruptpc is %#x\n", env->pc);
break;
case EXCP_DTLBMISS:
case EXCP_ITLBMISS:
- qemu_log("\nTLB miss\n");
+ qemu_log_mask(CPU_LOG_INT, "\nTLB miss\n");
break;
case EXCP_RANGE:
- qemu_log("\nRange\n");
+ qemu_log_mask(CPU_LOG_INT, "\nRange\n");
gdbsig = TARGET_SIGSEGV;
break;
case EXCP_SYSCALL:
@@ -2706,26 +2739,25 @@ void cpu_loop(CPUOpenRISCState *env)
env->gpr[8], 0, 0);
break;
case EXCP_FPE:
- qemu_log("\nFloating point error\n");
+ qemu_log_mask(CPU_LOG_INT, "\nFloating point error\n");
break;
case EXCP_TRAP:
- qemu_log("\nTrap\n");
+ qemu_log_mask(CPU_LOG_INT, "\nTrap\n");
gdbsig = TARGET_SIGTRAP;
break;
case EXCP_NR:
- qemu_log("\nNR\n");
+ qemu_log_mask(CPU_LOG_INT, "\nNR\n");
break;
default:
- qemu_log("\nqemu: unhandled CPU exception %#x - aborting\n",
+ EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
gdbsig = TARGET_SIGILL;
break;
}
if (gdbsig) {
gdb_handlesig(cs, gdbsig);
if (gdbsig != TARGET_SIGTRAP) {
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -2790,7 +2822,7 @@ void cpu_loop(CPUSH4State *env)
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -2851,7 +2883,7 @@ void cpu_loop(CPUCRISState *env)
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -2932,7 +2964,7 @@ void cpu_loop(CPUMBState *env)
printf ("Unhandled hw-exception: 0x%x\n",
env->sregs[SR_ESR] & ESR_EC_MASK);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
break;
}
break;
@@ -2953,7 +2985,7 @@ void cpu_loop(CPUMBState *env)
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -3046,9 +3078,7 @@ void cpu_loop(CPUM68KState *env)
}
break;
default:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
- trapnr);
- cpu_dump_state(cs, stderr, fprintf, 0);
+ EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr);
abort();
}
process_pending_signals(env);
@@ -3122,17 +3152,17 @@ void cpu_loop(CPUAlphaState *env)
switch (trapnr) {
case EXCP_RESET:
fprintf(stderr, "Reset requested. Exit\n");
- exit(1);
+ exit(EXIT_FAILURE);
break;
case EXCP_MCHK:
fprintf(stderr, "Machine check exception. Exit\n");
- exit(1);
+ exit(EXIT_FAILURE);
break;
case EXCP_SMP_INTERRUPT:
case EXCP_CLK_INTERRUPT:
case EXCP_DEV_INTERRUPT:
fprintf(stderr, "External interrupt. Exit\n");
- exit(1);
+ exit(EXIT_FAILURE);
break;
case EXCP_MMFAULT:
env->lock_addr = -1;
@@ -3282,7 +3312,7 @@ void cpu_loop(CPUAlphaState *env)
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit (1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -3386,7 +3416,7 @@ void cpu_loop(CPUS390XState *env)
default:
fprintf(stderr, "Unhandled program exception: %#x\n", n);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit(1);
+ exit(EXIT_FAILURE);
}
break;
@@ -3403,7 +3433,7 @@ void cpu_loop(CPUS390XState *env)
default:
fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(cs, stderr, fprintf, 0);
- exit(1);
+ exit(EXIT_FAILURE);
}
process_pending_signals (env);
}
@@ -3411,6 +3441,252 @@ void cpu_loop(CPUS390XState *env)
#endif /* TARGET_S390X */
+#ifdef TARGET_TILEGX
+
+static void gen_sigill_reg(CPUTLGState *env)
+{
+ target_siginfo_t info;
+
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_PRVREG;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, &info);
+}
+
+static void do_signal(CPUTLGState *env, int signo, int sigcode)
+{
+ target_siginfo_t info;
+
+ info.si_signo = signo;
+ info.si_errno = 0;
+ info._sifields._sigfault._addr = env->pc;
+
+ if (signo == TARGET_SIGSEGV) {
+ /* The passed in sigcode is a dummy; check for a page mapping
+ and pass either MAPERR or ACCERR. */
+ target_ulong addr = env->excaddr;
+ info._sifields._sigfault._addr = addr;
+ if (page_check_range(addr, 1, PAGE_VALID) < 0) {
+ sigcode = TARGET_SEGV_MAPERR;
+ } else {
+ sigcode = TARGET_SEGV_ACCERR;
+ }
+ }
+ info.si_code = sigcode;
+
+ queue_signal(env, info.si_signo, &info);
+}
+
+static void gen_sigsegv_maperr(CPUTLGState *env, target_ulong addr)
+{
+ env->excaddr = addr;
+ do_signal(env, TARGET_SIGSEGV, 0);
+}
+
+static void set_regval(CPUTLGState *env, uint8_t reg, uint64_t val)
+{
+ if (unlikely(reg >= TILEGX_R_COUNT)) {
+ switch (reg) {
+ case TILEGX_R_SN:
+ case TILEGX_R_ZERO:
+ return;
+ case TILEGX_R_IDN0:
+ case TILEGX_R_IDN1:
+ case TILEGX_R_UDN0:
+ case TILEGX_R_UDN1:
+ case TILEGX_R_UDN2:
+ case TILEGX_R_UDN3:
+ gen_sigill_reg(env);
+ return;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ env->regs[reg] = val;
+}
+
+/*
+ * Compare the 8-byte contents of the CmpValue SPR with the 8-byte value in
+ * memory at the address held in the first source register. If the values are
+ * not equal, then no memory operation is performed. If the values are equal,
+ * the 8-byte quantity from the second source register is written into memory
+ * at the address held in the first source register. In either case, the result
+ * of the instruction is the value read from memory. The compare and write to
+ * memory are atomic and thus can be used for synchronization purposes. This
+ * instruction only operates for addresses aligned to a 8-byte boundary.
+ * Unaligned memory access causes an Unaligned Data Reference interrupt.
+ *
+ * Functional Description (64-bit)
+ * uint64_t memVal = memoryReadDoubleWord (rf[SrcA]);
+ * rf[Dest] = memVal;
+ * if (memVal == SPR[CmpValueSPR])
+ * memoryWriteDoubleWord (rf[SrcA], rf[SrcB]);
+ *
+ * Functional Description (32-bit)
+ * uint64_t memVal = signExtend32 (memoryReadWord (rf[SrcA]));
+ * rf[Dest] = memVal;
+ * if (memVal == signExtend32 (SPR[CmpValueSPR]))
+ * memoryWriteWord (rf[SrcA], rf[SrcB]);
+ *
+ *
+ * This function also processes exch and exch4 which need not process SPR.
+ */
+static void do_exch(CPUTLGState *env, bool quad, bool cmp)
+{
+ target_ulong addr;
+ target_long val, sprval;
+
+ start_exclusive();
+
+ addr = env->atomic_srca;
+ if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
+ goto sigsegv_maperr;
+ }
+
+ if (cmp) {
+ if (quad) {
+ sprval = env->spregs[TILEGX_SPR_CMPEXCH];
+ } else {
+ sprval = sextract64(env->spregs[TILEGX_SPR_CMPEXCH], 0, 32);
+ }
+ }
+
+ if (!cmp || val == sprval) {
+ target_long valb = env->atomic_srcb;
+ if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
+ goto sigsegv_maperr;
+ }
+ }
+
+ set_regval(env, env->atomic_dstr, val);
+ end_exclusive();
+ return;
+
+ sigsegv_maperr:
+ end_exclusive();
+ gen_sigsegv_maperr(env, addr);
+}
+
+static void do_fetch(CPUTLGState *env, int trapnr, bool quad)
+{
+ int8_t write = 1;
+ target_ulong addr;
+ target_long val, valb;
+
+ start_exclusive();
+
+ addr = env->atomic_srca;
+ valb = env->atomic_srcb;
+ if (quad ? get_user_s64(val, addr) : get_user_s32(val, addr)) {
+ goto sigsegv_maperr;
+ }
+
+ switch (trapnr) {
+ case TILEGX_EXCP_OPCODE_FETCHADD:
+ case TILEGX_EXCP_OPCODE_FETCHADD4:
+ valb += val;
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
+ valb += val;
+ if (valb < 0) {
+ write = 0;
+ }
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
+ valb += val;
+ if ((int32_t)valb < 0) {
+ write = 0;
+ }
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHAND:
+ case TILEGX_EXCP_OPCODE_FETCHAND4:
+ valb &= val;
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHOR:
+ case TILEGX_EXCP_OPCODE_FETCHOR4:
+ valb |= val;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ if (write) {
+ if (quad ? put_user_u64(valb, addr) : put_user_u32(valb, addr)) {
+ goto sigsegv_maperr;
+ }
+ }
+
+ set_regval(env, env->atomic_dstr, val);
+ end_exclusive();
+ return;
+
+ sigsegv_maperr:
+ end_exclusive();
+ gen_sigsegv_maperr(env, addr);
+}
+
+void cpu_loop(CPUTLGState *env)
+{
+ CPUState *cs = CPU(tilegx_env_get_cpu(env));
+ int trapnr;
+
+ while (1) {
+ cpu_exec_start(cs);
+ trapnr = cpu_tilegx_exec(cs);
+ cpu_exec_end(cs);
+ switch (trapnr) {
+ case TILEGX_EXCP_SYSCALL:
+ env->regs[TILEGX_R_RE] = do_syscall(env, env->regs[TILEGX_R_NR],
+ env->regs[0], env->regs[1],
+ env->regs[2], env->regs[3],
+ env->regs[4], env->regs[5],
+ env->regs[6], env->regs[7]);
+ env->regs[TILEGX_R_ERR] = TILEGX_IS_ERRNO(env->regs[TILEGX_R_RE])
+ ? - env->regs[TILEGX_R_RE]
+ : 0;
+ break;
+ case TILEGX_EXCP_OPCODE_EXCH:
+ do_exch(env, true, false);
+ break;
+ case TILEGX_EXCP_OPCODE_EXCH4:
+ do_exch(env, false, false);
+ break;
+ case TILEGX_EXCP_OPCODE_CMPEXCH:
+ do_exch(env, true, true);
+ break;
+ case TILEGX_EXCP_OPCODE_CMPEXCH4:
+ do_exch(env, false, true);
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADD:
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ:
+ case TILEGX_EXCP_OPCODE_FETCHAND:
+ case TILEGX_EXCP_OPCODE_FETCHOR:
+ do_fetch(env, trapnr, true);
+ break;
+ case TILEGX_EXCP_OPCODE_FETCHADD4:
+ case TILEGX_EXCP_OPCODE_FETCHADDGEZ4:
+ case TILEGX_EXCP_OPCODE_FETCHAND4:
+ case TILEGX_EXCP_OPCODE_FETCHOR4:
+ do_fetch(env, trapnr, false);
+ break;
+ case TILEGX_EXCP_SIGNAL:
+ do_signal(env, env->signo, env->sigcode);
+ break;
+ case TILEGX_EXCP_REG_IDN_ACCESS:
+ case TILEGX_EXCP_REG_UDN_ACCESS:
+ gen_sigill_reg(env);
+ break;
+ default:
+ fprintf(stderr, "trapnr is %d[0x%x].\n", trapnr, trapnr);
+ g_assert_not_reached();
+ }
+ process_pending_signals(env);
+ }
+}
+
+#endif
+
THREAD CPUState *thread_cpu;
void task_settid(TaskState *ts)
@@ -3472,7 +3748,7 @@ CPUArchState *cpu_copy(CPUArchState *env)
static void handle_arg_help(const char *arg)
{
- usage();
+ usage(EXIT_SUCCESS);
}
static void handle_arg_log(const char *arg)
@@ -3482,7 +3758,7 @@ static void handle_arg_log(const char *arg)
mask = qemu_str_to_log_mask(arg);
if (!mask) {
qemu_print_log_usage(stdout);
- exit(1);
+ exit(EXIT_FAILURE);
}
qemu_set_log(mask);
}
@@ -3498,7 +3774,7 @@ static void handle_arg_set_env(const char *arg)
r = p = strdup(arg);
while ((token = strsep(&p, ",")) != NULL) {
if (envlist_setenv(envlist, token) != 0) {
- usage();
+ usage(EXIT_FAILURE);
}
}
free(r);
@@ -3510,7 +3786,7 @@ static void handle_arg_unset_env(const char *arg)
r = p = strdup(arg);
while ((token = strsep(&p, ",")) != NULL) {
if (envlist_unsetenv(envlist, token) != 0) {
- usage();
+ usage(EXIT_FAILURE);
}
}
free(r);
@@ -3526,7 +3802,7 @@ static void handle_arg_stack_size(const char *arg)
char *p;
guest_stack_size = strtoul(arg, &p, 0);
if (guest_stack_size == 0) {
- usage();
+ usage(EXIT_FAILURE);
}
if (*p == 'M') {
@@ -3547,7 +3823,7 @@ static void handle_arg_pagesize(const char *arg)
if (qemu_host_page_size == 0 ||
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
fprintf(stderr, "page size must be a power of two\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
}
@@ -3557,7 +3833,7 @@ static void handle_arg_randseed(const char *arg)
if (parse_uint_full(arg, &seed, 0) != 0 || seed > UINT_MAX) {
fprintf(stderr, "Invalid seed number: %s\n", arg);
- exit(1);
+ exit(EXIT_FAILURE);
}
srand(seed);
}
@@ -3580,11 +3856,10 @@ static void handle_arg_cpu(const char *arg)
#if defined(cpu_list)
cpu_list(stdout, &fprintf);
#endif
- exit(1);
+ exit(EXIT_FAILURE);
}
}
-#if defined(CONFIG_USE_GUEST_BASE)
static void handle_arg_guest_base(const char *arg)
{
guest_base = strtol(arg, NULL, 0);
@@ -3618,15 +3893,14 @@ static void handle_arg_reserved_va(const char *arg)
#endif
) {
fprintf(stderr, "Reserved virtual address too big\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
}
if (*p) {
fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
- exit(1);
+ exit(EXIT_FAILURE);
}
}
-#endif
static void handle_arg_singlestep(const char *arg)
{
@@ -3642,7 +3916,7 @@ static void handle_arg_version(const char *arg)
{
printf("qemu-" TARGET_NAME " version " QEMU_VERSION QEMU_PKGVERSION
", Copyright (c) 2003-2008 Fabrice Bellard\n");
- exit(0);
+ exit(EXIT_SUCCESS);
}
struct qemu_argument {
@@ -3657,6 +3931,8 @@ struct qemu_argument {
static const struct qemu_argument arg_table[] = {
{"h", "", false, handle_arg_help,
"", "print this help"},
+ {"help", "", false, handle_arg_help,
+ "", ""},
{"g", "QEMU_GDB", true, handle_arg_gdb,
"port", "wait gdb connection to 'port'"},
{"L", "QEMU_LD_PREFIX", true, handle_arg_ld_prefix,
@@ -3673,12 +3949,10 @@ static const struct qemu_argument arg_table[] = {
"argv0", "forces target process argv[0] to be 'argv0'"},
{"r", "QEMU_UNAME", true, handle_arg_uname,
"uname", "set qemu uname release string to 'uname'"},
-#if defined(CONFIG_USE_GUEST_BASE)
{"B", "QEMU_GUEST_BASE", true, handle_arg_guest_base,
"address", "set guest_base address to 'address'"},
{"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va,
"size", "reserve 'size' bytes for guest virtual address space"},
-#endif
{"d", "QEMU_LOG", true, handle_arg_log,
"item[,...]", "enable logging of specified items "
"(use '-d help' for a list of items)"},
@@ -3697,7 +3971,7 @@ static const struct qemu_argument arg_table[] = {
{NULL, NULL, false, NULL, NULL, NULL}
};
-static void usage(void)
+static void usage(int exitcode)
{
const struct qemu_argument *arginfo;
int maxarglen;
@@ -3764,7 +4038,7 @@ static void usage(void)
"Note that if you provide several changes to a single variable\n"
"the last change will stay in effect.\n");
- exit(1);
+ exit(exitcode);
}
static int parse_args(int argc, char **argv)
@@ -3798,12 +4072,18 @@ static int parse_args(int argc, char **argv)
if (!strcmp(r, "-")) {
break;
}
+ /* Treat --foo the same as -foo. */
+ if (r[0] == '-') {
+ r++;
+ }
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (!strcmp(r, arginfo->argv)) {
if (arginfo->has_arg) {
if (optind >= argc) {
- usage();
+ (void) fprintf(stderr,
+ "qemu: missing argument for option '%s'\n", r);
+ exit(EXIT_FAILURE);
}
arginfo->handle_opt(argv[optind]);
optind++;
@@ -3816,12 +4096,14 @@ static int parse_args(int argc, char **argv)
/* no option matched the current argv */
if (arginfo->handle_opt == NULL) {
- usage();
+ (void) fprintf(stderr, "qemu: unknown option '%s'\n", r);
+ exit(EXIT_FAILURE);
}
}
if (optind >= argc) {
- usage();
+ (void) fprintf(stderr, "qemu: no user program specified\n");
+ exit(EXIT_FAILURE);
}
filename = argv[optind];
@@ -3850,7 +4132,7 @@ int main(int argc, char **argv, char **envp)
if ((envlist = envlist_create()) == NULL) {
(void) fprintf(stderr, "Unable to allocate envlist\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
/* add current environment into the list */
@@ -3920,7 +4202,7 @@ int main(int argc, char **argv, char **envp)
cpu_model = "or1200";
#elif defined(TARGET_PPC)
# ifdef TARGET_PPC64
- cpu_model = "POWER7";
+ cpu_model = "POWER8";
# else
cpu_model = "750";
# endif
@@ -3936,7 +4218,7 @@ int main(int argc, char **argv, char **envp)
cpu = cpu_init(cpu_model);
if (!cpu) {
fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
env = cpu->env_ptr;
cpu_reset(cpu);
@@ -3954,7 +4236,6 @@ int main(int argc, char **argv, char **envp)
target_environ = envlist_to_environ(envlist, NULL);
envlist_free(envlist);
-#if defined(CONFIG_USE_GUEST_BASE)
/*
* Now that page sizes are configured in cpu_init() we can do
* proper page alignment for guest_base.
@@ -3969,14 +4250,13 @@ int main(int argc, char **argv, char **envp)
"space for use as guest address space (check your virtual "
"memory ulimit setting or reserve less using -R option)\n",
reserved_va);
- exit(1);
+ exit(EXIT_FAILURE);
}
if (reserved_va) {
mmap_next_start = reserved_va;
}
}
-#endif /* CONFIG_USE_GUEST_BASE */
/*
* Read in mmap_min_addr kernel parameter. This value is used
@@ -3990,7 +4270,7 @@ int main(int argc, char **argv, char **envp)
unsigned long tmp;
if (fscanf(fp, "%lu", &tmp) == 1) {
mmap_min_addr = tmp;
- qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
+ qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n", mmap_min_addr);
}
fclose(fp);
}
@@ -4003,7 +4283,7 @@ int main(int argc, char **argv, char **envp)
target_argv = calloc(target_argc + 1, sizeof (char *));
if (target_argv == NULL) {
(void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
/*
@@ -4019,7 +4299,7 @@ int main(int argc, char **argv, char **envp)
}
target_argv[target_argc] = NULL;
- ts = g_malloc0 (sizeof(TaskState));
+ ts = g_new0(TaskState, 1);
init_task_state(ts);
/* build Task State */
ts->info = info;
@@ -4032,7 +4312,7 @@ int main(int argc, char **argv, char **envp)
execfd = open(filename, O_RDONLY);
if (execfd < 0) {
printf("Error while loading %s: %s\n", filename, strerror(errno));
- _exit(1);
+ _exit(EXIT_FAILURE);
}
}
@@ -4040,7 +4320,7 @@ int main(int argc, char **argv, char **envp)
info, &bprm);
if (ret != 0) {
printf("Error while loading %s: %s\n", filename, strerror(-ret));
- _exit(1);
+ _exit(EXIT_FAILURE);
}
for (wrk = target_environ; *wrk; wrk++) {
@@ -4049,10 +4329,8 @@ int main(int argc, char **argv, char **envp)
free(target_environ);
- if (qemu_log_enabled()) {
-#if defined(CONFIG_USE_GUEST_BASE)
+ if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
qemu_log("guest_base 0x%lx\n", guest_base);
-#endif
log_page_dump();
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
@@ -4072,12 +4350,10 @@ int main(int argc, char **argv, char **envp)
syscall_init();
signal_init();
-#if defined(CONFIG_USE_GUEST_BASE)
/* Now that we've loaded the binary, GUEST_BASE is fixed. Delay
generating the prologue until now so that the prologue can take
the real value of GUEST_BASE into account. */
tcg_prologue_init(&tcg_ctx);
-#endif
#if defined(TARGET_I386)
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
@@ -4090,7 +4366,7 @@ int main(int argc, char **argv, char **envp)
/* enable 64 bit mode if possible */
if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
env->cr[4] |= CR4_PAE_MASK;
env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
@@ -4200,7 +4476,7 @@ int main(int argc, char **argv, char **envp)
if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
fprintf(stderr,
"The selected ARM CPU does not support 64 bit mode\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
for (i = 0; i < 31; i++) {
@@ -4212,15 +4488,21 @@ int main(int argc, char **argv, char **envp)
#elif defined(TARGET_ARM)
{
int i;
- cpsr_write(env, regs->uregs[16], 0xffffffff);
+ cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC,
+ CPSRWriteByInstr);
for(i = 0; i < 16; i++) {
env->regs[i] = regs->uregs[i];
}
+#ifdef TARGET_WORDS_BIGENDIAN
/* Enable BE8. */
if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
&& (info->elf_flags & EF_ARM_BE8)) {
- env->bswap_code = 1;
+ env->uncached_cpsr |= CPSR_E;
+ env->cp15.sctlr_el[1] |= SCTLR_E0E;
+ } else {
+ env->cp15.sctlr_el[1] |= SCTLR_B;
}
+#endif
}
#elif defined(TARGET_UNICORE32)
{
@@ -4386,6 +4668,17 @@ int main(int argc, char **argv, char **envp)
env->psw.mask = regs->psw.mask;
env->psw.addr = regs->psw.addr;
}
+#elif defined(TARGET_TILEGX)
+ {
+ int i;
+ for (i = 0; i < TILEGX_R_COUNT; i++) {
+ env->regs[i] = regs->regs[i];
+ }
+ for (i = 0; i < TILEGX_SPR_COUNT; i++) {
+ env->spregs[i] = 0;
+ }
+ env->pc = regs->pc;
+ }
#else
#error unsupported target CPU
#endif
@@ -4401,7 +4694,7 @@ int main(int argc, char **argv, char **envp)
if (gdbserver_start(gdbstub_port) < 0) {
fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
gdbstub_port);
- exit(1);
+ exit(EXIT_FAILURE);
}
gdb_handlesig(cpu, 0);
}