aboutsummaryrefslogtreecommitdiff
path: root/linux-user/main.c
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2017-01-18 23:01:42 +0100
committerRichard Henderson <rth@twiddle.net>2017-01-24 13:10:35 -0800
commita0a839b65b61a51934b9c2c197fa058c319cc94a (patch)
tree925ce4031c19b9e10cc8927c934a4e90a6f7dff6 /linux-user/main.c
parent3f0c3423093fe7a07af3806cc773bf7d71adf8c9 (diff)
downloadqemu-a0a839b65b61a51934b9c2c197fa058c319cc94a.zip
qemu-a0a839b65b61a51934b9c2c197fa058c319cc94a.tar.gz
qemu-a0a839b65b61a51934b9c2c197fa058c319cc94a.tar.bz2
nios2: Add usermode binaries emulation
Add missing bits for qemu-user required for emulating Altera Nios2 userspace binaries. Signed-off-by: Marek Vasut <marex@denx.de> Cc: Chris Wulff <crwulff@gmail.com> Cc: Jeff Da Silva <jdasilva@altera.com> Cc: Ley Foon Tan <lftan@altera.com> Cc: Sandra Loosemore <sandra@codesourcery.com> Cc: Yves Vandervennet <yvanderv@altera.com> Reviewed-by: Alexander Graf <agraf@suse.de> Message-Id: <20170118220146.489-4-marex@denx.de> Signed-off-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'linux-user/main.c')
-rw-r--r--linux-user/main.c140
1 files changed, 138 insertions, 2 deletions
diff --git a/linux-user/main.c b/linux-user/main.c
index db4eb68..f5c8557 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -68,8 +68,11 @@ do { \
* This way we will never overlap with our own libraries or binaries or stack
* or anything else that QEMU maps.
*/
-# ifdef TARGET_MIPS
-/* MIPS only supports 31 bits of virtual address space for user space */
+# if defined(TARGET_MIPS) || defined(TARGET_NIOS2)
+/*
+ * MIPS only supports 31 bits of virtual address space for user space.
+ * Nios2 also only supports 31 bits.
+ */
unsigned long reserved_va = 0x77000000;
# else
unsigned long reserved_va = 0xf7000000;
@@ -2462,6 +2465,109 @@ error:
}
#endif
+#ifdef TARGET_NIOS2
+
+void cpu_loop(CPUNios2State *env)
+{
+ CPUState *cs = ENV_GET_CPU(env);
+ Nios2CPU *cpu = NIOS2_CPU(cs);
+ target_siginfo_t info;
+ int trapnr, gdbsig, ret;
+
+ for (;;) {
+ cpu_exec_start(cs);
+ trapnr = cpu_exec(cs);
+ cpu_exec_end(cs);
+ gdbsig = 0;
+
+ switch (trapnr) {
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_TRAP:
+ if (env->regs[R_AT] == 0) {
+ abi_long ret;
+ qemu_log_mask(CPU_LOG_INT, "\nSyscall\n");
+
+ ret = do_syscall(env, env->regs[2],
+ env->regs[4], env->regs[5], env->regs[6],
+ env->regs[7], env->regs[8], env->regs[9],
+ 0, 0);
+
+ if (env->regs[2] == 0) { /* FIXME: syscall 0 workaround */
+ ret = 0;
+ }
+
+ env->regs[2] = abs(ret);
+ /* Return value is 0..4096 */
+ env->regs[7] = (ret > 0xfffffffffffff000ULL);
+ env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
+ env->regs[CR_STATUS] &= ~0x3;
+ env->regs[R_EA] = env->regs[R_PC] + 4;
+ env->regs[R_PC] += 4;
+ break;
+ } else {
+ qemu_log_mask(CPU_LOG_INT, "\nTrap\n");
+
+ env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
+ env->regs[CR_STATUS] &= ~0x3;
+ env->regs[R_EA] = env->regs[R_PC] + 4;
+ env->regs[R_PC] = cpu->exception_addr;
+
+ gdbsig = TARGET_SIGTRAP;
+ break;
+ }
+ case 0xaa:
+ switch (env->regs[R_PC]) {
+ /*case 0x1000:*/ /* TODO:__kuser_helper_version */
+ case 0x1004: /* __kuser_cmpxchg */
+ start_exclusive();
+ if (env->regs[4] & 0x3) {
+ goto kuser_fail;
+ }
+ ret = get_user_u32(env->regs[2], env->regs[4]);
+ if (ret) {
+ end_exclusive();
+ goto kuser_fail;
+ }
+ env->regs[2] -= env->regs[5];
+ if (env->regs[2] == 0) {
+ put_user_u32(env->regs[6], env->regs[4]);
+ }
+ end_exclusive();
+ env->regs[R_PC] = env->regs[R_RA];
+ break;
+ /*case 0x1040:*/ /* TODO:__kuser_sigtramp */
+ default:
+ ;
+kuser_fail:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* TODO: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->regs[R_PC];
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ }
+ break;
+ default:
+ EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
+ trapnr);
+ gdbsig = TARGET_SIGILL;
+ break;
+ }
+ if (gdbsig) {
+ gdb_handlesig(cs, gdbsig);
+ if (gdbsig != TARGET_SIGTRAP) {
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ process_pending_signals(env);
+ }
+}
+
+#endif /* TARGET_NIOS2 */
+
#ifdef TARGET_OPENRISC
void cpu_loop(CPUOpenRISCState *env)
@@ -4632,6 +4738,36 @@ int main(int argc, char **argv, char **envp)
restore_snan_bit_mode(env);
}
}
+#elif defined(TARGET_NIOS2)
+ {
+ env->regs[0] = 0;
+ env->regs[1] = regs->r1;
+ env->regs[2] = regs->r2;
+ env->regs[3] = regs->r3;
+ env->regs[4] = regs->r4;
+ env->regs[5] = regs->r5;
+ env->regs[6] = regs->r6;
+ env->regs[7] = regs->r7;
+ env->regs[8] = regs->r8;
+ env->regs[9] = regs->r9;
+ env->regs[10] = regs->r10;
+ env->regs[11] = regs->r11;
+ env->regs[12] = regs->r12;
+ env->regs[13] = regs->r13;
+ env->regs[14] = regs->r14;
+ env->regs[15] = regs->r15;
+ /* TODO: unsigned long orig_r2; */
+ env->regs[R_RA] = regs->ra;
+ env->regs[R_FP] = regs->fp;
+ env->regs[R_SP] = regs->sp;
+ env->regs[R_GP] = regs->gp;
+ env->regs[CR_ESTATUS] = regs->estatus;
+ env->regs[R_EA] = regs->ea;
+ /* TODO: unsigned long orig_r7; */
+
+ /* Emulate eret when starting thread. */
+ env->regs[R_PC] = regs->ea;
+ }
#elif defined(TARGET_OPENRISC)
{
int i;