1 /* 2 * arm cpu init and loop 3 * 4 * Copyright (c) 2013 Stacey D. Son 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #ifndef _TARGET_ARCH_CPU_H_ 21 #define _TARGET_ARCH_CPU_H_ 22 23 #include "target_arch.h" 24 #include "signal-common.h" 25 26 #define TARGET_DEFAULT_CPU_MODEL "any" 27 28 static inline void target_cpu_init(CPUARMState *env, 29 struct target_pt_regs *regs) 30 { 31 int i; 32 33 cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC, 34 CPSRWriteByInstr); 35 for (i = 0; i < 16; i++) { 36 env->regs[i] = regs->uregs[i]; 37 } 38 } 39 40 static inline void target_cpu_loop(CPUARMState *env) 41 { 42 int trapnr; 43 target_siginfo_t info; 44 unsigned int n; 45 CPUState *cs = env_cpu(env); 46 47 for (;;) { 48 cpu_exec_start(cs); 49 trapnr = cpu_exec(cs); 50 cpu_exec_end(cs); 51 process_queued_cpu_work(cs); 52 switch (trapnr) { 53 case EXCP_UDEF: 54 { 55 /* See arm/arm/undefined.c undefinedinstruction(); */ 56 info.si_addr = env->regs[15]; 57 58 /* illegal instruction */ 59 info.si_signo = TARGET_SIGILL; 60 info.si_errno = 0; 61 info.si_code = TARGET_ILL_ILLOPC; 62 queue_signal(env, info.si_signo, &info); 63 64 /* TODO: What about instruction emulation? */ 65 } 66 break; 67 case EXCP_SWI: 68 { 69 n = env->regs[7]; 70 if (bsd_type == target_freebsd) { 71 int ret; 72 abi_ulong params = get_sp_from_cpustate(env); 73 int32_t syscall_nr = n; 74 int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; 75 76 /* See arm/arm/trap.c cpu_fetch_syscall_args() */ 77 if (syscall_nr == TARGET_FREEBSD_NR_syscall) { 78 syscall_nr = env->regs[0]; 79 arg1 = env->regs[1]; 80 arg2 = env->regs[2]; 81 arg3 = env->regs[3]; 82 get_user_s32(arg4, params); 83 params += sizeof(int32_t); 84 get_user_s32(arg5, params); 85 params += sizeof(int32_t); 86 get_user_s32(arg6, params); 87 params += sizeof(int32_t); 88 get_user_s32(arg7, params); 89 arg8 = 0; 90 } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { 91 syscall_nr = env->regs[0]; 92 arg1 = env->regs[2]; 93 arg2 = env->regs[3]; 94 get_user_s32(arg3, params); 95 params += sizeof(int32_t); 96 get_user_s32(arg4, params); 97 params += sizeof(int32_t); 98 get_user_s32(arg5, params); 99 params += sizeof(int32_t); 100 get_user_s32(arg6, params); 101 arg7 = 0; 102 arg8 = 0; 103 } else { 104 arg1 = env->regs[0]; 105 arg2 = env->regs[1]; 106 arg3 = env->regs[2]; 107 arg4 = env->regs[3]; 108 get_user_s32(arg5, params); 109 params += sizeof(int32_t); 110 get_user_s32(arg6, params); 111 params += sizeof(int32_t); 112 get_user_s32(arg7, params); 113 params += sizeof(int32_t); 114 get_user_s32(arg8, params); 115 } 116 ret = do_freebsd_syscall(env, syscall_nr, arg1, arg2, arg3, 117 arg4, arg5, arg6, arg7, arg8); 118 /* 119 * Compare to arm/arm/vm_machdep.c 120 * cpu_set_syscall_retval() 121 */ 122 if (-TARGET_EJUSTRETURN == ret) { 123 /* 124 * Returning from a successful sigreturn syscall. 125 * Avoid clobbering register state. 126 */ 127 break; 128 } 129 if (-TARGET_ERESTART == ret) { 130 env->regs[15] -= env->thumb ? 2 : 4; 131 break; 132 } 133 if ((unsigned int)ret >= (unsigned int)(-515)) { 134 ret = -ret; 135 cpsr_write(env, CPSR_C, CPSR_C, CPSRWriteByInstr); 136 env->regs[0] = ret; 137 } else { 138 cpsr_write(env, 0, CPSR_C, CPSRWriteByInstr); 139 env->regs[0] = ret; /* XXX need to handle lseek()? */ 140 /* env->regs[1] = 0; */ 141 } 142 } else { 143 fprintf(stderr, "qemu: bsd_type (= %d) syscall " 144 "not supported\n", bsd_type); 145 } 146 } 147 break; 148 case EXCP_INTERRUPT: 149 /* just indicate that signals should be handled asap */ 150 break; 151 case EXCP_PREFETCH_ABORT: 152 /* See arm/arm/trap.c prefetch_abort_handler() */ 153 case EXCP_DATA_ABORT: 154 /* See arm/arm/trap.c data_abort_handler() */ 155 info.si_signo = TARGET_SIGSEGV; 156 info.si_errno = 0; 157 /* XXX: check env->error_code */ 158 info.si_code = 0; 159 info.si_addr = env->exception.vaddress; 160 queue_signal(env, info.si_signo, &info); 161 break; 162 case EXCP_DEBUG: 163 case EXCP_BKPT: 164 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[15]); 165 break; 166 case EXCP_YIELD: 167 /* nothing to do here for user-mode, just resume guest code */ 168 break; 169 case EXCP_ATOMIC: 170 cpu_exec_step_atomic(cs); 171 break; 172 default: 173 fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 174 trapnr); 175 cpu_dump_state(cs, stderr, 0); 176 abort(); 177 } /* switch() */ 178 process_pending_signals(env); 179 } /* for (;;) */ 180 } 181 182 static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp) 183 { 184 if (newsp) { 185 env->regs[13] = newsp; 186 } 187 env->regs[0] = 0; 188 } 189 190 static inline void target_cpu_reset(CPUArchState *cpu) 191 { 192 } 193 194 #endif /* !_TARGET_ARCH_CPU_H */ 195