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" 24ca5d32a3SWarner Losh 25ca5d32a3SWarner Losh #define TARGET_DEFAULT_CPU_MODEL "any" 26ca5d32a3SWarner Losh 27ca5d32a3SWarner Losh static inline void target_cpu_init(CPUARMState *env, 28ca5d32a3SWarner Losh struct target_pt_regs *regs) 29ca5d32a3SWarner Losh { 30ca5d32a3SWarner Losh int i; 31ca5d32a3SWarner Losh 32ca5d32a3SWarner Losh cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC, 33ca5d32a3SWarner Losh CPSRWriteByInstr); 34ca5d32a3SWarner Losh for (i = 0; i < 16; i++) { 35ca5d32a3SWarner Losh env->regs[i] = regs->uregs[i]; 36ca5d32a3SWarner Losh } 37ca5d32a3SWarner Losh } 38ca5d32a3SWarner Losh 3906efe3bfSWarner Losh static inline void target_cpu_loop(CPUARMState *env) 4006efe3bfSWarner Losh { 4106efe3bfSWarner Losh int trapnr; 4206efe3bfSWarner Losh target_siginfo_t info; 438d450c9aSWarner Losh unsigned int n; 4406efe3bfSWarner Losh CPUState *cs = env_cpu(env); 4506efe3bfSWarner Losh 4606efe3bfSWarner Losh for (;;) { 4706efe3bfSWarner Losh cpu_exec_start(cs); 4806efe3bfSWarner Losh trapnr = cpu_exec(cs); 4906efe3bfSWarner Losh cpu_exec_end(cs); 5006efe3bfSWarner Losh process_queued_cpu_work(cs); 5106efe3bfSWarner Losh switch (trapnr) { 5270985aecSWarner Losh case EXCP_UDEF: 5370985aecSWarner Losh { 5470985aecSWarner Losh /* See arm/arm/undefined.c undefinedinstruction(); */ 5570985aecSWarner Losh info.si_addr = env->regs[15]; 5670985aecSWarner Losh 5770985aecSWarner Losh /* illegal instruction */ 5870985aecSWarner Losh info.si_signo = TARGET_SIGILL; 5970985aecSWarner Losh info.si_errno = 0; 6070985aecSWarner Losh info.si_code = TARGET_ILL_ILLOPC; 6170985aecSWarner Losh queue_signal(env, info.si_signo, &info); 6270985aecSWarner Losh 6370985aecSWarner Losh /* TODO: What about instruction emulation? */ 6470985aecSWarner Losh } 6570985aecSWarner Losh break; 668d450c9aSWarner Losh case EXCP_SWI: 678d450c9aSWarner Losh case EXCP_BKPT: 688d450c9aSWarner Losh { 698d450c9aSWarner Losh /* 708d450c9aSWarner Losh * system call 718d450c9aSWarner Losh * See arm/arm/trap.c cpu_fetch_syscall_args() 728d450c9aSWarner Losh */ 738d450c9aSWarner Losh if (trapnr == EXCP_BKPT) { 748d450c9aSWarner Losh if (env->thumb) { 758d450c9aSWarner Losh env->regs[15] += 2; 768d450c9aSWarner Losh } else { 778d450c9aSWarner Losh env->regs[15] += 4; 788d450c9aSWarner Losh } 798d450c9aSWarner Losh } 808d450c9aSWarner Losh n = env->regs[7]; 818d450c9aSWarner Losh if (bsd_type == target_freebsd) { 828d450c9aSWarner Losh int ret; 838d450c9aSWarner Losh abi_ulong params = get_sp_from_cpustate(env); 848d450c9aSWarner Losh int32_t syscall_nr = n; 858d450c9aSWarner Losh int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; 868d450c9aSWarner Losh 878d450c9aSWarner Losh /* See arm/arm/trap.c cpu_fetch_syscall_args() */ 888d450c9aSWarner Losh if (syscall_nr == TARGET_FREEBSD_NR_syscall) { 898d450c9aSWarner Losh syscall_nr = env->regs[0]; 908d450c9aSWarner Losh arg1 = env->regs[1]; 918d450c9aSWarner Losh arg2 = env->regs[2]; 928d450c9aSWarner Losh arg3 = env->regs[3]; 938d450c9aSWarner Losh get_user_s32(arg4, params); 948d450c9aSWarner Losh params += sizeof(int32_t); 958d450c9aSWarner Losh get_user_s32(arg5, params); 968d450c9aSWarner Losh params += sizeof(int32_t); 978d450c9aSWarner Losh get_user_s32(arg6, params); 988d450c9aSWarner Losh params += sizeof(int32_t); 998d450c9aSWarner Losh get_user_s32(arg7, params); 1008d450c9aSWarner Losh arg8 = 0; 1018d450c9aSWarner Losh } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { 1028d450c9aSWarner Losh syscall_nr = env->regs[0]; 1038d450c9aSWarner Losh arg1 = env->regs[2]; 1048d450c9aSWarner Losh arg2 = env->regs[3]; 1058d450c9aSWarner Losh get_user_s32(arg3, params); 1068d450c9aSWarner Losh params += sizeof(int32_t); 1078d450c9aSWarner Losh get_user_s32(arg4, params); 1088d450c9aSWarner Losh params += sizeof(int32_t); 1098d450c9aSWarner Losh get_user_s32(arg5, params); 1108d450c9aSWarner Losh params += sizeof(int32_t); 1118d450c9aSWarner Losh get_user_s32(arg6, params); 1128d450c9aSWarner Losh arg7 = 0; 1138d450c9aSWarner Losh arg8 = 0; 1148d450c9aSWarner Losh } else { 1158d450c9aSWarner Losh arg1 = env->regs[0]; 1168d450c9aSWarner Losh arg2 = env->regs[1]; 1178d450c9aSWarner Losh arg3 = env->regs[2]; 1188d450c9aSWarner Losh arg4 = env->regs[3]; 1198d450c9aSWarner Losh get_user_s32(arg5, params); 1208d450c9aSWarner Losh params += sizeof(int32_t); 1218d450c9aSWarner Losh get_user_s32(arg6, params); 1228d450c9aSWarner Losh params += sizeof(int32_t); 1238d450c9aSWarner Losh get_user_s32(arg7, params); 1248d450c9aSWarner Losh params += sizeof(int32_t); 1258d450c9aSWarner Losh get_user_s32(arg8, params); 1268d450c9aSWarner Losh } 1278d450c9aSWarner Losh ret = do_freebsd_syscall(env, syscall_nr, arg1, arg2, arg3, 1288d450c9aSWarner Losh arg4, arg5, arg6, arg7, arg8); 1298d450c9aSWarner Losh /* 1308d450c9aSWarner Losh * Compare to arm/arm/vm_machdep.c 1318d450c9aSWarner Losh * cpu_set_syscall_retval() 1328d450c9aSWarner Losh */ 1338d450c9aSWarner Losh if (-TARGET_EJUSTRETURN == ret) { 1348d450c9aSWarner Losh /* 1358d450c9aSWarner Losh * Returning from a successful sigreturn syscall. 1368d450c9aSWarner Losh * Avoid clobbering register state. 1378d450c9aSWarner Losh */ 1388d450c9aSWarner Losh break; 1398d450c9aSWarner Losh } 1408d450c9aSWarner Losh if (-TARGET_ERESTART == ret) { 1418d450c9aSWarner Losh env->regs[15] -= env->thumb ? 2 : 4; 1428d450c9aSWarner Losh break; 1438d450c9aSWarner Losh } 1448d450c9aSWarner Losh if ((unsigned int)ret >= (unsigned int)(-515)) { 1458d450c9aSWarner Losh ret = -ret; 1468d450c9aSWarner Losh cpsr_write(env, CPSR_C, CPSR_C, CPSRWriteByInstr); 1478d450c9aSWarner Losh env->regs[0] = ret; 1488d450c9aSWarner Losh } else { 1498d450c9aSWarner Losh cpsr_write(env, 0, CPSR_C, CPSRWriteByInstr); 1508d450c9aSWarner Losh env->regs[0] = ret; /* XXX need to handle lseek()? */ 1518d450c9aSWarner Losh /* env->regs[1] = 0; */ 1528d450c9aSWarner Losh } 1538d450c9aSWarner Losh } else { 1548d450c9aSWarner Losh fprintf(stderr, "qemu: bsd_type (= %d) syscall " 1558d450c9aSWarner Losh "not supported\n", bsd_type); 1568d450c9aSWarner Losh } 1578d450c9aSWarner Losh } 1588d450c9aSWarner Losh break; 15970985aecSWarner Losh case EXCP_INTERRUPT: 16070985aecSWarner Losh /* just indicate that signals should be handled asap */ 16170985aecSWarner Losh break; 162ef1412bdSWarner Losh case EXCP_PREFETCH_ABORT: 163ef1412bdSWarner Losh /* See arm/arm/trap.c prefetch_abort_handler() */ 164ef1412bdSWarner Losh case EXCP_DATA_ABORT: 165ef1412bdSWarner Losh /* See arm/arm/trap.c data_abort_handler() */ 166ef1412bdSWarner Losh info.si_signo = TARGET_SIGSEGV; 167ef1412bdSWarner Losh info.si_errno = 0; 168ef1412bdSWarner Losh /* XXX: check env->error_code */ 169ef1412bdSWarner Losh info.si_code = 0; 170ef1412bdSWarner Losh info.si_addr = env->exception.vaddress; 171ef1412bdSWarner Losh queue_signal(env, info.si_signo, &info); 172ef1412bdSWarner Losh break; 17370985aecSWarner Losh case EXCP_DEBUG: 17470985aecSWarner Losh { 17570985aecSWarner Losh 17670985aecSWarner Losh info.si_signo = TARGET_SIGTRAP; 17770985aecSWarner Losh info.si_errno = 0; 17870985aecSWarner Losh info.si_code = TARGET_TRAP_BRKPT; 17970985aecSWarner Losh info.si_addr = env->exception.vaddress; 18070985aecSWarner Losh queue_signal(env, info.si_signo, &info); 18170985aecSWarner Losh } 18270985aecSWarner Losh break; 18370985aecSWarner Losh case EXCP_YIELD: 18470985aecSWarner Losh /* nothing to do here for user-mode, just resume guest code */ 18570985aecSWarner Losh break; 186*c0d2691cSWarner Losh case EXCP_ATOMIC: 187*c0d2691cSWarner Losh cpu_exec_step_atomic(cs); 188*c0d2691cSWarner Losh break; 18906efe3bfSWarner Losh default: 19006efe3bfSWarner Losh fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 19106efe3bfSWarner Losh trapnr); 19206efe3bfSWarner Losh cpu_dump_state(cs, stderr, 0); 19306efe3bfSWarner Losh abort(); 19406efe3bfSWarner Losh } /* switch() */ 19506efe3bfSWarner Losh process_pending_signals(env); 19606efe3bfSWarner Losh } /* for (;;) */ 19706efe3bfSWarner Losh } 19806efe3bfSWarner Losh 199e17d4c9aSWarner Losh static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp) 200e17d4c9aSWarner Losh { 201e17d4c9aSWarner Losh if (newsp) { 202e17d4c9aSWarner Losh env->regs[13] = newsp; 203e17d4c9aSWarner Losh } 204e17d4c9aSWarner Losh env->regs[0] = 0; 205e17d4c9aSWarner Losh } 206e17d4c9aSWarner Losh 207ca5d32a3SWarner Losh static inline void target_cpu_reset(CPUArchState *cpu) 208ca5d32a3SWarner Losh { 209ca5d32a3SWarner Losh } 210ca5d32a3SWarner Losh 211ca5d32a3SWarner Losh #endif /* !_TARGET_ARCH_CPU_H */ 212