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 25 #define TARGET_DEFAULT_CPU_MODEL "any" 26 27 static inline void target_cpu_init(CPUARMState *env, 28 struct target_pt_regs *regs) 29 { 30 int i; 31 32 cpsr_write(env, regs->uregs[16], CPSR_USER | CPSR_EXEC, 33 CPSRWriteByInstr); 34 for (i = 0; i < 16; i++) { 35 env->regs[i] = regs->uregs[i]; 36 } 37 } 38 39 static inline void target_cpu_loop(CPUARMState *env) 40 { 41 int trapnr; 42 target_siginfo_t info; 43 unsigned int n; 44 CPUState *cs = env_cpu(env); 45 46 for (;;) { 47 cpu_exec_start(cs); 48 trapnr = cpu_exec(cs); 49 cpu_exec_end(cs); 50 process_queued_cpu_work(cs); 51 switch (trapnr) { 52 case EXCP_UDEF: 53 { 54 /* See arm/arm/undefined.c undefinedinstruction(); */ 55 info.si_addr = env->regs[15]; 56 57 /* illegal instruction */ 58 info.si_signo = TARGET_SIGILL; 59 info.si_errno = 0; 60 info.si_code = TARGET_ILL_ILLOPC; 61 queue_signal(env, info.si_signo, &info); 62 63 /* TODO: What about instruction emulation? */ 64 } 65 break; 66 case EXCP_SWI: 67 case EXCP_BKPT: 68 { 69 /* 70 * system call 71 * See arm/arm/trap.c cpu_fetch_syscall_args() 72 */ 73 if (trapnr == EXCP_BKPT) { 74 if (env->thumb) { 75 env->regs[15] += 2; 76 } else { 77 env->regs[15] += 4; 78 } 79 } 80 n = env->regs[7]; 81 if (bsd_type == target_freebsd) { 82 int ret; 83 abi_ulong params = get_sp_from_cpustate(env); 84 int32_t syscall_nr = n; 85 int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; 86 87 /* See arm/arm/trap.c cpu_fetch_syscall_args() */ 88 if (syscall_nr == TARGET_FREEBSD_NR_syscall) { 89 syscall_nr = env->regs[0]; 90 arg1 = env->regs[1]; 91 arg2 = env->regs[2]; 92 arg3 = env->regs[3]; 93 get_user_s32(arg4, params); 94 params += sizeof(int32_t); 95 get_user_s32(arg5, params); 96 params += sizeof(int32_t); 97 get_user_s32(arg6, params); 98 params += sizeof(int32_t); 99 get_user_s32(arg7, params); 100 arg8 = 0; 101 } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { 102 syscall_nr = env->regs[0]; 103 arg1 = env->regs[2]; 104 arg2 = env->regs[3]; 105 get_user_s32(arg3, params); 106 params += sizeof(int32_t); 107 get_user_s32(arg4, params); 108 params += sizeof(int32_t); 109 get_user_s32(arg5, params); 110 params += sizeof(int32_t); 111 get_user_s32(arg6, params); 112 arg7 = 0; 113 arg8 = 0; 114 } else { 115 arg1 = env->regs[0]; 116 arg2 = env->regs[1]; 117 arg3 = env->regs[2]; 118 arg4 = env->regs[3]; 119 get_user_s32(arg5, params); 120 params += sizeof(int32_t); 121 get_user_s32(arg6, params); 122 params += sizeof(int32_t); 123 get_user_s32(arg7, params); 124 params += sizeof(int32_t); 125 get_user_s32(arg8, params); 126 } 127 ret = do_freebsd_syscall(env, syscall_nr, arg1, arg2, arg3, 128 arg4, arg5, arg6, arg7, arg8); 129 /* 130 * Compare to arm/arm/vm_machdep.c 131 * cpu_set_syscall_retval() 132 */ 133 if (-TARGET_EJUSTRETURN == ret) { 134 /* 135 * Returning from a successful sigreturn syscall. 136 * Avoid clobbering register state. 137 */ 138 break; 139 } 140 if (-TARGET_ERESTART == ret) { 141 env->regs[15] -= env->thumb ? 2 : 4; 142 break; 143 } 144 if ((unsigned int)ret >= (unsigned int)(-515)) { 145 ret = -ret; 146 cpsr_write(env, CPSR_C, CPSR_C, CPSRWriteByInstr); 147 env->regs[0] = ret; 148 } else { 149 cpsr_write(env, 0, CPSR_C, CPSRWriteByInstr); 150 env->regs[0] = ret; /* XXX need to handle lseek()? */ 151 /* env->regs[1] = 0; */ 152 } 153 } else { 154 fprintf(stderr, "qemu: bsd_type (= %d) syscall " 155 "not supported\n", bsd_type); 156 } 157 } 158 break; 159 case EXCP_INTERRUPT: 160 /* just indicate that signals should be handled asap */ 161 break; 162 case EXCP_PREFETCH_ABORT: 163 /* See arm/arm/trap.c prefetch_abort_handler() */ 164 case EXCP_DATA_ABORT: 165 /* See arm/arm/trap.c data_abort_handler() */ 166 info.si_signo = TARGET_SIGSEGV; 167 info.si_errno = 0; 168 /* XXX: check env->error_code */ 169 info.si_code = 0; 170 info.si_addr = env->exception.vaddress; 171 queue_signal(env, info.si_signo, &info); 172 break; 173 case EXCP_DEBUG: 174 { 175 176 info.si_signo = TARGET_SIGTRAP; 177 info.si_errno = 0; 178 info.si_code = TARGET_TRAP_BRKPT; 179 info.si_addr = env->exception.vaddress; 180 queue_signal(env, info.si_signo, &info); 181 } 182 break; 183 case EXCP_ATOMIC: 184 cpu_exec_step_atomic(cs); 185 break; 186 case EXCP_YIELD: 187 /* nothing to do here for user-mode, just resume guest code */ 188 break; 189 default: 190 fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 191 trapnr); 192 cpu_dump_state(cs, stderr, 0); 193 abort(); 194 } /* switch() */ 195 process_pending_signals(env); 196 } /* for (;;) */ 197 } 198 199 static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp) 200 { 201 if (newsp) { 202 env->regs[13] = newsp; 203 } 204 env->regs[0] = 0; 205 } 206 207 static inline void target_cpu_reset(CPUArchState *cpu) 208 { 209 } 210 211 #endif /* !_TARGET_ARCH_CPU_H */ 212