1ca5d32a3SWarner Losh /* 2ca5d32a3SWarner Losh * arm cpu init and loop 3ca5d32a3SWarner Losh * 4ca5d32a3SWarner Losh * Copyright (c) 2013 Stacey D. Son 5ca5d32a3SWarner Losh * 6ca5d32a3SWarner Losh * This program is free software; you can redistribute it and/or modify 7ca5d32a3SWarner Losh * it under the terms of the GNU General Public License as published by 8ca5d32a3SWarner Losh * the Free Software Foundation; either version 2 of the License, or 9ca5d32a3SWarner Losh * (at your option) any later version. 10ca5d32a3SWarner Losh * 11ca5d32a3SWarner Losh * This program is distributed in the hope that it will be useful, 12ca5d32a3SWarner Losh * but WITHOUT ANY WARRANTY; without even the implied warranty of 13ca5d32a3SWarner Losh * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14ca5d32a3SWarner Losh * GNU General Public License for more details. 15ca5d32a3SWarner Losh * 16ca5d32a3SWarner Losh * You should have received a copy of the GNU General Public License 17ca5d32a3SWarner Losh * along with this program; if not, see <http://www.gnu.org/licenses/>. 18ca5d32a3SWarner Losh */ 19ca5d32a3SWarner Losh 20ca5d32a3SWarner Losh #ifndef _TARGET_ARCH_CPU_H_ 21ca5d32a3SWarner Losh #define _TARGET_ARCH_CPU_H_ 22ca5d32a3SWarner Losh 23ca5d32a3SWarner Losh #include "target_arch.h" 242bd010c4SWarner Losh #include "signal-common.h" 25ca5d32a3SWarner Losh 26ca5d32a3SWarner Losh #define TARGET_DEFAULT_CPU_MODEL "any" 27ca5d32a3SWarner Losh 28ca5d32a3SWarner Losh static inline void target_cpu_init(CPUARMState *env, 29ca5d32a3SWarner Losh struct target_pt_regs *regs) 30ca5d32a3SWarner Losh { 31ca5d32a3SWarner Losh int i; 32ca5d32a3SWarner Losh 33ca5d32a3SWarner Losh cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC, 34ca5d32a3SWarner Losh CPSRWriteByInstr); 35ca5d32a3SWarner Losh for (i = 0; i < 16; i++) { 36ca5d32a3SWarner Losh env->regs[i] = regs->uregs[i]; 37ca5d32a3SWarner Losh } 38ca5d32a3SWarner Losh } 39ca5d32a3SWarner Losh 4006efe3bfSWarner Losh static inline void target_cpu_loop(CPUARMState *env) 4106efe3bfSWarner Losh { 4206efe3bfSWarner Losh int trapnr; 4306efe3bfSWarner Losh target_siginfo_t info; 448d450c9aSWarner Losh unsigned int n; 4506efe3bfSWarner Losh CPUState *cs = env_cpu(env); 4606efe3bfSWarner Losh 4706efe3bfSWarner Losh for (;;) { 4806efe3bfSWarner Losh cpu_exec_start(cs); 4906efe3bfSWarner Losh trapnr = cpu_exec(cs); 5006efe3bfSWarner Losh cpu_exec_end(cs); 5106efe3bfSWarner Losh process_queued_cpu_work(cs); 5206efe3bfSWarner Losh switch (trapnr) { 5370985aecSWarner Losh case EXCP_UDEF: 5470985aecSWarner Losh { 5570985aecSWarner Losh /* See arm/arm/undefined.c undefinedinstruction(); */ 5670985aecSWarner Losh info.si_addr = env->regs[15]; 5770985aecSWarner Losh 5870985aecSWarner Losh /* illegal instruction */ 5970985aecSWarner Losh info.si_signo = TARGET_SIGILL; 6070985aecSWarner Losh info.si_errno = 0; 6170985aecSWarner Losh info.si_code = TARGET_ILL_ILLOPC; 6270985aecSWarner Losh queue_signal(env, info.si_signo, &info); 6370985aecSWarner Losh 6470985aecSWarner Losh /* TODO: What about instruction emulation? */ 6570985aecSWarner Losh } 6670985aecSWarner Losh break; 678d450c9aSWarner Losh case EXCP_SWI: 688d450c9aSWarner Losh { 698d450c9aSWarner Losh n = env->regs[7]; 708d450c9aSWarner Losh if (bsd_type == target_freebsd) { 718d450c9aSWarner Losh int ret; 728d450c9aSWarner Losh abi_ulong params = get_sp_from_cpustate(env); 738d450c9aSWarner Losh int32_t syscall_nr = n; 748d450c9aSWarner Losh int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; 758d450c9aSWarner Losh 768d450c9aSWarner Losh /* See arm/arm/trap.c cpu_fetch_syscall_args() */ 778d450c9aSWarner Losh if (syscall_nr == TARGET_FREEBSD_NR_syscall) { 788d450c9aSWarner Losh syscall_nr = env->regs[0]; 798d450c9aSWarner Losh arg1 = env->regs[1]; 808d450c9aSWarner Losh arg2 = env->regs[2]; 818d450c9aSWarner Losh arg3 = env->regs[3]; 828d450c9aSWarner Losh get_user_s32(arg4, params); 838d450c9aSWarner Losh params += sizeof(int32_t); 848d450c9aSWarner Losh get_user_s32(arg5, params); 858d450c9aSWarner Losh params += sizeof(int32_t); 868d450c9aSWarner Losh get_user_s32(arg6, params); 878d450c9aSWarner Losh params += sizeof(int32_t); 888d450c9aSWarner Losh get_user_s32(arg7, params); 898d450c9aSWarner Losh arg8 = 0; 908d450c9aSWarner Losh } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { 918d450c9aSWarner Losh syscall_nr = env->regs[0]; 928d450c9aSWarner Losh arg1 = env->regs[2]; 938d450c9aSWarner Losh arg2 = env->regs[3]; 948d450c9aSWarner Losh get_user_s32(arg3, params); 958d450c9aSWarner Losh params += sizeof(int32_t); 968d450c9aSWarner Losh get_user_s32(arg4, params); 978d450c9aSWarner Losh params += sizeof(int32_t); 988d450c9aSWarner Losh get_user_s32(arg5, params); 998d450c9aSWarner Losh params += sizeof(int32_t); 1008d450c9aSWarner Losh get_user_s32(arg6, params); 1018d450c9aSWarner Losh arg7 = 0; 1028d450c9aSWarner Losh arg8 = 0; 1038d450c9aSWarner Losh } else { 1048d450c9aSWarner Losh arg1 = env->regs[0]; 1058d450c9aSWarner Losh arg2 = env->regs[1]; 1068d450c9aSWarner Losh arg3 = env->regs[2]; 1078d450c9aSWarner Losh arg4 = env->regs[3]; 1088d450c9aSWarner Losh get_user_s32(arg5, params); 1098d450c9aSWarner Losh params += sizeof(int32_t); 1108d450c9aSWarner Losh get_user_s32(arg6, params); 1118d450c9aSWarner Losh params += sizeof(int32_t); 1128d450c9aSWarner Losh get_user_s32(arg7, params); 1138d450c9aSWarner Losh params += sizeof(int32_t); 1148d450c9aSWarner Losh get_user_s32(arg8, params); 1158d450c9aSWarner Losh } 1168d450c9aSWarner Losh ret = do_freebsd_syscall(env, syscall_nr, arg1, arg2, arg3, 1178d450c9aSWarner Losh arg4, arg5, arg6, arg7, arg8); 1188d450c9aSWarner Losh /* 1198d450c9aSWarner Losh * Compare to arm/arm/vm_machdep.c 1208d450c9aSWarner Losh * cpu_set_syscall_retval() 1218d450c9aSWarner Losh */ 1228d450c9aSWarner Losh if (-TARGET_EJUSTRETURN == ret) { 1238d450c9aSWarner Losh /* 1248d450c9aSWarner Losh * Returning from a successful sigreturn syscall. 1258d450c9aSWarner Losh * Avoid clobbering register state. 1268d450c9aSWarner Losh */ 1278d450c9aSWarner Losh break; 1288d450c9aSWarner Losh } 1298d450c9aSWarner Losh if (-TARGET_ERESTART == ret) { 1308d450c9aSWarner Losh env->regs[15] -= env->thumb ? 2 : 4; 1318d450c9aSWarner Losh break; 1328d450c9aSWarner Losh } 1338d450c9aSWarner Losh if ((unsigned int)ret >= (unsigned int)(-515)) { 1348d450c9aSWarner Losh ret = -ret; 1358d450c9aSWarner Losh cpsr_write(env, CPSR_C, CPSR_C, CPSRWriteByInstr); 1368d450c9aSWarner Losh env->regs[0] = ret; 1378d450c9aSWarner Losh } else { 1388d450c9aSWarner Losh cpsr_write(env, 0, CPSR_C, CPSRWriteByInstr); 1398d450c9aSWarner Losh env->regs[0] = ret; /* XXX need to handle lseek()? */ 1408d450c9aSWarner Losh /* env->regs[1] = 0; */ 1418d450c9aSWarner Losh } 1428d450c9aSWarner Losh } else { 1438d450c9aSWarner Losh fprintf(stderr, "qemu: bsd_type (= %d) syscall " 1448d450c9aSWarner Losh "not supported\n", bsd_type); 1458d450c9aSWarner Losh } 1468d450c9aSWarner Losh } 1478d450c9aSWarner Losh break; 14870985aecSWarner Losh case EXCP_INTERRUPT: 14970985aecSWarner Losh /* just indicate that signals should be handled asap */ 15070985aecSWarner Losh break; 151ef1412bdSWarner Losh case EXCP_PREFETCH_ABORT: 152ef1412bdSWarner Losh /* See arm/arm/trap.c prefetch_abort_handler() */ 153ef1412bdSWarner Losh case EXCP_DATA_ABORT: 154ef1412bdSWarner Losh /* See arm/arm/trap.c data_abort_handler() */ 155ef1412bdSWarner Losh info.si_signo = TARGET_SIGSEGV; 156ef1412bdSWarner Losh info.si_errno = 0; 157ef1412bdSWarner Losh /* XXX: check env->error_code */ 158ef1412bdSWarner Losh info.si_code = 0; 159ef1412bdSWarner Losh info.si_addr = env->exception.vaddress; 160ef1412bdSWarner Losh queue_signal(env, info.si_signo, &info); 161ef1412bdSWarner Losh break; 16270985aecSWarner Losh case EXCP_DEBUG: 163*a3ed97ceSWarner Losh case EXCP_BKPT: 164*a3ed97ceSWarner Losh force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[15]); 16570985aecSWarner Losh break; 16670985aecSWarner Losh case EXCP_YIELD: 16770985aecSWarner Losh /* nothing to do here for user-mode, just resume guest code */ 16870985aecSWarner Losh break; 169c0d2691cSWarner Losh case EXCP_ATOMIC: 170c0d2691cSWarner Losh cpu_exec_step_atomic(cs); 171c0d2691cSWarner Losh break; 17206efe3bfSWarner Losh default: 17306efe3bfSWarner Losh fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 17406efe3bfSWarner Losh trapnr); 17506efe3bfSWarner Losh cpu_dump_state(cs, stderr, 0); 17606efe3bfSWarner Losh abort(); 17706efe3bfSWarner Losh } /* switch() */ 17806efe3bfSWarner Losh process_pending_signals(env); 17906efe3bfSWarner Losh } /* for (;;) */ 18006efe3bfSWarner Losh } 18106efe3bfSWarner Losh 182e17d4c9aSWarner Losh static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp) 183e17d4c9aSWarner Losh { 184e17d4c9aSWarner Losh if (newsp) { 185e17d4c9aSWarner Losh env->regs[13] = newsp; 186e17d4c9aSWarner Losh } 187e17d4c9aSWarner Losh env->regs[0] = 0; 188e17d4c9aSWarner Losh } 189e17d4c9aSWarner Losh 190ca5d32a3SWarner Losh static inline void target_cpu_reset(CPUArchState *cpu) 191ca5d32a3SWarner Losh { 192ca5d32a3SWarner Losh } 193ca5d32a3SWarner Losh 194ca5d32a3SWarner Losh #endif /* !_TARGET_ARCH_CPU_H */ 195