18cbb4fc1SStacey Son /*
28cbb4fc1SStacey Son  *  ARM AArch64 cpu init and loop
38cbb4fc1SStacey Son  *
48cbb4fc1SStacey Son  * Copyright (c) 2015 Stacey Son
58cbb4fc1SStacey Son  *
68cbb4fc1SStacey Son  * This library is free software; you can redistribute it and/or
78cbb4fc1SStacey Son  * modify it under the terms of the GNU Lesser General Public
88cbb4fc1SStacey Son  * License as published by the Free Software Foundation; either
98cbb4fc1SStacey Son  * version 2 of the License, or (at your option) any later version.
108cbb4fc1SStacey Son  *
118cbb4fc1SStacey Son  * This library is distributed in the hope that it will be useful,
128cbb4fc1SStacey Son  * but WITHOUT ANY WARRANTY; without even the implied warranty of
138cbb4fc1SStacey Son  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
148cbb4fc1SStacey Son  * Lesser General Public License for more details.
158cbb4fc1SStacey Son  *
168cbb4fc1SStacey Son  * You should have received a copy of the GNU Lesser General Public
178cbb4fc1SStacey Son  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
188cbb4fc1SStacey Son  */
198cbb4fc1SStacey Son 
208cbb4fc1SStacey Son #ifndef TARGET_ARCH_CPU_H
218cbb4fc1SStacey Son #define TARGET_ARCH_CPU_H
228cbb4fc1SStacey Son 
238cbb4fc1SStacey Son #include "target_arch.h"
248cbb4fc1SStacey Son #include "signal-common.h"
258cbb4fc1SStacey Son #include "target/arm/syndrome.h"
268cbb4fc1SStacey Son 
278cbb4fc1SStacey Son #define TARGET_DEFAULT_CPU_MODEL "any"
288cbb4fc1SStacey Son 
target_cpu_init(CPUARMState * env,struct target_pt_regs * regs)298cbb4fc1SStacey Son static inline void target_cpu_init(CPUARMState *env,
308cbb4fc1SStacey Son     struct target_pt_regs *regs)
318cbb4fc1SStacey Son {
328cbb4fc1SStacey Son     int i;
338cbb4fc1SStacey Son 
348cbb4fc1SStacey Son     if (!(arm_feature(env, ARM_FEATURE_AARCH64))) {
358cbb4fc1SStacey Son         fprintf(stderr, "The selected ARM CPU does not support 64 bit mode\n");
368cbb4fc1SStacey Son         exit(1);
378cbb4fc1SStacey Son     }
388cbb4fc1SStacey Son     for (i = 0; i < 31; i++) {
398cbb4fc1SStacey Son         env->xregs[i] = regs->regs[i];
408cbb4fc1SStacey Son     }
418cbb4fc1SStacey Son     env->pc = regs->pc;
428cbb4fc1SStacey Son     env->xregs[31] = regs->sp;
438cbb4fc1SStacey Son }
448cbb4fc1SStacey Son 
458cbb4fc1SStacey Son 
target_cpu_loop(CPUARMState * env)468cbb4fc1SStacey Son static inline void target_cpu_loop(CPUARMState *env)
478cbb4fc1SStacey Son {
488cbb4fc1SStacey Son     CPUState *cs = env_cpu(env);
498cbb4fc1SStacey Son     int trapnr, ec, fsc, si_code, si_signo;
508cbb4fc1SStacey Son     uint64_t code, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
518cbb4fc1SStacey Son     abi_long ret;
528cbb4fc1SStacey Son 
538cbb4fc1SStacey Son     for (;;) {
548cbb4fc1SStacey Son         cpu_exec_start(cs);
558cbb4fc1SStacey Son         trapnr = cpu_exec(cs);
568cbb4fc1SStacey Son         cpu_exec_end(cs);
578cbb4fc1SStacey Son         process_queued_cpu_work(cs);
588cbb4fc1SStacey Son 
598cbb4fc1SStacey Son         switch (trapnr) {
608cbb4fc1SStacey Son         case EXCP_SWI:
618cbb4fc1SStacey Son             /* See arm64/arm64/trap.c cpu_fetch_syscall_args() */
628cbb4fc1SStacey Son             code = env->xregs[8];
638cbb4fc1SStacey Son             if (code == TARGET_FREEBSD_NR_syscall ||
648cbb4fc1SStacey Son                 code == TARGET_FREEBSD_NR___syscall) {
658cbb4fc1SStacey Son                 code = env->xregs[0];
668cbb4fc1SStacey Son                 arg1 = env->xregs[1];
678cbb4fc1SStacey Son                 arg2 = env->xregs[2];
688cbb4fc1SStacey Son                 arg3 = env->xregs[3];
698cbb4fc1SStacey Son                 arg4 = env->xregs[4];
708cbb4fc1SStacey Son                 arg5 = env->xregs[5];
718cbb4fc1SStacey Son                 arg6 = env->xregs[6];
728cbb4fc1SStacey Son                 arg7 = env->xregs[7];
738cbb4fc1SStacey Son                 arg8 = 0;
748cbb4fc1SStacey Son             } else {
758cbb4fc1SStacey Son                 arg1 = env->xregs[0];
768cbb4fc1SStacey Son                 arg2 = env->xregs[1];
778cbb4fc1SStacey Son                 arg3 = env->xregs[2];
788cbb4fc1SStacey Son                 arg4 = env->xregs[3];
798cbb4fc1SStacey Son                 arg5 = env->xregs[4];
808cbb4fc1SStacey Son                 arg6 = env->xregs[5];
818cbb4fc1SStacey Son                 arg7 = env->xregs[6];
828cbb4fc1SStacey Son                 arg8 = env->xregs[7];
838cbb4fc1SStacey Son             }
848cbb4fc1SStacey Son             ret = do_freebsd_syscall(env, code, arg1, arg2, arg3,
858cbb4fc1SStacey Son                     arg4, arg5, arg6, arg7, arg8);
868cbb4fc1SStacey Son             /*
878cbb4fc1SStacey Son              * The carry bit is cleared for no error; set for error.
888cbb4fc1SStacey Son              * See arm64/arm64/vm_machdep.c cpu_set_syscall_retval()
898cbb4fc1SStacey Son              */
908cbb4fc1SStacey Son             if (ret >= 0) {
91*ce6c541dSStacey Son                 env->CF = 0;
928cbb4fc1SStacey Son                 env->xregs[0] = ret;
938cbb4fc1SStacey Son             } else if (ret == -TARGET_ERESTART) {
948cbb4fc1SStacey Son                 env->pc -= 4;
958cbb4fc1SStacey Son                 break;
968cbb4fc1SStacey Son             } else if (ret != -TARGET_EJUSTRETURN) {
97*ce6c541dSStacey Son                 env->CF = 1;
988cbb4fc1SStacey Son                 env->xregs[0] = -ret;
998cbb4fc1SStacey Son             }
1008cbb4fc1SStacey Son             break;
1018cbb4fc1SStacey Son 
1028cbb4fc1SStacey Son         case EXCP_INTERRUPT:
1038cbb4fc1SStacey Son             /* Just indicate that signals should be handle ASAP. */
1048cbb4fc1SStacey Son             break;
1058cbb4fc1SStacey Son 
1068cbb4fc1SStacey Son         case EXCP_UDEF:
1078cbb4fc1SStacey Son             force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
1088cbb4fc1SStacey Son             break;
1098cbb4fc1SStacey Son 
1108cbb4fc1SStacey Son 
1118cbb4fc1SStacey Son         case EXCP_PREFETCH_ABORT:
1128cbb4fc1SStacey Son         case EXCP_DATA_ABORT:
1138cbb4fc1SStacey Son             /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */
1148cbb4fc1SStacey Son             ec = syn_get_ec(env->exception.syndrome);
1158cbb4fc1SStacey Son             assert(ec == EC_DATAABORT || ec == EC_INSNABORT);
1168cbb4fc1SStacey Son 
1178cbb4fc1SStacey Son             /* Both EC have the same format for FSC, or close enough. */
1188cbb4fc1SStacey Son             fsc = extract32(env->exception.syndrome, 0, 6);
1198cbb4fc1SStacey Son             switch (fsc) {
1208cbb4fc1SStacey Son             case 0x04 ... 0x07: /* Translation fault, level {0-3} */
1218cbb4fc1SStacey Son                 si_signo = TARGET_SIGSEGV;
1228cbb4fc1SStacey Son                 si_code = TARGET_SEGV_MAPERR;
1238cbb4fc1SStacey Son                 break;
1248cbb4fc1SStacey Son             case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
1258cbb4fc1SStacey Son             case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
1268cbb4fc1SStacey Son                 si_signo = TARGET_SIGSEGV;
1278cbb4fc1SStacey Son                 si_code = TARGET_SEGV_ACCERR;
1288cbb4fc1SStacey Son                 break;
1298cbb4fc1SStacey Son             case 0x11: /* Synchronous Tag Check Fault */
1308cbb4fc1SStacey Son                 si_signo = TARGET_SIGSEGV;
1318cbb4fc1SStacey Son                 si_code = /* TARGET_SEGV_MTESERR; */ TARGET_SEGV_ACCERR;
1328cbb4fc1SStacey Son                 break;
1338cbb4fc1SStacey Son             case 0x21: /* Alignment fault */
1348cbb4fc1SStacey Son                 si_signo = TARGET_SIGBUS;
1358cbb4fc1SStacey Son                 si_code = TARGET_BUS_ADRALN;
1368cbb4fc1SStacey Son                 break;
1378cbb4fc1SStacey Son             default:
1388cbb4fc1SStacey Son                 g_assert_not_reached();
1398cbb4fc1SStacey Son             }
1408cbb4fc1SStacey Son             force_sig_fault(si_signo, si_code, env->exception.vaddress);
1418cbb4fc1SStacey Son             break;
1428cbb4fc1SStacey Son 
1438cbb4fc1SStacey Son         case EXCP_DEBUG:
1448cbb4fc1SStacey Son         case EXCP_BKPT:
1458cbb4fc1SStacey Son             force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
1468cbb4fc1SStacey Son             break;
1478cbb4fc1SStacey Son 
1488cbb4fc1SStacey Son         case EXCP_ATOMIC:
1498cbb4fc1SStacey Son             cpu_exec_step_atomic(cs);
1508cbb4fc1SStacey Son             break;
1518cbb4fc1SStacey Son 
1528cbb4fc1SStacey Son         case EXCP_YIELD:
1538cbb4fc1SStacey Son             /* nothing to do here for user-mode, just resume guest code */
1548cbb4fc1SStacey Son             break;
1558cbb4fc1SStacey Son         default:
1568cbb4fc1SStacey Son             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
1578cbb4fc1SStacey Son                     trapnr);
1588cbb4fc1SStacey Son             cpu_dump_state(cs, stderr, 0);
1598cbb4fc1SStacey Son             abort();
1608cbb4fc1SStacey Son         } /* switch() */
1618cbb4fc1SStacey Son         process_pending_signals(env);
1628cbb4fc1SStacey Son         /*
1638cbb4fc1SStacey Son          * Exception return on AArch64 always clears the exclusive
1648cbb4fc1SStacey Son          * monitor, so any return to running guest code implies this.
1658cbb4fc1SStacey Son          * A strex (successful or otherwise) also clears the monitor, so
1668cbb4fc1SStacey Son          * we don't need to specialcase EXCP_STREX.
1678cbb4fc1SStacey Son          */
1688cbb4fc1SStacey Son         env->exclusive_addr = -1;
1698cbb4fc1SStacey Son     } /* for (;;) */
1708cbb4fc1SStacey Son }
1718cbb4fc1SStacey Son 
1728cbb4fc1SStacey Son 
1738cbb4fc1SStacey Son /* See arm64/arm64/vm_machdep.c cpu_fork() */
target_cpu_clone_regs(CPUARMState * env,target_ulong newsp)1748cbb4fc1SStacey Son static inline void target_cpu_clone_regs(CPUARMState *env, target_ulong newsp)
1758cbb4fc1SStacey Son {
1768cbb4fc1SStacey Son     if (newsp) {
1778cbb4fc1SStacey Son         env->xregs[31] = newsp;
1788cbb4fc1SStacey Son     }
1798cbb4fc1SStacey Son     env->regs[0] = 0;
1808cbb4fc1SStacey Son     env->regs[1] = 0;
1818cbb4fc1SStacey Son     pstate_write(env, 0);
1828cbb4fc1SStacey Son }
1838cbb4fc1SStacey Son 
target_cpu_reset(CPUArchState * env)1848cbb4fc1SStacey Son static inline void target_cpu_reset(CPUArchState *env)
1858cbb4fc1SStacey Son {
1868cbb4fc1SStacey Son }
1878cbb4fc1SStacey Son 
1888cbb4fc1SStacey Son 
1898cbb4fc1SStacey Son #endif /* TARGET_ARCH_CPU_H */
190