Browse Source

Merge branch 'parisc-4.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux

Pull parisc fixes from Helge Deller:

 - Unbreak parisc bootloader by avoiding a gcc-7 optimization to convert
   multiple byte-accesses into one word-access.

 - Add missing HWPOISON page fault handler code. I completely missed
   that when I added HWPOISON support during this merge window and it
   only showed up now with the madvise07 LTP test case.

 - Fix backtrace unwinding to stop when stack start has been reached.

 - Issue warning if initrd has been loaded into memory regions with
   broken RAM modules.

 - Fix HPMC handler (parisc hardware fault handler) to comply with
   architecture specification.

 - Avoid compiler warnings about too large frame sizes.

 - Minor init-section fixes.

* 'parisc-4.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: Unbreak bootloader due to gcc-7 optimizations
  parisc: Reintroduce option to gzip-compress the kernel
  parisc: Add HWPOISON page fault handler code
  parisc: Move init_per_cpu() into init section
  parisc: Check if initrd was loaded into broken RAM
  parisc: Add PDCE_CHECK instruction to HPMC handler
  parisc: Add wrapper for pdc_instr() firmware function
  parisc: Move start_parisc() into init section
  parisc: Stop unwinding at start of stack
  parisc: Fix too large frame size warnings
Linus Torvalds 8 years ago
parent
commit
cd4175b116

+ 12 - 0
arch/parisc/Kconfig

@@ -257,6 +257,18 @@ config PARISC_PAGE_SIZE_64KB
 
 
 endchoice
 endchoice
 
 
+config PARISC_SELF_EXTRACT
+	bool "Build kernel as self-extracting executable"
+	default y
+	help
+	  Say Y if you want to build the parisc kernel as a kind of
+	  self-extracting executable.
+
+	  If you say N here, the kernel will be compressed with gzip
+	  which can be loaded by the palo bootloader directly too.
+
+	  If you don't know what to do here, say Y.
+
 config SMP
 config SMP
 	bool "Symmetric multi-processing support"
 	bool "Symmetric multi-processing support"
 	---help---
 	---help---

+ 5 - 0
arch/parisc/Makefile

@@ -129,8 +129,13 @@ Image: vmlinux
 bzImage: vmlinux
 bzImage: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 	$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
 
 
+ifdef CONFIG_PARISC_SELF_EXTRACT
 vmlinuz: bzImage
 vmlinuz: bzImage
 	$(OBJCOPY) $(boot)/bzImage $@
 	$(OBJCOPY) $(boot)/bzImage $@
+else
+vmlinuz: vmlinux
+	@gzip -cf -9 $< > $@
+endif
 
 
 install:
 install:
 	$(CONFIG_SHELL) $(src)/arch/parisc/install.sh \
 	$(CONFIG_SHELL) $(src)/arch/parisc/install.sh \

+ 1 - 1
arch/parisc/boot/compressed/Makefile

@@ -15,7 +15,7 @@ targets += misc.o piggy.o sizes.h head.o real2.o firmware.o
 KBUILD_CFLAGS := -D__KERNEL__ -O2 -DBOOTLOADER
 KBUILD_CFLAGS := -D__KERNEL__ -O2 -DBOOTLOADER
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
 KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks
 KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks
-KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs
+KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs -Os
 ifndef CONFIG_64BIT
 ifndef CONFIG_64BIT
 KBUILD_CFLAGS += -mfast-indirect-calls
 KBUILD_CFLAGS += -mfast-indirect-calls
 endif
 endif

+ 2 - 1
arch/parisc/boot/compressed/misc.c

@@ -24,7 +24,8 @@
 /* Symbols defined by linker scripts */
 /* Symbols defined by linker scripts */
 extern char input_data[];
 extern char input_data[];
 extern int input_len;
 extern int input_len;
-extern __le32 output_len;	/* at unaligned address, little-endian */
+/* output_len is inserted by the linker possibly at an unaligned address */
+extern __le32 output_len __aligned(1);
 extern char _text, _end;
 extern char _text, _end;
 extern char _bss, _ebss;
 extern char _bss, _ebss;
 extern char _startcode_end;
 extern char _startcode_end;

+ 1 - 0
arch/parisc/include/asm/pdc.h

@@ -280,6 +280,7 @@ void setup_pdc(void);		/* in inventory.c */
 /* wrapper-functions from pdc.c */
 /* wrapper-functions from pdc.c */
 
 
 int pdc_add_valid(unsigned long address);
 int pdc_add_valid(unsigned long address);
+int pdc_instr(unsigned int *instr);
 int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
 int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
 int pdc_chassis_disp(unsigned long disp);
 int pdc_chassis_disp(unsigned long disp);
 int pdc_chassis_warn(unsigned long *warn);
 int pdc_chassis_warn(unsigned long *warn);

+ 1 - 0
arch/parisc/include/asm/smp.h

@@ -1,6 +1,7 @@
 #ifndef __ASM_SMP_H
 #ifndef __ASM_SMP_H
 #define __ASM_SMP_H
 #define __ASM_SMP_H
 
 
+extern int init_per_cpu(int cpuid);
 
 
 #if defined(CONFIG_SMP)
 #if defined(CONFIG_SMP)
 
 

+ 20 - 0
arch/parisc/kernel/firmware.c

@@ -232,6 +232,26 @@ int pdc_add_valid(unsigned long address)
 }
 }
 EXPORT_SYMBOL(pdc_add_valid);
 EXPORT_SYMBOL(pdc_add_valid);
 
 
+/**
+ * pdc_instr - Get instruction that invokes PDCE_CHECK in HPMC handler.
+ * @instr: Pointer to variable which will get instruction opcode.
+ *
+ * The return value is PDC_OK (0) in case call succeeded.
+ */
+int __init pdc_instr(unsigned int *instr)
+{
+	int retval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdc_lock, flags);
+	retval = mem_pdc_call(PDC_INSTR, 0UL, __pa(pdc_result));
+	convert_to_wide(pdc_result);
+	*instr = pdc_result[0];
+	spin_unlock_irqrestore(&pdc_lock, flags);
+
+	return retval;
+}
+
 /**
 /**
  * pdc_chassis_info - Return chassis information.
  * pdc_chassis_info - Return chassis information.
  * @result: The return buffer.
  * @result: The return buffer.

+ 9 - 0
arch/parisc/kernel/pdt.c

@@ -15,6 +15,7 @@
 #include <linux/memblock.h>
 #include <linux/memblock.h>
 #include <linux/seq_file.h>
 #include <linux/seq_file.h>
 #include <linux/kthread.h>
 #include <linux/kthread.h>
+#include <linux/initrd.h>
 
 
 #include <asm/pdc.h>
 #include <asm/pdc.h>
 #include <asm/pdcpat.h>
 #include <asm/pdcpat.h>
@@ -216,8 +217,16 @@ void __init pdc_pdt_init(void)
 	}
 	}
 
 
 	for (i = 0; i < pdt_status.pdt_entries; i++) {
 	for (i = 0; i < pdt_status.pdt_entries; i++) {
+		unsigned long addr;
+
 		report_mem_err(pdt_entry[i]);
 		report_mem_err(pdt_entry[i]);
 
 
+		addr = pdt_entry[i] & PDT_ADDR_PHYS_MASK;
+		if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) &&
+			addr >= initrd_start && addr < initrd_end)
+			pr_crit("CRITICAL: initrd possibly broken "
+				"due to bad memory!\n");
+
 		/* mark memory page bad */
 		/* mark memory page bad */
 		memblock_reserve(pdt_entry[i] & PAGE_MASK, PAGE_SIZE);
 		memblock_reserve(pdt_entry[i] & PAGE_MASK, PAGE_SIZE);
 	}
 	}

+ 1 - 1
arch/parisc/kernel/processor.c

@@ -317,7 +317,7 @@ void __init collect_boot_cpu_data(void)
  *
  *
  * o Enable CPU profiling hooks.
  * o Enable CPU profiling hooks.
  */
  */
-int init_per_cpu(int cpunum)
+int __init init_per_cpu(int cpunum)
 {
 {
 	int ret;
 	int ret;
 	struct pdc_coproc_cfg coproc_cfg;
 	struct pdc_coproc_cfg coproc_cfg;

+ 3 - 3
arch/parisc/kernel/setup.c

@@ -38,6 +38,7 @@
 #include <linux/export.h>
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/sched/clock.h>
 #include <linux/sched/clock.h>
+#include <linux/start_kernel.h>
 
 
 #include <asm/processor.h>
 #include <asm/processor.h>
 #include <asm/sections.h>
 #include <asm/sections.h>
@@ -48,6 +49,7 @@
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/setup.h>
 #include <asm/unwind.h>
 #include <asm/unwind.h>
+#include <asm/smp.h>
 
 
 static char __initdata command_line[COMMAND_LINE_SIZE];
 static char __initdata command_line[COMMAND_LINE_SIZE];
 
 
@@ -115,7 +117,6 @@ void __init dma_ops_init(void)
 }
 }
 #endif
 #endif
 
 
-extern int init_per_cpu(int cpuid);
 extern void collect_boot_cpu_data(void);
 extern void collect_boot_cpu_data(void);
 
 
 void __init setup_arch(char **cmdline_p)
 void __init setup_arch(char **cmdline_p)
@@ -398,9 +399,8 @@ static int __init parisc_init(void)
 }
 }
 arch_initcall(parisc_init);
 arch_initcall(parisc_init);
 
 
-void start_parisc(void)
+void __init start_parisc(void)
 {
 {
-	extern void start_kernel(void);
 	extern void early_trap_init(void);
 	extern void early_trap_init(void);
 
 
 	int ret, cpunum;
 	int ret, cpunum;

+ 1 - 2
arch/parisc/kernel/smp.c

@@ -255,12 +255,11 @@ void arch_send_call_function_single_ipi(int cpu)
 static void __init
 static void __init
 smp_cpu_init(int cpunum)
 smp_cpu_init(int cpunum)
 {
 {
-	extern int init_per_cpu(int);  /* arch/parisc/kernel/processor.c */
 	extern void init_IRQ(void);    /* arch/parisc/kernel/irq.c */
 	extern void init_IRQ(void);    /* arch/parisc/kernel/irq.c */
 	extern void start_cpu_itimer(void); /* arch/parisc/kernel/time.c */
 	extern void start_cpu_itimer(void); /* arch/parisc/kernel/time.c */
 
 
 	/* Set modes and Enable floating point coprocessor */
 	/* Set modes and Enable floating point coprocessor */
-	(void) init_per_cpu(cpunum);
+	init_per_cpu(cpunum);
 
 
 	disable_sr_hashing();
 	disable_sr_hashing();
 
 

+ 9 - 1
arch/parisc/kernel/traps.c

@@ -817,7 +817,7 @@ void __init initialize_ivt(const void *iva)
 	u32 check = 0;
 	u32 check = 0;
 	u32 *ivap;
 	u32 *ivap;
 	u32 *hpmcp;
 	u32 *hpmcp;
-	u32 length;
+	u32 length, instr;
 
 
 	if (strcmp((const char *)iva, "cows can fly"))
 	if (strcmp((const char *)iva, "cows can fly"))
 		panic("IVT invalid");
 		panic("IVT invalid");
@@ -827,6 +827,14 @@ void __init initialize_ivt(const void *iva)
 	for (i = 0; i < 8; i++)
 	for (i = 0; i < 8; i++)
 	    *ivap++ = 0;
 	    *ivap++ = 0;
 
 
+	/*
+	 * Use PDC_INSTR firmware function to get instruction that invokes
+	 * PDCE_CHECK in HPMC handler.  See programming note at page 1-31 of
+	 * the PA 1.1 Firmware Architecture document.
+	 */
+	if (pdc_instr(&instr) == PDC_OK)
+		ivap[0] = instr;
+
 	/* Compute Checksum for HPMC handler */
 	/* Compute Checksum for HPMC handler */
 	length = os_hpmc_size;
 	length = os_hpmc_size;
 	ivap[7] = length;
 	ivap[7] = length;

+ 12 - 0
arch/parisc/kernel/unwind.c

@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/kallsyms.h>
 #include <linux/kallsyms.h>
 #include <linux/sort.h>
 #include <linux/sort.h>
+#include <linux/sched.h>
 
 
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
 #include <asm/assembly.h>
 #include <asm/assembly.h>
@@ -279,6 +280,17 @@ static void unwind_frame_regs(struct unwind_frame_info *info)
 
 
 			info->prev_sp = sp - 64;
 			info->prev_sp = sp - 64;
 			info->prev_ip = 0;
 			info->prev_ip = 0;
+
+			/* The stack is at the end inside the thread_union
+			 * struct. If we reach data, we have reached the
+			 * beginning of the stack and should stop unwinding. */
+			if (info->prev_sp >= (unsigned long) task_thread_info(info->t) &&
+			    info->prev_sp < ((unsigned long) task_thread_info(info->t)
+						+ THREAD_SZ_ALGN)) {
+				info->prev_sp = 0;
+				break;
+			}
+
 			if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET))) 
 			if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET))) 
 				break;
 				break;
 			info->prev_ip = tmp;
 			info->prev_ip = tmp;

+ 29 - 4
arch/parisc/mm/fault.c

@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/extable.h>
 #include <linux/extable.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
+#include <linux/hugetlb.h>
 
 
 #include <asm/traps.h>
 #include <asm/traps.h>
 
 
@@ -261,7 +262,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
 	struct task_struct *tsk;
 	struct task_struct *tsk;
 	struct mm_struct *mm;
 	struct mm_struct *mm;
 	unsigned long acc_type;
 	unsigned long acc_type;
-	int fault;
+	int fault = 0;
 	unsigned int flags;
 	unsigned int flags;
 
 
 	if (faulthandler_disabled())
 	if (faulthandler_disabled())
@@ -315,7 +316,8 @@ good_area:
 			goto out_of_memory;
 			goto out_of_memory;
 		else if (fault & VM_FAULT_SIGSEGV)
 		else if (fault & VM_FAULT_SIGSEGV)
 			goto bad_area;
 			goto bad_area;
-		else if (fault & VM_FAULT_SIGBUS)
+		else if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
+				  VM_FAULT_HWPOISON_LARGE))
 			goto bad_area;
 			goto bad_area;
 		BUG();
 		BUG();
 	}
 	}
@@ -352,8 +354,7 @@ bad_area:
 
 
 	if (user_mode(regs)) {
 	if (user_mode(regs)) {
 		struct siginfo si;
 		struct siginfo si;
-
-		show_signal_msg(regs, code, address, tsk, vma);
+		unsigned int lsb = 0;
 
 
 		switch (code) {
 		switch (code) {
 		case 15:	/* Data TLB miss fault/Data page fault */
 		case 15:	/* Data TLB miss fault/Data page fault */
@@ -386,6 +387,30 @@ bad_area:
 			si.si_code = (code == 26) ? SEGV_ACCERR : SEGV_MAPERR;
 			si.si_code = (code == 26) ? SEGV_ACCERR : SEGV_MAPERR;
 			break;
 			break;
 		}
 		}
+
+#ifdef CONFIG_MEMORY_FAILURE
+		if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
+			printk(KERN_ERR
+	"MCE: Killing %s:%d due to hardware memory corruption fault at %08lx\n",
+			tsk->comm, tsk->pid, address);
+			si.si_signo = SIGBUS;
+			si.si_code = BUS_MCEERR_AR;
+		}
+#endif
+
+		/*
+		 * Either small page or large page may be poisoned.
+		 * In other words, VM_FAULT_HWPOISON_LARGE and
+		 * VM_FAULT_HWPOISON are mutually exclusive.
+		 */
+		if (fault & VM_FAULT_HWPOISON_LARGE)
+			lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
+		else if (fault & VM_FAULT_HWPOISON)
+			lsb = PAGE_SHIFT;
+		else
+			show_signal_msg(regs, code, address, tsk, vma);
+		si.si_addr_lsb = lsb;
+
 		si.si_errno = 0;
 		si.si_errno = 0;
 		si.si_addr = (void __user *) address;
 		si.si_addr = (void __user *) address;
 		force_sig_info(si.si_signo, &si, current);
 		force_sig_info(si.si_signo, &si, current);

+ 2 - 1
lib/Kconfig.debug

@@ -219,7 +219,8 @@ config FRAME_WARN
 	range 0 8192
 	range 0 8192
 	default 0 if KASAN
 	default 0 if KASAN
 	default 2048 if GCC_PLUGIN_LATENT_ENTROPY
 	default 2048 if GCC_PLUGIN_LATENT_ENTROPY
-	default 1024 if !64BIT
+	default 1280 if (!64BIT && PARISC)
+	default 1024 if (!64BIT && !PARISC)
 	default 2048 if 64BIT
 	default 2048 if 64BIT
 	help
 	help
 	  Tell gcc to warn at build time for stack frames larger than this.
 	  Tell gcc to warn at build time for stack frames larger than this.