162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Kernel traps/events for Hexagon processor
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <linux/sched/signal.h>
1062306a36Sopenharmony_ci#include <linux/sched/debug.h>
1162306a36Sopenharmony_ci#include <linux/sched/task_stack.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/kallsyms.h>
1462306a36Sopenharmony_ci#include <linux/kdebug.h>
1562306a36Sopenharmony_ci#include <linux/syscalls.h>
1662306a36Sopenharmony_ci#include <linux/signal.h>
1762306a36Sopenharmony_ci#include <linux/ptrace.h>
1862306a36Sopenharmony_ci#include <asm/traps.h>
1962306a36Sopenharmony_ci#include <asm/vm_fault.h>
2062306a36Sopenharmony_ci#include <asm/syscall.h>
2162306a36Sopenharmony_ci#include <asm/registers.h>
2262306a36Sopenharmony_ci#include <asm/unistd.h>
2362306a36Sopenharmony_ci#include <asm/sections.h>
2462306a36Sopenharmony_ci#ifdef CONFIG_KGDB
2562306a36Sopenharmony_ci# include <linux/kgdb.h>
2662306a36Sopenharmony_ci#endif
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define TRAP_SYSCALL	1
2962306a36Sopenharmony_ci#define TRAP_DEBUG	0xdb
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#ifdef CONFIG_GENERIC_BUG
3262306a36Sopenharmony_ci/* Maybe should resemble arch/sh/kernel/traps.c ?? */
3362306a36Sopenharmony_ciint is_valid_bugaddr(unsigned long addr)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	return 1;
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci#endif /* CONFIG_GENERIC_BUG */
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic const char *ex_name(int ex)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	switch (ex) {
4262306a36Sopenharmony_ci	case HVM_GE_C_XPROT:
4362306a36Sopenharmony_ci	case HVM_GE_C_XUSER:
4462306a36Sopenharmony_ci		return "Execute protection fault";
4562306a36Sopenharmony_ci	case HVM_GE_C_RPROT:
4662306a36Sopenharmony_ci	case HVM_GE_C_RUSER:
4762306a36Sopenharmony_ci		return "Read protection fault";
4862306a36Sopenharmony_ci	case HVM_GE_C_WPROT:
4962306a36Sopenharmony_ci	case HVM_GE_C_WUSER:
5062306a36Sopenharmony_ci		return "Write protection fault";
5162306a36Sopenharmony_ci	case HVM_GE_C_XMAL:
5262306a36Sopenharmony_ci		return "Misaligned instruction";
5362306a36Sopenharmony_ci	case HVM_GE_C_WREG:
5462306a36Sopenharmony_ci		return "Multiple writes to same register in packet";
5562306a36Sopenharmony_ci	case HVM_GE_C_PCAL:
5662306a36Sopenharmony_ci		return "Program counter values that are not properly aligned";
5762306a36Sopenharmony_ci	case HVM_GE_C_RMAL:
5862306a36Sopenharmony_ci		return "Misaligned data load";
5962306a36Sopenharmony_ci	case HVM_GE_C_WMAL:
6062306a36Sopenharmony_ci		return "Misaligned data store";
6162306a36Sopenharmony_ci	case HVM_GE_C_INVI:
6262306a36Sopenharmony_ci	case HVM_GE_C_PRIVI:
6362306a36Sopenharmony_ci		return "Illegal instruction";
6462306a36Sopenharmony_ci	case HVM_GE_C_BUS:
6562306a36Sopenharmony_ci		return "Precise bus error";
6662306a36Sopenharmony_ci	case HVM_GE_C_CACHE:
6762306a36Sopenharmony_ci		return "Cache error";
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	case 0xdb:
7062306a36Sopenharmony_ci		return "Debugger trap";
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	default:
7362306a36Sopenharmony_ci		return "Unrecognized exception";
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic void do_show_stack(struct task_struct *task, unsigned long *fp,
7862306a36Sopenharmony_ci			  unsigned long ip, const char *loglvl)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	int kstack_depth_to_print = 24;
8162306a36Sopenharmony_ci	unsigned long offset, size;
8262306a36Sopenharmony_ci	const char *name = NULL;
8362306a36Sopenharmony_ci	unsigned long *newfp;
8462306a36Sopenharmony_ci	unsigned long low, high;
8562306a36Sopenharmony_ci	char tmpstr[128];
8662306a36Sopenharmony_ci	char *modname;
8762306a36Sopenharmony_ci	int i;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (task == NULL)
9062306a36Sopenharmony_ci		task = current;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	printk("%sCPU#%d, %s/%d, Call Trace:\n", loglvl, raw_smp_processor_id(),
9362306a36Sopenharmony_ci		task->comm, task_pid_nr(task));
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (fp == NULL) {
9662306a36Sopenharmony_ci		if (task == current) {
9762306a36Sopenharmony_ci			asm("%0 = r30" : "=r" (fp));
9862306a36Sopenharmony_ci		} else {
9962306a36Sopenharmony_ci			fp = (unsigned long *)
10062306a36Sopenharmony_ci			     ((struct hexagon_switch_stack *)
10162306a36Sopenharmony_ci			     task->thread.switch_sp)->fp;
10262306a36Sopenharmony_ci		}
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if ((((unsigned long) fp) & 0x3) || ((unsigned long) fp < 0x1000)) {
10662306a36Sopenharmony_ci		printk("%s-- Corrupt frame pointer %p\n", loglvl, fp);
10762306a36Sopenharmony_ci		return;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* Saved link reg is one word above FP */
11162306a36Sopenharmony_ci	if (!ip)
11262306a36Sopenharmony_ci		ip = *(fp+1);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/* Expect kernel stack to be in-bounds */
11562306a36Sopenharmony_ci	low = (unsigned long)task_stack_page(task);
11662306a36Sopenharmony_ci	high = low + THREAD_SIZE - 8;
11762306a36Sopenharmony_ci	low += sizeof(struct thread_info);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	for (i = 0; i < kstack_depth_to_print; i++) {
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		name = kallsyms_lookup(ip, &size, &offset, &modname, tmpstr);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		printk("%s[%p] 0x%lx: %s + 0x%lx", loglvl, fp, ip, name, offset);
12462306a36Sopenharmony_ci		if (((unsigned long) fp < low) || (high < (unsigned long) fp))
12562306a36Sopenharmony_ci			printk(KERN_CONT " (FP out of bounds!)");
12662306a36Sopenharmony_ci		if (modname)
12762306a36Sopenharmony_ci			printk(KERN_CONT " [%s] ", modname);
12862306a36Sopenharmony_ci		printk(KERN_CONT "\n");
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		newfp = (unsigned long *) *fp;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		if (((unsigned long) newfp) & 0x3) {
13362306a36Sopenharmony_ci			printk("%s-- Corrupt frame pointer %p\n", loglvl, newfp);
13462306a36Sopenharmony_ci			break;
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		/* Attempt to continue past exception. */
13862306a36Sopenharmony_ci		if (0 == newfp) {
13962306a36Sopenharmony_ci			struct pt_regs *regs = (struct pt_regs *) (((void *)fp)
14062306a36Sopenharmony_ci						+ 8);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci			if (regs->syscall_nr != -1) {
14362306a36Sopenharmony_ci				printk("%s-- trap0 -- syscall_nr: %ld", loglvl,
14462306a36Sopenharmony_ci					regs->syscall_nr);
14562306a36Sopenharmony_ci				printk(KERN_CONT "  psp: %lx  elr: %lx\n",
14662306a36Sopenharmony_ci					 pt_psp(regs), pt_elr(regs));
14762306a36Sopenharmony_ci				break;
14862306a36Sopenharmony_ci			} else {
14962306a36Sopenharmony_ci				/* really want to see more ... */
15062306a36Sopenharmony_ci				kstack_depth_to_print += 6;
15162306a36Sopenharmony_ci				printk("%s-- %s (0x%lx)  badva: %lx\n", loglvl,
15262306a36Sopenharmony_ci					ex_name(pt_cause(regs)), pt_cause(regs),
15362306a36Sopenharmony_ci					pt_badva(regs));
15462306a36Sopenharmony_ci			}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci			newfp = (unsigned long *) regs->r30;
15762306a36Sopenharmony_ci			ip = pt_elr(regs);
15862306a36Sopenharmony_ci		} else {
15962306a36Sopenharmony_ci			ip = *(newfp + 1);
16062306a36Sopenharmony_ci		}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci		/* If link reg is null, we are done. */
16362306a36Sopenharmony_ci		if (ip == 0x0)
16462306a36Sopenharmony_ci			break;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci		/* If newfp isn't larger, we're tracing garbage. */
16762306a36Sopenharmony_ci		if (newfp > fp)
16862306a36Sopenharmony_ci			fp = newfp;
16962306a36Sopenharmony_ci		else
17062306a36Sopenharmony_ci			break;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_civoid show_stack(struct task_struct *task, unsigned long *fp, const char *loglvl)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	/* Saved link reg is one word above FP */
17762306a36Sopenharmony_ci	do_show_stack(task, fp, 0, loglvl);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ciint die(const char *str, struct pt_regs *regs, long err)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	static struct {
18362306a36Sopenharmony_ci		spinlock_t lock;
18462306a36Sopenharmony_ci		int counter;
18562306a36Sopenharmony_ci	} die = {
18662306a36Sopenharmony_ci		.lock = __SPIN_LOCK_UNLOCKED(die.lock),
18762306a36Sopenharmony_ci		.counter = 0
18862306a36Sopenharmony_ci	};
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	console_verbose();
19162306a36Sopenharmony_ci	oops_enter();
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	spin_lock_irq(&die.lock);
19462306a36Sopenharmony_ci	bust_spinlocks(1);
19562306a36Sopenharmony_ci	printk(KERN_EMERG "Oops: %s[#%d]:\n", str, ++die.counter);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (notify_die(DIE_OOPS, str, regs, err, pt_cause(regs), SIGSEGV) ==
19862306a36Sopenharmony_ci	    NOTIFY_STOP)
19962306a36Sopenharmony_ci		return 1;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	print_modules();
20262306a36Sopenharmony_ci	show_regs(regs);
20362306a36Sopenharmony_ci	do_show_stack(current, &regs->r30, pt_elr(regs), KERN_EMERG);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	bust_spinlocks(0);
20662306a36Sopenharmony_ci	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	spin_unlock_irq(&die.lock);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (in_interrupt())
21162306a36Sopenharmony_ci		panic("Fatal exception in interrupt");
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (panic_on_oops)
21462306a36Sopenharmony_ci		panic("Fatal exception");
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	oops_exit();
21762306a36Sopenharmony_ci	make_task_dead(err);
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ciint die_if_kernel(char *str, struct pt_regs *regs, long err)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	if (!user_mode(regs))
22462306a36Sopenharmony_ci		return die(str, regs, err);
22562306a36Sopenharmony_ci	else
22662306a36Sopenharmony_ci		return 0;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/*
23062306a36Sopenharmony_ci * It's not clear that misaligned fetches are ever recoverable.
23162306a36Sopenharmony_ci */
23262306a36Sopenharmony_cistatic void misaligned_instruction(struct pt_regs *regs)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	die_if_kernel("Misaligned Instruction", regs, 0);
23562306a36Sopenharmony_ci	force_sig(SIGBUS);
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci/*
23962306a36Sopenharmony_ci * Misaligned loads and stores, on the other hand, can be
24062306a36Sopenharmony_ci * emulated, and probably should be, some day.  But for now
24162306a36Sopenharmony_ci * they will be considered fatal.
24262306a36Sopenharmony_ci */
24362306a36Sopenharmony_cistatic void misaligned_data_load(struct pt_regs *regs)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	die_if_kernel("Misaligned Data Load", regs, 0);
24662306a36Sopenharmony_ci	force_sig(SIGBUS);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic void misaligned_data_store(struct pt_regs *regs)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	die_if_kernel("Misaligned Data Store", regs, 0);
25262306a36Sopenharmony_ci	force_sig(SIGBUS);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic void illegal_instruction(struct pt_regs *regs)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	die_if_kernel("Illegal Instruction", regs, 0);
25862306a36Sopenharmony_ci	force_sig(SIGILL);
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci/*
26262306a36Sopenharmony_ci * Precise bus errors may be recoverable with a a retry,
26362306a36Sopenharmony_ci * but for now, treat them as irrecoverable.
26462306a36Sopenharmony_ci */
26562306a36Sopenharmony_cistatic void precise_bus_error(struct pt_regs *regs)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	die_if_kernel("Precise Bus Error", regs, 0);
26862306a36Sopenharmony_ci	force_sig(SIGBUS);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/*
27262306a36Sopenharmony_ci * If anything is to be done here other than panic,
27362306a36Sopenharmony_ci * it will probably be complex and migrate to another
27462306a36Sopenharmony_ci * source module.  For now, just die.
27562306a36Sopenharmony_ci */
27662306a36Sopenharmony_cistatic void cache_error(struct pt_regs *regs)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	die("Cache Error", regs, 0);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/*
28262306a36Sopenharmony_ci * General exception handler
28362306a36Sopenharmony_ci */
28462306a36Sopenharmony_civoid do_genex(struct pt_regs *regs)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	/*
28762306a36Sopenharmony_ci	 * Decode Cause and Dispatch
28862306a36Sopenharmony_ci	 */
28962306a36Sopenharmony_ci	switch (pt_cause(regs)) {
29062306a36Sopenharmony_ci	case HVM_GE_C_XPROT:
29162306a36Sopenharmony_ci	case HVM_GE_C_XUSER:
29262306a36Sopenharmony_ci		execute_protection_fault(regs);
29362306a36Sopenharmony_ci		break;
29462306a36Sopenharmony_ci	case HVM_GE_C_RPROT:
29562306a36Sopenharmony_ci	case HVM_GE_C_RUSER:
29662306a36Sopenharmony_ci		read_protection_fault(regs);
29762306a36Sopenharmony_ci		break;
29862306a36Sopenharmony_ci	case HVM_GE_C_WPROT:
29962306a36Sopenharmony_ci	case HVM_GE_C_WUSER:
30062306a36Sopenharmony_ci		write_protection_fault(regs);
30162306a36Sopenharmony_ci		break;
30262306a36Sopenharmony_ci	case HVM_GE_C_XMAL:
30362306a36Sopenharmony_ci		misaligned_instruction(regs);
30462306a36Sopenharmony_ci		break;
30562306a36Sopenharmony_ci	case HVM_GE_C_WREG:
30662306a36Sopenharmony_ci		illegal_instruction(regs);
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	case HVM_GE_C_PCAL:
30962306a36Sopenharmony_ci		misaligned_instruction(regs);
31062306a36Sopenharmony_ci		break;
31162306a36Sopenharmony_ci	case HVM_GE_C_RMAL:
31262306a36Sopenharmony_ci		misaligned_data_load(regs);
31362306a36Sopenharmony_ci		break;
31462306a36Sopenharmony_ci	case HVM_GE_C_WMAL:
31562306a36Sopenharmony_ci		misaligned_data_store(regs);
31662306a36Sopenharmony_ci		break;
31762306a36Sopenharmony_ci	case HVM_GE_C_INVI:
31862306a36Sopenharmony_ci	case HVM_GE_C_PRIVI:
31962306a36Sopenharmony_ci		illegal_instruction(regs);
32062306a36Sopenharmony_ci		break;
32162306a36Sopenharmony_ci	case HVM_GE_C_BUS:
32262306a36Sopenharmony_ci		precise_bus_error(regs);
32362306a36Sopenharmony_ci		break;
32462306a36Sopenharmony_ci	case HVM_GE_C_CACHE:
32562306a36Sopenharmony_ci		cache_error(regs);
32662306a36Sopenharmony_ci		break;
32762306a36Sopenharmony_ci	default:
32862306a36Sopenharmony_ci		/* Halt and catch fire */
32962306a36Sopenharmony_ci		panic("Unrecognized exception 0x%lx\n", pt_cause(regs));
33062306a36Sopenharmony_ci		break;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci/* Indirect system call dispatch */
33562306a36Sopenharmony_cilong sys_syscall(void)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	printk(KERN_ERR "sys_syscall invoked!\n");
33862306a36Sopenharmony_ci	return -ENOSYS;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_civoid do_trap0(struct pt_regs *regs)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	syscall_fn syscall;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	switch (pt_cause(regs)) {
34662306a36Sopenharmony_ci	case TRAP_SYSCALL:
34762306a36Sopenharmony_ci		/* System call is trap0 #1 */
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		/* allow strace to catch syscall args  */
35062306a36Sopenharmony_ci		if (unlikely(test_thread_flag(TIF_SYSCALL_TRACE) &&
35162306a36Sopenharmony_ci			ptrace_report_syscall_entry(regs)))
35262306a36Sopenharmony_ci			return;  /*  return -ENOSYS somewhere?  */
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		/* Interrupts should be re-enabled for syscall processing */
35562306a36Sopenharmony_ci		__vmsetie(VM_INT_ENABLE);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		/*
35862306a36Sopenharmony_ci		 * System call number is in r6, arguments in r0..r5.
35962306a36Sopenharmony_ci		 * Fortunately, no Linux syscall has more than 6 arguments,
36062306a36Sopenharmony_ci		 * and Hexagon ABI passes first 6 arguments in registers.
36162306a36Sopenharmony_ci		 * 64-bit arguments are passed in odd/even register pairs.
36262306a36Sopenharmony_ci		 * Fortunately, we have no system calls that take more
36362306a36Sopenharmony_ci		 * than three arguments with more than one 64-bit value.
36462306a36Sopenharmony_ci		 * Should that change, we'd need to redesign to copy
36562306a36Sopenharmony_ci		 * between user and kernel stacks.
36662306a36Sopenharmony_ci		 */
36762306a36Sopenharmony_ci		regs->syscall_nr = regs->r06;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci		/*
37062306a36Sopenharmony_ci		 * GPR R0 carries the first parameter, and is also used
37162306a36Sopenharmony_ci		 * to report the return value.  We need a backup of
37262306a36Sopenharmony_ci		 * the user's value in case we need to do a late restart
37362306a36Sopenharmony_ci		 * of the system call.
37462306a36Sopenharmony_ci		 */
37562306a36Sopenharmony_ci		regs->restart_r0 = regs->r00;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		if ((unsigned long) regs->syscall_nr >= __NR_syscalls) {
37862306a36Sopenharmony_ci			regs->r00 = -1;
37962306a36Sopenharmony_ci		} else {
38062306a36Sopenharmony_ci			syscall = (syscall_fn)
38162306a36Sopenharmony_ci				  (sys_call_table[regs->syscall_nr]);
38262306a36Sopenharmony_ci			regs->r00 = syscall(regs->r00, regs->r01,
38362306a36Sopenharmony_ci				   regs->r02, regs->r03,
38462306a36Sopenharmony_ci				   regs->r04, regs->r05);
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		/* allow strace to get the syscall return state  */
38862306a36Sopenharmony_ci		if (unlikely(test_thread_flag(TIF_SYSCALL_TRACE)))
38962306a36Sopenharmony_ci			ptrace_report_syscall_exit(regs, 0);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		break;
39262306a36Sopenharmony_ci	case TRAP_DEBUG:
39362306a36Sopenharmony_ci		/* Trap0 0xdb is debug breakpoint */
39462306a36Sopenharmony_ci		if (user_mode(regs)) {
39562306a36Sopenharmony_ci			/*
39662306a36Sopenharmony_ci			 * Some architecures add some per-thread state
39762306a36Sopenharmony_ci			 * to distinguish between breakpoint traps and
39862306a36Sopenharmony_ci			 * trace traps.  We may want to do that, and
39962306a36Sopenharmony_ci			 * set the si_code value appropriately, or we
40062306a36Sopenharmony_ci			 * may want to use a different trap0 flavor.
40162306a36Sopenharmony_ci			 */
40262306a36Sopenharmony_ci			force_sig_fault(SIGTRAP, TRAP_BRKPT,
40362306a36Sopenharmony_ci					(void __user *) pt_elr(regs));
40462306a36Sopenharmony_ci		} else {
40562306a36Sopenharmony_ci#ifdef CONFIG_KGDB
40662306a36Sopenharmony_ci			kgdb_handle_exception(pt_cause(regs), SIGTRAP,
40762306a36Sopenharmony_ci					      TRAP_BRKPT, regs);
40862306a36Sopenharmony_ci#endif
40962306a36Sopenharmony_ci		}
41062306a36Sopenharmony_ci		break;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci	/* Ignore other trap0 codes for now, especially 0 (Angel calls) */
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci/*
41662306a36Sopenharmony_ci * Machine check exception handler
41762306a36Sopenharmony_ci */
41862306a36Sopenharmony_civoid do_machcheck(struct pt_regs *regs)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	/* Halt and catch fire */
42162306a36Sopenharmony_ci	__vmstop();
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci/*
42562306a36Sopenharmony_ci * Treat this like the old 0xdb trap.
42662306a36Sopenharmony_ci */
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_civoid do_debug_exception(struct pt_regs *regs)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	regs->hvmer.vmest &= ~HVM_VMEST_CAUSE_MSK;
43162306a36Sopenharmony_ci	regs->hvmer.vmest |= (TRAP_DEBUG << HVM_VMEST_CAUSE_SFT);
43262306a36Sopenharmony_ci	do_trap0(regs);
43362306a36Sopenharmony_ci}
434