in kernel/traps.c [341:413]
void do_trap0(struct pt_regs *regs)
{
syscall_fn syscall;
switch (pt_cause(regs)) {
case TRAP_SYSCALL:
/* System call is trap0 #1 */
/* allow strace to catch syscall args */
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACE) &&
tracehook_report_syscall_entry(regs)))
return; /* return -ENOSYS somewhere? */
/* Interrupts should be re-enabled for syscall processing */
__vmsetie(VM_INT_ENABLE);
/*
* System call number is in r6, arguments in r0..r5.
* Fortunately, no Linux syscall has more than 6 arguments,
* and Hexagon ABI passes first 6 arguments in registers.
* 64-bit arguments are passed in odd/even register pairs.
* Fortunately, we have no system calls that take more
* than three arguments with more than one 64-bit value.
* Should that change, we'd need to redesign to copy
* between user and kernel stacks.
*/
regs->syscall_nr = regs->r06;
/*
* GPR R0 carries the first parameter, and is also used
* to report the return value. We need a backup of
* the user's value in case we need to do a late restart
* of the system call.
*/
regs->restart_r0 = regs->r00;
if ((unsigned long) regs->syscall_nr >= __NR_syscalls) {
regs->r00 = -1;
} else {
syscall = (syscall_fn)
(sys_call_table[regs->syscall_nr]);
regs->r00 = syscall(regs->r00, regs->r01,
regs->r02, regs->r03,
regs->r04, regs->r05);
}
/* allow strace to get the syscall return state */
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACE)))
tracehook_report_syscall_exit(regs, 0);
break;
case TRAP_DEBUG:
/* Trap0 0xdb is debug breakpoint */
if (user_mode(regs)) {
/*
* Some architecures add some per-thread state
* to distinguish between breakpoint traps and
* trace traps. We may want to do that, and
* set the si_code value appropriately, or we
* may want to use a different trap0 flavor.
*/
force_sig_fault(SIGTRAP, TRAP_BRKPT,
(void __user *) pt_elr(regs));
} else {
#ifdef CONFIG_KGDB
kgdb_handle_exception(pt_cause(regs), SIGTRAP,
TRAP_BRKPT, regs);
#endif
}
break;
}
/* Ignore other trap0 codes for now, especially 0 (Angel calls) */
}