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, si_signo, si_code; 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 case EXCP_NOCP: 54 case EXCP_INVSTATE: 55 /* 56 * See arm/arm/undefined.c undefinedinstruction(); 57 * 58 * A number of details aren't emulated (they likely don't matter): 59 * o Misaligned PC generates ILL_ILLADR (these can't come from qemu) 60 * o Thumb-2 instructions generate ILLADR 61 * o Both modes implement coprocessor instructions, which we don't 62 * do here. FreeBSD just implements them for the VFP coprocessor 63 * and special kernel breakpoints, trace points, dtrace, etc. 64 */ 65 force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->regs[15]); 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/syscall.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 case EXCP_DATA_ABORT: 153 /* 154 * See arm/arm/trap-v6.c prefetch_abort_handler() and 155 * data_abort_handler() 156 * 157 * However, FreeBSD maps these to a generic value and then uses that 158 * to maybe fault in pages in vm/vm_fault.c:vm_fault_trap(). I 159 * believe that the indirection maps the same as Linux, but haven't 160 * chased down every single possible indirection. 161 */ 162 163 /* For user-only we don't set TTBCR_EAE, so look at the FSR. */ 164 switch (env->exception.fsr & 0x1f) { 165 case 0x1: /* Alignment */ 166 si_signo = TARGET_SIGBUS; 167 si_code = TARGET_BUS_ADRALN; 168 break; 169 case 0x3: /* Access flag fault, level 1 */ 170 case 0x6: /* Access flag fault, level 2 */ 171 case 0x9: /* Domain fault, level 1 */ 172 case 0xb: /* Domain fault, level 2 */ 173 case 0xd: /* Permission fault, level 1 */ 174 case 0xf: /* Permission fault, level 2 */ 175 si_signo = TARGET_SIGSEGV; 176 si_code = TARGET_SEGV_ACCERR; 177 break; 178 case 0x5: /* Translation fault, level 1 */ 179 case 0x7: /* Translation fault, level 2 */ 180 si_signo = TARGET_SIGSEGV; 181 si_code = TARGET_SEGV_MAPERR; 182 break; 183 default: 184 g_assert_not_reached(); 185 } 186 force_sig_fault(si_signo, si_code, env->exception.vaddress); 187 break; 188 case EXCP_DEBUG: 189 case EXCP_BKPT: 190 force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[15]); 191 break; 192 case EXCP_YIELD: 193 /* nothing to do here for user-mode, just resume guest code */ 194 break; 195 case EXCP_ATOMIC: 196 cpu_exec_step_atomic(cs); 197 break; 198 default: 199 fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 200 trapnr); 201 cpu_dump_state(cs, stderr, 0); 202 abort(); 203 } /* switch() */ 204 process_pending_signals(env); 205 } /* for (;;) */ 206 } 207 208 static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp) 209 { 210 if (newsp) { 211 env->regs[13] = newsp; 212 } 213 env->regs[0] = 0; 214 } 215 216 static inline void target_cpu_reset(CPUArchState *env) 217 { 218 } 219 220 #endif /* !_TARGET_ARCH_CPU_H */ 221