// SPDX-License-Identifier: GPL-2.0-only /* * Kernel traps/events for Hexagon processor * * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
*/
#ifdef CONFIG_GENERIC_BUG /* Maybe should resemble arch/sh/kernel/traps.c ?? */ int is_valid_bugaddr(unsignedlong addr)
{ return 1;
} #endif/* CONFIG_GENERIC_BUG */
staticconstchar *ex_name(int ex)
{ switch (ex) { case HVM_GE_C_XPROT: case HVM_GE_C_XUSER: return"Execute protection fault"; case HVM_GE_C_RPROT: case HVM_GE_C_RUSER: return"Read protection fault"; case HVM_GE_C_WPROT: case HVM_GE_C_WUSER: return"Write protection fault"; case HVM_GE_C_XMAL: return"Misaligned instruction"; case HVM_GE_C_WREG: return"Multiple writes to same register in packet"; case HVM_GE_C_PCAL: return"Program counter values that are not properly aligned"; case HVM_GE_C_RMAL: return"Misaligned data load"; case HVM_GE_C_WMAL: return"Misaligned data store"; case HVM_GE_C_INVI: case HVM_GE_C_PRIVI: return"Illegal instruction"; case HVM_GE_C_BUS: return"Precise bus error"; case HVM_GE_C_CACHE: return"Cache error";
if (in_interrupt())
panic("Fatal exception in interrupt");
if (panic_on_oops)
panic("Fatal exception");
oops_exit();
make_task_dead(err); return 0;
}
int die_if_kernel(char *str, struct pt_regs *regs, long err)
{ if (!user_mode(regs)) return die(str, regs, err); else return 0;
}
/* * It's not clear that misaligned fetches are ever recoverable.
*/ staticvoid misaligned_instruction(struct pt_regs *regs)
{
die_if_kernel("Misaligned Instruction", regs, 0);
force_sig(SIGBUS);
}
/* * Misaligned loads and stores, on the other hand, can be * emulated, and probably should be, some day. But for now * they will be considered fatal.
*/ staticvoid misaligned_data_load(struct pt_regs *regs)
{
die_if_kernel("Misaligned Data Load", regs, 0);
force_sig(SIGBUS);
}
/* * Precise bus errors may be recoverable with a a retry, * but for now, treat them as irrecoverable.
*/ staticvoid precise_bus_error(struct pt_regs *regs)
{
die_if_kernel("Precise Bus Error", regs, 0);
force_sig(SIGBUS);
}
/* * If anything is to be done here other than panic, * it will probably be complex and migrate to another * source module. For now, just die.
*/ staticvoid cache_error(struct pt_regs *regs)
{
die("Cache Error", regs, 0);
}
/* * General exception handler
*/ void do_genex(struct pt_regs *regs); void do_genex(struct pt_regs *regs)
{ /* * Decode Cause and Dispatch
*/ switch (pt_cause(regs)) { case HVM_GE_C_XPROT: case HVM_GE_C_XUSER:
execute_protection_fault(regs); break; case HVM_GE_C_RPROT: case HVM_GE_C_RUSER:
read_protection_fault(regs); break; case HVM_GE_C_WPROT: case HVM_GE_C_WUSER:
write_protection_fault(regs); break; case HVM_GE_C_XMAL:
misaligned_instruction(regs); break; case HVM_GE_C_WREG:
illegal_instruction(regs); break; case HVM_GE_C_PCAL:
misaligned_instruction(regs); break; case HVM_GE_C_RMAL:
misaligned_data_load(regs); break; case HVM_GE_C_WMAL:
misaligned_data_store(regs); break; case HVM_GE_C_INVI: case HVM_GE_C_PRIVI:
illegal_instruction(regs); break; case HVM_GE_C_BUS:
precise_bus_error(regs); break; case HVM_GE_C_CACHE:
cache_error(regs); break; default: /* Halt and catch fire */
panic("Unrecognized exception 0x%lx\n", pt_cause(regs)); break;
}
}
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) &&
ptrace_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;
/* allow strace to get the syscall return state */ if (unlikely(test_thread_flag(TIF_SYSCALL_TRACE)))
ptrace_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) */
}
/* * Machine check exception handler
*/ void do_machcheck(struct pt_regs *regs); void do_machcheck(struct pt_regs *regs)
{ /* Halt and catch fire */
__vmstop();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.