Add -name option, by Anthony Liguori.
[qemu] / linux-user / main.c
index 78f45a5..0c5e6b5 100644 (file)
@@ -34,6 +34,7 @@
 #endif
 
 static const char *interp_prefix = CONFIG_QEMU_PREFIX;
+const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 
 #if defined(__i386__) && !defined(CONFIG_STATIC)
 /* Force usage of an ELF interpreter even if it is an ELF shared
@@ -106,29 +107,7 @@ int cpu_get_pic_interrupt(CPUState *env)
 
 /* timers for rdtsc */
 
-#if defined(__i386__)
-
-int64_t cpu_get_real_ticks(void)
-{
-    int64_t val;
-    asm volatile ("rdtsc" : "=A" (val));
-    return val;
-}
-
-#elif defined(__x86_64__)
-
-int64_t cpu_get_real_ticks(void)
-{
-    uint32_t low,high;
-    int64_t val;
-    asm volatile("rdtsc" : "=a" (low), "=d" (high));
-    val = high;
-    val <<= 32;
-    val |= low;
-    return val;
-}
-
-#else
+#if 0
 
 static uint64_t emu_time;
 
@@ -143,6 +122,10 @@ int64_t cpu_get_real_ticks(void)
 /***********************************************************/
 /* CPUX86 core interface */
 
+void cpu_smm_update(CPUState *env)
+{
+}
+
 uint64_t cpu_get_tsc(CPUX86State *env)
 {
     return cpu_get_real_ticks();
@@ -494,11 +477,17 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1)
 
 static void save_window(CPUSPARCState *env)
 {
+#ifndef TARGET_SPARC64
     unsigned int new_wim;
     new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
         ((1LL << NWINDOWS) - 1);
     save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1));
     env->wim = new_wim;
+#else
+    save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1));
+    env->cansave++;
+    env->canrestore--;
+#endif
 }
 
 static void restore_window(CPUSPARCState *env)
@@ -521,6 +510,12 @@ static void restore_window(CPUSPARCState *env)
         sp_ptr += sizeof(target_ulong);
     }
     env->wim = new_wim;
+#ifdef TARGET_SPARC64
+    env->canrestore++;
+    if (env->cleanwin < NWINDOWS - 1)
+       env->cleanwin++;
+    env->cansave--;
+#endif
 }
 
 static void flush_windows(CPUSPARCState *env)
@@ -553,17 +548,29 @@ void cpu_loop (CPUSPARCState *env)
         trapnr = cpu_sparc_exec (env);
         
         switch (trapnr) {
+#ifndef TARGET_SPARC64
         case 0x88: 
         case 0x90:
+#else
+        case 0x16d:
+#endif
             ret = do_syscall (env, env->gregs[1],
                               env->regwptr[0], env->regwptr[1], 
                               env->regwptr[2], env->regwptr[3], 
                               env->regwptr[4], env->regwptr[5]);
             if ((unsigned int)ret >= (unsigned int)(-515)) {
+#ifdef TARGET_SPARC64
+                env->xcc |= PSR_CARRY;
+#else
                 env->psr |= PSR_CARRY;
+#endif
                 ret = -ret;
             } else {
+#ifdef TARGET_SPARC64
+                env->xcc &= ~PSR_CARRY;
+#else
                 env->psr &= ~PSR_CARRY;
+#endif
             }
             env->regwptr[0] = ret;
             /* next instruction */
@@ -595,10 +602,17 @@ void cpu_loop (CPUSPARCState *env)
             }
             break;
 #else
+        case TT_SPILL: /* window overflow */
+            save_window(env);
+            break;
+        case TT_FILL: /* window underflow */
+            restore_window(env);
+            break;
            // XXX
 #endif
-       case 0x100: // XXX, why do we get these?
-           break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
         case EXCP_DEBUG:
             {
                 int sig;
@@ -656,18 +670,23 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
 {
     cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
 }
-  
-uint32_t cpu_ppc_load_decr (CPUState *env)
+
+void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
+__attribute__ (( alias ("cpu_ppc_store_tbu") ));
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+__attribute__ (( alias ("cpu_ppc_load_tbu") ));
+
+void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
 {
-    /* TO FIX */
-    return -1;
+    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
 }
-void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
 {
-    /* TO FIX */
+    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
 }
+
 void cpu_loop(CPUPPCState *env)
 {
     target_siginfo_t info;
@@ -1283,6 +1302,7 @@ static const uint8_t mips_syscall_args[] = {
        MIPS_SYS(sys_add_key    , 5)
        MIPS_SYS(sys_request_key        , 4)
        MIPS_SYS(sys_keyctl     , 5)
+       MIPS_SYS(sys_set_thread_area, 1)
 };
 
 #undef MIPS_SYS
@@ -1300,6 +1320,7 @@ void cpu_loop(CPUMIPSState *env)
         case EXCP_SYSCALL:
             {
                 syscall_num = env->gpr[2] - 4000;
+                env->PC += 4;
                 if (syscall_num >= sizeof(mips_syscall_args)) {
                     ret = -ENOSYS;
                 } else {
@@ -1326,8 +1347,6 @@ void cpu_loop(CPUMIPSState *env)
                                      arg5, 
                                      arg6);
                 }
-                fail:
-                env->PC += 4;
                 if ((unsigned int)ret >= (unsigned int)(-1133)) {
                     env->gpr[7] = 1; /* error flag */
                     ret = -ret;
@@ -1339,40 +1358,30 @@ void cpu_loop(CPUMIPSState *env)
                 }
             }
             break;
+        case EXCP_TLBL:
+        case EXCP_TLBS:
         case EXCP_CpU:
         case EXCP_RI:
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = 0;
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_DEBUG:
             {
-                uint32_t insn, op;
-
-                insn = tget32(env->PC);
-                op = insn >> 26;
-                //                printf("insn=%08x op=%02x\n", insn, op);
-                /* XXX: totally dummy FP ops just to be able to launch
-                   a few executables */
-                switch(op) {
-                case 0x31: /* LWC1 */
-                    env->PC += 4;
-                    break;
-                case 0x39: /* SWC1 */
-                    env->PC += 4;
-                    break;
-                case 0x11:
-                    switch((insn >> 21) & 0x1f) {
-                    case 0x02: /* CFC1 */
-                        env->PC += 4;
-                        break;
-                    default:
-                        goto sigill;
-                    }
-                    break;
-                default:
-                sigill:
-                    info.si_signo = TARGET_SIGILL;
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
                     info.si_errno = 0;
-                    info.si_code = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
                     queue_signal(info.si_signo, &info);
-                    break;
-                }
+                  }
             }
             break;
         default:
@@ -1391,7 +1400,7 @@ void cpu_loop(CPUMIPSState *env)
 void cpu_loop (CPUState *env)
 {
     int trapnr, ret;
-    //    target_siginfo_t info;
+    target_siginfo_t info;
     
     while (1) {
         trapnr = cpu_sh4_exec (env);
@@ -1399,16 +1408,30 @@ void cpu_loop (CPUState *env)
         switch (trapnr) {
         case 0x160:
             ret = do_syscall(env, 
-                             env->gregs[0x13], 
-                             env->gregs[0x14], 
-                             env->gregs[0x15], 
-                             env->gregs[0x16], 
-                             env->gregs[0x17], 
-                             env->gregs[0x10], 
+                             env->gregs[3], 
+                             env->gregs[4], 
+                             env->gregs[5], 
+                             env->gregs[6], 
+                             env->gregs[7], 
+                             env->gregs[0], 
                              0);
-            env->gregs[0x10] = ret;
+            env->gregs[0] = ret;
             env->pc += 2;
             break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(info.si_signo, &info);
+                  }
+            }
+            break;
         default:
             printf ("Unhandled trap: 0x%x\n", trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
@@ -1419,16 +1442,109 @@ void cpu_loop (CPUState *env)
 }
 #endif
 
+#ifdef TARGET_M68K
+
+void cpu_loop(CPUM68KState *env)
+{
+    int trapnr;
+    unsigned int n;
+    target_siginfo_t info;
+    TaskState *ts = env->opaque;
+    
+    for(;;) {
+        trapnr = cpu_m68k_exec(env);
+        switch(trapnr) {
+        case EXCP_ILLEGAL:
+            {
+                if (ts->sim_syscalls) {
+                    uint16_t nr;
+                    nr = lduw(env->pc + 2);
+                    env->pc += 4;
+                    do_m68k_simcall(env, nr);
+                } else {
+                    goto do_sigill;
+                }
+            }
+            break;
+        case EXCP_HALTED:
+            /* Semihosing syscall.  */
+            env->pc += 2;
+            do_m68k_semihosting(env, env->dregs[0]);
+            break;
+        case EXCP_LINEA:
+        case EXCP_LINEF:
+        case EXCP_UNSUPPORTED:
+        do_sigill:
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_ILLOPN;
+            info._sifields._sigfault._addr = env->pc;
+            queue_signal(info.si_signo, &info);
+            break;
+        case EXCP_TRAP0:
+            {
+                ts->sim_syscalls = 0;
+                n = env->dregs[0];
+                env->pc += 2;
+                env->dregs[0] = do_syscall(env, 
+                                          n, 
+                                          env->dregs[1],
+                                          env->dregs[2],
+                                          env->dregs[3],
+                                          env->dregs[4],
+                                          env->dregs[5],
+                                          env->dregs[6]);
+            }
+            break;
+        case EXCP_INTERRUPT:
+            /* just indicate that signals should be handled asap */
+            break;
+        case EXCP_ACCESS:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                info._sifields._sigfault._addr = env->mmu.ar;
+                queue_signal(info.si_signo, &info);
+            }
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(info.si_signo, &info);
+                  }
+            }
+            break;
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 
+                    trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+#endif /* TARGET_M68K */
+
 void usage(void)
 {
-    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n"
-           "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n"
+    printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
+           "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] [-cpu model] program [arguments...]\n"
            "Linux CPU emulator (compiled for %s emulation)\n"
            "\n"
            "-h           print this help\n"
            "-g port      wait gdb connection to port\n"
            "-L path      set the elf interpreter prefix (default=%s)\n"
            "-s size      set the stack size in bytes (default=%ld)\n"
+           "-cpu model   select CPU (-cpu ? for list)\n"
            "\n"
            "debug options:\n"
 #ifdef USE_CODE_COPY
@@ -1452,6 +1568,7 @@ TaskState *first_task_state;
 int main(int argc, char **argv)
 {
     const char *filename;
+    const char *cpu_model;
     struct target_pt_regs regs1, *regs = &regs1;
     struct image_info info1, *info = &info1;
     TaskState ts1, *ts = &ts1;
@@ -1466,6 +1583,7 @@ int main(int argc, char **argv)
     /* init debug */
     cpu_set_log_filename(DEBUG_LOGFILE);
 
+    cpu_model = NULL;
     optind = 1;
     for(;;) {
         if (optind >= argc)
@@ -1514,6 +1632,20 @@ int main(int argc, char **argv)
             }
         } else if (!strcmp(r, "g")) {
             gdbstub_port = atoi(argv[optind++]);
+       } else if (!strcmp(r, "r")) {
+           qemu_uname_release = argv[optind++];
+        } else if (!strcmp(r, "cpu")) {
+            cpu_model = argv[optind++];
+            if (strcmp(cpu_model, "?") == 0) {
+#if defined(TARGET_PPC)
+                ppc_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_ARM)
+                arm_cpu_list();
+#elif defined(TARGET_MIPS)
+                mips_cpu_list(stdout, &fprintf);
+#endif
+                _exit(1);
+            }
         } else 
 #ifdef USE_CODE_COPY
         if (!strcmp(r, "no-code-copy")) {
@@ -1542,7 +1674,7 @@ int main(int argc, char **argv)
     env = cpu_init();
     global_env = env;
     
-    if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
+    if (loader_exec(filename, argv+optind, environ, regs, info) != 0) {
        printf("Error loading %s\n", filename);
        _exit(1);
     }
@@ -1553,6 +1685,7 @@ int main(int argc, char **argv)
         fprintf(logfile, "start_brk   0x%08lx\n" , info->start_brk);
         fprintf(logfile, "end_code    0x%08lx\n" , info->end_code);
         fprintf(logfile, "start_code  0x%08lx\n" , info->start_code);
+        fprintf(logfile, "start_data  0x%08lx\n" , info->start_data);
         fprintf(logfile, "end_data    0x%08lx\n" , info->end_data);
         fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
         fprintf(logfile, "brk         0x%08lx\n" , info->brk);
@@ -1567,6 +1700,7 @@ int main(int argc, char **argv)
     memset(ts, 0, sizeof(TaskState));
     env->opaque = ts;
     ts->used = 1;
+    ts->info = info;
     env->user_mode_only = 1;
     
 #if defined(TARGET_I386)
@@ -1637,7 +1771,9 @@ int main(int argc, char **argv)
 #elif defined(TARGET_ARM)
     {
         int i;
-        cpu_arm_set_model(env, ARM_CPUID_ARM1026);
+        if (cpu_model == NULL)
+            cpu_model = "arm926";
+        cpu_arm_set_model(env, cpu_model);
         cpsr_write(env, regs->uregs[16], 0xffffffff);
         for(i = 0; i < 16; i++) {
             env->regs[i] = regs->uregs[i];
@@ -1664,15 +1800,9 @@ int main(int argc, char **argv)
         int i;
 
         /* Choose and initialise CPU */
-        /* XXX: CPU model (or PVR) should be provided on command line */
-        //        ppc_find_by_name("750gx", &def);
-        //        ppc_find_by_name("750fx", &def);
-        //        ppc_find_by_name("750p", &def);
-        ppc_find_by_name("750", &def);
-        //        ppc_find_by_name("G3", &def);
-        //        ppc_find_by_name("604r", &def);
-        //        ppc_find_by_name("604e", &def);
-        //        ppc_find_by_name("604", &def);
+        if (cpu_model == NULL)
+            cpu_model = "750";
+        ppc_find_by_name(cpu_model, &def);
         if (def == NULL) {
             cpu_abort(env,
                       "Unable to find PowerPC CPU definition\n");
@@ -1688,14 +1818,55 @@ int main(int argc, char **argv)
             env->gpr[i] = regs->gpr[i];
         }
     }
+#elif defined(TARGET_M68K)
+    {
+        m68k_def_t *def;
+        def = m68k_find_by_name("cfv4e");
+        if (def == NULL) {
+            cpu_abort(cpu_single_env,
+                      "Unable to find m68k CPU definition\n");
+        }
+        cpu_m68k_register(cpu_single_env, def);
+        env->pc = regs->pc;
+        env->dregs[0] = regs->d0;
+        env->dregs[1] = regs->d1;
+        env->dregs[2] = regs->d2;
+        env->dregs[3] = regs->d3;
+        env->dregs[4] = regs->d4;
+        env->dregs[5] = regs->d5;
+        env->dregs[6] = regs->d6;
+        env->dregs[7] = regs->d7;
+        env->aregs[0] = regs->a0;
+        env->aregs[1] = regs->a1;
+        env->aregs[2] = regs->a2;
+        env->aregs[3] = regs->a3;
+        env->aregs[4] = regs->a4;
+        env->aregs[5] = regs->a5;
+        env->aregs[6] = regs->a6;
+        env->aregs[7] = regs->usp;
+        env->sr = regs->sr;
+        ts->sim_syscalls = 1;
+    }
 #elif defined(TARGET_MIPS)
     {
+        mips_def_t *def;
         int i;
 
+        /* Choose and initialise CPU */
+        if (cpu_model == NULL)
+            cpu_model = "24Kf";
+        mips_find_by_name(cpu_model, &def);
+        if (def == NULL)
+            cpu_abort(env, "Unable to find MIPS CPU definition\n");
+        cpu_mips_register(env, def);
+
         for(i = 0; i < 32; i++) {
             env->gpr[i] = regs->regs[i];
         }
         env->PC = regs->cp0_epc;
+        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+            env->CP0_Status |= (1 << CP0St_CU1);
+        }
     }
 #elif defined(TARGET_SH4)
     {