Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f0bb4ad7 authored by Alex Van Brunt's avatar Alex Van Brunt Committed by Ruchi Kandoi
Browse files

arm64: add undefined instruction handler hooks



Add undefined instruction handler hooks similar to the system in the
arm archetecture. One difference is that hooks can only be added at
boot time and they can never be removed. This removes the need for
the spinlock in the handler.

Change-Id: I4684937f5209ca2a64ee63947bb2ab6411ae14f7
Signed-off-by: default avatarAlex Van Brunt <avanbrunt@nvidia.com>
Reviewed-on: http://git-master/r/361736
Reviewed-on: http://git-master/r/365059


Reviewed-by: default avatarRichard Wiley <rwiley@nvidia.com>
Tested-by: default avatarOskari Jaaskelainen <oskarij@nvidia.com>
parent 6fdf4dcc
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -18,6 +18,19 @@
#ifndef __ASM_TRAP_H
#define __ASM_TRAP_H

#include <linux/list.h>

struct undef_hook {
	struct list_head node;
	u32 instr_mask;
	u32 instr_val;
	u32 pstate_mask;
	u32 pstate_val;
	int (*fn)(struct pt_regs *regs, unsigned int instr);
};

void register_undef_hook(struct undef_hook *hook);

static inline int in_exception_text(unsigned long ptr)
{
	extern char __exception_text_start[];
+40 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
 *
 * Copyright (C) 1995-2009 Russell King
 * Copyright (C) 2012 ARM Ltd.
 * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
@@ -259,15 +260,54 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
	}
}

static LIST_HEAD(undef_hook);

void register_undef_hook(struct undef_hook *hook)
{
	list_add(&hook->node, &undef_hook);
}

static int call_undef_hook(struct pt_regs *regs, unsigned int instr)
{
	struct undef_hook *hook;
	int (*fn)(struct pt_regs *regs, unsigned int instr) = NULL;

	list_for_each_entry(hook, &undef_hook, node)
		if ((instr & hook->instr_mask) == hook->instr_val &&
		    (regs->pstate & hook->pstate_mask) == hook->pstate_val)
			fn = hook->fn;

	return fn ? fn(regs, instr) : 1;
}

asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
{
	u32 instr;
	siginfo_t info;
	void __user *pc = (void __user *)instruction_pointer(regs);

	/* check for AArch32 breakpoint instructions */
	if (!aarch32_break_handler(regs))
		return;
	if (compat_thumb_mode(regs)) {
		if (get_user(instr, (u16 __user *)pc))
			goto die_sig;
		if (is_wide_instruction(instr)) {
			u32 instr2;
			if (get_user(instr2, (u16 __user *)pc+1))
				goto die_sig;
			instr <<= 16;
			instr |= instr2;
		}

	} else if ((get_user(instr, (u32 __user *)pc))) {
		goto die_sig;
	}

	if (call_undef_hook(regs, instr) == 0)
		return;

die_sig:
	if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
	    printk_ratelimit()) {
		pr_info("%s[%d]: undefined instruction: pc=%p\n",