Commit 91481c90 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull parisc architecture fixes from Helge Deller:
 "The current exception handler, which helps on kernel accesses to
  userspace, may exhibit data corruption. The problem is that it is not
  guaranteed that the compiler will use the processor register we
  specified in the source code, but may choose another register which
  then will lead to silent register- and data corruption. To fix this
  issue we now use another strategy to help the exception handler to
  always find and set the error code into the correct CPU register.

  The other fixes are small: fixing CPU hotplug bringup, fix the page
  alignment of the RO_DATA section, added a check for the calculated
  cache stride and fix possible hangups when printing longer output at
  bootup when running on serial console.

  Most of the patches are tagged for stable series.

   - Fix random data corruption triggered by exception handler

   - Fix crash when setting up BTLB at CPU bringup

   - Prevent hung tasks when printing inventory on serial console

   - Make RO_DATA page aligned in vmlinux.lds.S

   - Add check for valid cache stride size"

* tag 'parisc-for-6.8-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: BTLB: Fix crash when setting up BTLB at CPU bringup
  parisc: Fix random data corruption from exception handler
  parisc: Drop unneeded semicolon in parse_tree_node()
  parisc: Prevent hung tasks when printing inventory on serial console
  parisc: Check for valid stride size for cache flushes
  parisc: Make RO_DATA page aligned in vmlinux.lds.S
parents a4126826 913b9d44
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ config PARISC
	select RTC_DRV_GENERIC
	select INIT_ALL_POSSIBLE
	select BUG
	select BUILDTIME_TABLE_SORT
	select HAVE_KERNEL_UNCOMPRESSED
	select HAVE_PCI
	select HAVE_PERF_EVENTS
+1 −0
Original line number Diff line number Diff line
@@ -576,6 +576,7 @@
	.section __ex_table,"aw"			!	\
	.align 4					!	\
	.word (fault_addr - .), (except_addr - .)	!	\
	or %r0,%r0,%r0					!	\
	.previous


+64 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PARISC_EXTABLE_H
#define __PARISC_EXTABLE_H

#include <asm/ptrace.h>
#include <linux/compiler.h>

/*
 * The exception table consists of three addresses:
 *
 * - A relative address to the instruction that is allowed to fault.
 * - A relative address at which the program should continue (fixup routine)
 * - An asm statement which specifies which CPU register will
 *   receive -EFAULT when an exception happens if the lowest bit in
 *   the fixup address is set.
 *
 * Note: The register specified in the err_opcode instruction will be
 * modified at runtime if a fault happens. Register %r0 will be ignored.
 *
 * Since relative addresses are used, 32bit values are sufficient even on
 * 64bit kernel.
 */

struct pt_regs;
int fixup_exception(struct pt_regs *regs);

#define ARCH_HAS_RELATIVE_EXTABLE
struct exception_table_entry {
	int insn;	/* relative address of insn that is allowed to fault. */
	int fixup;	/* relative address of fixup routine */
	int err_opcode; /* sample opcode with register which holds error code */
};

#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr, opcode )\
	".section __ex_table,\"aw\"\n"			   \
	".align 4\n"					   \
	".word (" #fault_addr " - .), (" #except_addr " - .)\n" \
	opcode "\n"					   \
	".previous\n"

/*
 * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry
 * (with lowest bit set) for which the fault handler in fixup_exception() will
 * load -EFAULT on fault into the register specified by the err_opcode instruction,
 * and zeroes the target register in case of a read fault in get_user().
 */
#define ASM_EXCEPTIONTABLE_VAR(__err_var)		\
	int __err_var = 0
#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr, register )\
	ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1, "or %%r0,%%r0," register)

static inline void swap_ex_entry_fixup(struct exception_table_entry *a,
				       struct exception_table_entry *b,
				       struct exception_table_entry tmp,
				       int delta)
{
	a->fixup = b->fixup + delta;
	b->fixup = tmp.fixup - delta;
	a->err_opcode = b->err_opcode;
	b->err_opcode = tmp.err_opcode;
}
#define swap_ex_entry_fixup swap_ex_entry_fixup

#endif
+4 −2
Original line number Diff line number Diff line
@@ -8,7 +8,8 @@
		"copy %%r0,%0\n"			\
		"8:\tlpa %%r0(%1),%0\n"			\
		"9:\n"					\
		ASM_EXCEPTIONTABLE_ENTRY(8b, 9b)	\
		ASM_EXCEPTIONTABLE_ENTRY(8b, 9b,	\
				"or %%r0,%%r0,%%r0")	\
		: "=&r" (pa)				\
		: "r" (va)				\
		: "memory"				\
@@ -22,7 +23,8 @@
		"copy %%r0,%0\n"			\
		"8:\tlpa %%r0(%%sr3,%1),%0\n"		\
		"9:\n"					\
		ASM_EXCEPTIONTABLE_ENTRY(8b, 9b)	\
		ASM_EXCEPTIONTABLE_ENTRY(8b, 9b,	\
				"or %%r0,%%r0,%%r0")	\
		: "=&r" (pa)				\
		: "r" (va)				\
		: "memory"				\
+7 −41
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 */
#include <asm/page.h>
#include <asm/cache.h>
#include <asm/extable.h>

#include <linux/bug.h>
#include <linux/string.h>
@@ -26,37 +27,6 @@
#define STD_USER(sr, x, ptr)	__put_user_asm(sr, "std", x, ptr)
#endif

/*
 * The exception table contains two values: the first is the relative offset to
 * the address of the instruction that is allowed to fault, and the second is
 * the relative offset to the address of the fixup routine. Since relative
 * addresses are used, 32bit values are sufficient even on 64bit kernel.
 */

#define ARCH_HAS_RELATIVE_EXTABLE
struct exception_table_entry {
	int insn;	/* relative address of insn that is allowed to fault. */
	int fixup;	/* relative address of fixup routine */
};

#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\
	".section __ex_table,\"aw\"\n"			   \
	".align 4\n"					   \
	".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \
	".previous\n"

/*
 * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry
 * (with lowest bit set) for which the fault handler in fixup_exception() will
 * load -EFAULT into %r29 for a read or write fault, and zeroes the target
 * register in case of a read fault in get_user().
 */
#define ASM_EXCEPTIONTABLE_REG	29
#define ASM_EXCEPTIONTABLE_VAR(__variable)		\
	register long __variable __asm__ ("r29") = 0
#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr )\
	ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1)

#define __get_user_internal(sr, val, ptr)		\
({							\
	ASM_EXCEPTIONTABLE_VAR(__gu_err);		\
@@ -83,7 +53,7 @@ struct exception_table_entry {
							\
	__asm__("1: " ldx " 0(%%sr%2,%3),%0\n"		\
		"9:\n"					\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)	\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1")	\
		: "=r"(__gu_val), "+r"(__gu_err)        \
		: "i"(sr), "r"(ptr));			\
							\
@@ -115,8 +85,8 @@ struct exception_table_entry {
		"1: ldw 0(%%sr%2,%3),%0\n"		\
		"2: ldw 4(%%sr%2,%3),%R0\n"		\
		"9:\n"					\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)	\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b)	\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1")	\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%1")	\
		: "=&r"(__gu_tmp.l), "+r"(__gu_err)	\
		: "i"(sr), "r"(ptr));			\
							\
@@ -174,7 +144,7 @@ struct exception_table_entry {
	__asm__ __volatile__ (					\
		"1: " stx " %1,0(%%sr%2,%3)\n"			\
		"9:\n"						\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)		\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0")	\
		: "+r"(__pu_err)				\
		: "r"(x), "i"(sr), "r"(ptr))

@@ -186,15 +156,14 @@ struct exception_table_entry {
		"1: stw %1,0(%%sr%2,%3)\n"			\
		"2: stw %R1,4(%%sr%2,%3)\n"			\
		"9:\n"						\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b)		\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b)		\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0")	\
		ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%0")	\
		: "+r"(__pu_err)				\
		: "r"(__val), "i"(sr), "r"(ptr));		\
} while (0)

#endif /* !defined(CONFIG_64BIT) */


/*
 * Complex access routines -- external declarations
 */
@@ -216,7 +185,4 @@ unsigned long __must_check raw_copy_from_user(void *dst, const void __user *src,
#define INLINE_COPY_TO_USER
#define INLINE_COPY_FROM_USER

struct pt_regs;
int fixup_exception(struct pt_regs *regs);

#endif /* __PARISC_UACCESS_H */
Loading