Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *  linux/arch/arm/kernel/swp_emulate.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *  Copyright (C) 2009 ARM Limited
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *  __user_* functions adapted from include/asm/uaccess.h
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *  Implements emulation of the SWP/SWPB instructions using load-exclusive and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *  store-exclusive for processors that have them disabled (or future ones that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *  might not implement them).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  *  Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  *  Where: Rt  = destination
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  *	   Rt2 = source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  *	   Rn  = address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/sched/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/syscalls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <linux/perf_event.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include <asm/opcodes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include <asm/system_info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #include <asm/traps.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)  * Error-checking SWP macros implemented using ldrex{b}/strex{b}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #define __user_swpX_asm(data, addr, res, temp, B)		\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	__asm__ __volatile__(					\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	"0:	ldrex"B"	%2, [%3]\n"			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	"1:	strex"B"	%0, %1, [%3]\n"			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	"	cmp		%0, #0\n"			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	"	moveq		%1, %2\n"			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	"	movne		%0, %4\n"			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	"2:\n"							\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	"	.section	 .text.fixup,\"ax\"\n"		\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	"	.align		2\n"				\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 	"3:	mov		%0, %5\n"			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	"	b		2b\n"				\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	"	.previous\n"					\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	"	.section	 __ex_table,\"a\"\n"		\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	"	.align		3\n"				\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	"	.long		0b, 3b\n"			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	"	.long		1b, 3b\n"			\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	"	.previous"					\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	: "=&r" (res), "+r" (data), "=&r" (temp)		\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	: "r" (addr), "i" (-EAGAIN), "i" (-EFAULT)		\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	: "cc", "memory")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) #define __user_swp_asm(data, addr, res, temp) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	__user_swpX_asm(data, addr, res, temp, "")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) #define __user_swpb_asm(data, addr, res, temp) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	__user_swpX_asm(data, addr, res, temp, "b")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63)  * Macros/defines for extracting register numbers from instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) #define EXTRACT_REG_NUM(instruction, offset) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	(((instruction) & (0xf << (offset))) >> (offset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) #define RN_OFFSET  16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) #define RT_OFFSET  12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) #define RT2_OFFSET  0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71)  * Bit 22 of the instruction encoding distinguishes between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72)  * the SWP and SWPB variants (bit set means SWPB).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) #define TYPE_SWPB (1 << 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) static unsigned long swpcounter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) static unsigned long swpbcounter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) static unsigned long abtcounter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) static pid_t         previous_pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) #ifdef CONFIG_PROC_FS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) static int proc_status_show(struct seq_file *m, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	seq_printf(m, "Emulated SWP:\t\t%lu\n", swpcounter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	seq_printf(m, "Emulated SWPB:\t\t%lu\n", swpbcounter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	seq_printf(m, "Aborted SWP{B}:\t\t%lu\n", abtcounter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	if (previous_pid != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 		seq_printf(m, "Last process:\t\t%d\n", previous_pid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94)  * Set up process info to signal segmentation fault - called on access error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) static void set_segfault(struct pt_regs *regs, unsigned long addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	int si_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	mmap_read_lock(current->mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	if (find_vma(current->mm, addr) == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 		si_code = SEGV_MAPERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		si_code = SEGV_ACCERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	mmap_read_unlock(current->mm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	pr_debug("SWP{B} emulation: access caused memory abort!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	arm_notify_die("Illegal memory access", regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		       SIGSEGV, si_code,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		       (void __user *)instruction_pointer(regs),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 		       0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	abtcounter++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static int emulate_swpX(unsigned int address, unsigned int *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 			unsigned int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	unsigned int res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	if ((type != TYPE_SWPB) && (address & 0x3)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 		/* SWP to unaligned address not permitted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 		pr_debug("SWP instruction on unaligned pointer!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 		return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		unsigned long temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		unsigned int __ua_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		__ua_flags = uaccess_save_and_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		if (type == TYPE_SWPB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 			__user_swpb_asm(*data, address, res, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 			__user_swp_asm(*data, address, res, temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		uaccess_restore(__ua_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 		if (likely(res != -EAGAIN) || signal_pending(current))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 		cond_resched();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	if (res == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		if (type == TYPE_SWPB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 			swpbcounter++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 			swpcounter++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)  * swp_handler logs the id of calling process, dissects the instruction, sanity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)  * checks the memory location, calls emulate_swpX for the actual operation and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)  * deals with fixup/error handling before returning
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static int swp_handler(struct pt_regs *regs, unsigned int instr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	unsigned int address, destreg, data, type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	unsigned int res = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->ARM_pc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	res = arm_check_condition(instr, regs->ARM_cpsr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	switch (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	case ARM_OPCODE_CONDTEST_PASS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	case ARM_OPCODE_CONDTEST_FAIL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		/* Condition failed - return to next instruction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		regs->ARM_pc += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	case ARM_OPCODE_CONDTEST_UNCOND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		/* If unconditional encoding - not a SWP, undef */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	if (current->pid != previous_pid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 		pr_debug("\"%s\" (%ld) uses deprecated SWP{B} instruction\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 			 current->comm, (unsigned long)current->pid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		previous_pid = current->pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	address = regs->uregs[EXTRACT_REG_NUM(instr, RN_OFFSET)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	data	= regs->uregs[EXTRACT_REG_NUM(instr, RT2_OFFSET)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	destreg = EXTRACT_REG_NUM(instr, RT_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	type = instr & TYPE_SWPB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		 EXTRACT_REG_NUM(instr, RN_OFFSET), address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 		 destreg, EXTRACT_REG_NUM(instr, RT2_OFFSET), data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	/* Check access in reasonable access range for both SWP and SWPB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	if (!access_ok((void __user *)(address & ~3), 4)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 		pr_debug("SWP{B} emulation: access to %p not allowed!\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 			 (void *)address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 		res = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 		res = emulate_swpX(address, &data, type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	if (res == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		 * On successful emulation, revert the adjustment to the PC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 		 * made in kernel/traps.c in order to resume execution at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		 * instruction following the SWP{B}.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 		regs->ARM_pc += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 		regs->uregs[destreg] = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	} else if (res == -EFAULT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		 * Memory errors do not mean emulation failed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 		 * Set up signal info to return SEGV, then return OK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 		set_segfault(regs, address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)  * Only emulate SWP/SWPB executed in ARM state/User mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)  * The kernel must be SWP free and SWP{B} does not exist in Thumb/ThumbEE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) static struct undef_hook swp_hook = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	.instr_mask = 0x0fb00ff0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	.instr_val  = 0x01000090,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	.cpsr_mask  = MODE_MASK | PSR_T_BIT | PSR_J_BIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	.cpsr_val   = USR_MODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	.fn	    = swp_handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)  * Register handler and create status file in /proc/cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)  * Invoked as late_initcall, since not needed before init spawned.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) static int __init swp_emulation_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	if (cpu_architecture() < CPU_ARCH_ARMv7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) #ifdef CONFIG_PROC_FS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	if (!proc_create_single("cpu/swp_emulation", S_IRUGO, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 			proc_status_show))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) #endif /* CONFIG_PROC_FS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	pr_notice("Registering SWP/SWPB emulation handler\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	register_undef_hook(&swp_hook);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) late_initcall(swp_emulation_init);