xref: /qemu/bsd-user/arm/target_arch_cpu.h (revision c0d2691ccce7828ade341a263df1d51ce1dfe9ff)
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