diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-04 14:05:52 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-04 14:05:52 -0700 |
commit | e46cae441824999c858d482ca1f661cf4292c02f (patch) | |
tree | 0bf4dabec0ef16f92723ff0fac0e837f59b48cdc /arch/s390/kernel | |
parent | 02bafd96f3a5d8e610b19033ffec55b92459aaae (diff) | |
parent | 6cd997db911f28f2510b771691270c52b63ed2e6 (diff) | |
download | linux-stable-e46cae441824999c858d482ca1f661cf4292c02f.tar.gz linux-stable-e46cae441824999c858d482ca1f661cf4292c02f.tar.bz2 linux-stable-e46cae441824999c858d482ca1f661cf4292c02f.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky:
"The new features and main improvements in this merge for v4.9
- Support for the UBSAN sanitizer
- Set HAVE_EFFICIENT_UNALIGNED_ACCESS, it improves the code in some
places
- Improvements for the in-kernel fpu code, in particular the overhead
for multiple consecutive in kernel fpu users is recuded
- Add a SIMD implementation for the RAID6 gen and xor operations
- Add RAID6 recovery based on the XC instruction
- The PCI DMA flush logic has been improved to increase the speed of
the map / unmap operations
- The time synchronization code has seen some updates
And bug fixes all over the place"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (48 commits)
s390/con3270: fix insufficient space padding
s390/con3270: fix use of uninitialised data
MAINTAINERS: update DASD maintainer
s390/cio: fix accidental interrupt enabling during resume
s390/dasd: add missing \n to end of dev_err messages
s390/config: Enable config options for Docker
s390/dasd: make query host access interruptible
s390/dasd: fix panic during offline processing
s390/dasd: fix hanging offline processing
s390/pci_dma: improve lazy flush for unmap
s390/pci_dma: split dma_update_trans
s390/pci_dma: improve map_sg
s390/pci_dma: simplify dma address calculation
s390/pci_dma: remove dma address range check
iommu/s390: simplify registration of I/O address translation parameters
s390: migrate exception table users off module.h and onto extable.h
s390: export header for CLP ioctl
s390/vmur: fix irq pointer dereference in int handler
s390/dasd: add missing KOBJ_CHANGE event for unformatted devices
s390: enable UBSAN
...
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/s390/kernel/crash_dump.c | 4 | ||||
-rw-r--r-- | arch/s390/kernel/early.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/fpu.c | 317 | ||||
-rw-r--r-- | arch/s390/kernel/kprobes.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/nmi.c | 67 | ||||
-rw-r--r-- | arch/s390/kernel/sysinfo.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/time.c | 86 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 3 | ||||
-rw-r--r-- | arch/s390/kernel/vdso32/Makefile | 3 | ||||
-rw-r--r-- | arch/s390/kernel/vdso64/Makefile | 3 |
11 files changed, 189 insertions, 303 deletions
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 3234817c7d47..72ccc41444dc 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -48,6 +48,9 @@ AFLAGS_head.o += -march=z900 endif GCOV_PROFILE_sclp.o := n GCOV_PROFILE_als.o := n +UBSAN_SANITIZE_als.o := n +UBSAN_SANITIZE_early.o := n +UBSAN_SANITIZE_sclp.o := n obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index 29df8484282b..f9293bfefb7f 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -71,9 +71,7 @@ struct save_area * __init save_area_alloc(bool is_boot_cpu) */ struct save_area * __init save_area_boot_cpu(void) { - if (list_empty(&dump_save_areas)) - return NULL; - return list_first_entry(&dump_save_areas, struct save_area, list); + return list_first_entry_or_null(&dump_save_areas, struct save_area, list); } /* diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 717b03aa16b5..2374c5b46bbc 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -13,7 +13,7 @@ #include <linux/string.h> #include <linux/ctype.h> #include <linux/lockdep.h> -#include <linux/module.h> +#include <linux/extable.h> #include <linux/pfn.h> #include <linux/uaccess.h> #include <linux/kernel.h> diff --git a/arch/s390/kernel/fpu.c b/arch/s390/kernel/fpu.c index 81d1d1887507..1235b9438df4 100644 --- a/arch/s390/kernel/fpu.c +++ b/arch/s390/kernel/fpu.c @@ -10,240 +10,167 @@ #include <asm/fpu/types.h> #include <asm/fpu/api.h> -/* - * Per-CPU variable to maintain FPU register ranges that are in use - * by the kernel. - */ -static DEFINE_PER_CPU(u32, kernel_fpu_state); - -#define KERNEL_FPU_STATE_MASK (KERNEL_FPU_MASK|KERNEL_FPC) - +asm(".include \"asm/vx-insn.h\"\n"); void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags) { - if (!__this_cpu_read(kernel_fpu_state)) { - /* - * Save user space FPU state and register contents. Multiple - * calls because of interruptions do not matter and return - * immediately. This also sets CIF_FPU to lazy restore FP/VX - * register contents when returning to user space. - */ - save_fpu_regs(); - } - - /* Update flags to use the vector facility for KERNEL_FPR */ - if (MACHINE_HAS_VX && (state->mask & KERNEL_FPR)) { - flags |= KERNEL_VXR_LOW | KERNEL_FPC; - flags &= ~KERNEL_FPR; - } - - /* Save and update current kernel VX state */ - state->mask = __this_cpu_read(kernel_fpu_state); - __this_cpu_or(kernel_fpu_state, flags & KERNEL_FPU_STATE_MASK); - /* - * If this is the first call to __kernel_fpu_begin(), no additional - * work is required. + * Limit the save to the FPU/vector registers already + * in use by the previous context */ - if (!(state->mask & KERNEL_FPU_STATE_MASK)) - return; + flags &= state->mask; - /* - * If KERNEL_FPR is still set, the vector facility is not available - * and, thus, save floating-point control and registers only. - */ - if (state->mask & KERNEL_FPR) { - asm volatile("stfpc %0" : "=Q" (state->fpc)); - asm volatile("std 0,%0" : "=Q" (state->fprs[0])); - asm volatile("std 1,%0" : "=Q" (state->fprs[1])); - asm volatile("std 2,%0" : "=Q" (state->fprs[2])); - asm volatile("std 3,%0" : "=Q" (state->fprs[3])); - asm volatile("std 4,%0" : "=Q" (state->fprs[4])); - asm volatile("std 5,%0" : "=Q" (state->fprs[5])); - asm volatile("std 6,%0" : "=Q" (state->fprs[6])); - asm volatile("std 7,%0" : "=Q" (state->fprs[7])); - asm volatile("std 8,%0" : "=Q" (state->fprs[8])); - asm volatile("std 9,%0" : "=Q" (state->fprs[9])); - asm volatile("std 10,%0" : "=Q" (state->fprs[10])); - asm volatile("std 11,%0" : "=Q" (state->fprs[11])); - asm volatile("std 12,%0" : "=Q" (state->fprs[12])); - asm volatile("std 13,%0" : "=Q" (state->fprs[13])); - asm volatile("std 14,%0" : "=Q" (state->fprs[14])); - asm volatile("std 15,%0" : "=Q" (state->fprs[15])); + if (flags & KERNEL_FPC) + /* Save floating point control */ + asm volatile("stfpc %0" : "=m" (state->fpc)); + + if (!MACHINE_HAS_VX) { + if (flags & KERNEL_VXR_V0V7) { + /* Save floating-point registers */ + asm volatile("std 0,%0" : "=Q" (state->fprs[0])); + asm volatile("std 1,%0" : "=Q" (state->fprs[1])); + asm volatile("std 2,%0" : "=Q" (state->fprs[2])); + asm volatile("std 3,%0" : "=Q" (state->fprs[3])); + asm volatile("std 4,%0" : "=Q" (state->fprs[4])); + asm volatile("std 5,%0" : "=Q" (state->fprs[5])); + asm volatile("std 6,%0" : "=Q" (state->fprs[6])); + asm volatile("std 7,%0" : "=Q" (state->fprs[7])); + asm volatile("std 8,%0" : "=Q" (state->fprs[8])); + asm volatile("std 9,%0" : "=Q" (state->fprs[9])); + asm volatile("std 10,%0" : "=Q" (state->fprs[10])); + asm volatile("std 11,%0" : "=Q" (state->fprs[11])); + asm volatile("std 12,%0" : "=Q" (state->fprs[12])); + asm volatile("std 13,%0" : "=Q" (state->fprs[13])); + asm volatile("std 14,%0" : "=Q" (state->fprs[14])); + asm volatile("std 15,%0" : "=Q" (state->fprs[15])); + } return; } - /* - * If this is a nested call to __kernel_fpu_begin(), check the saved - * state mask to save and later restore the vector registers that - * are already in use. Let's start with checking floating-point - * controls. - */ - if (state->mask & KERNEL_FPC) - asm volatile("stfpc %0" : "=m" (state->fpc)); - /* Test and save vector registers */ asm volatile ( /* * Test if any vector register must be saved and, if so, * test if all register can be saved. */ - " tmll %[m],15\n" /* KERNEL_VXR_MASK */ - " jz 20f\n" /* no work -> done */ " la 1,%[vxrs]\n" /* load save area */ - " jo 18f\n" /* -> save V0..V31 */ - + " tmll %[m],30\n" /* KERNEL_VXR */ + " jz 7f\n" /* no work -> done */ + " jo 5f\n" /* -> save V0..V31 */ /* - * Test if V8..V23 can be saved at once... this speeds up - * for KERNEL_fpu_MID only. Otherwise continue to split the - * range of vector registers into two halves and test them - * separately. + * Test for special case KERNEL_FPU_MID only. In this + * case a vstm V8..V23 is the best instruction */ - " tmll %[m],6\n" /* KERNEL_VXR_MID */ - " jo 17f\n" /* -> save V8..V23 */ - + " chi %[m],12\n" /* KERNEL_VXR_MID */ + " jne 0f\n" /* -> save V8..V23 */ + " VSTM 8,23,128,1\n" /* vstm %v8,%v23,128(%r1) */ + " j 7f\n" /* Test and save the first half of 16 vector registers */ - "1: tmll %[m],3\n" /* KERNEL_VXR_LOW */ - " jz 10f\n" /* -> KERNEL_VXR_HIGH */ + "0: tmll %[m],6\n" /* KERNEL_VXR_LOW */ + " jz 3f\n" /* -> KERNEL_VXR_HIGH */ " jo 2f\n" /* 11 -> save V0..V15 */ - " brc 4,3f\n" /* 01 -> save V0..V7 */ - " brc 2,4f\n" /* 10 -> save V8..V15 */ - + " brc 2,1f\n" /* 10 -> save V8..V15 */ + " VSTM 0,7,0,1\n" /* vstm %v0,%v7,0(%r1) */ + " j 3f\n" + "1: VSTM 8,15,128,1\n" /* vstm %v8,%v15,128(%r1) */ + " j 3f\n" + "2: VSTM 0,15,0,1\n" /* vstm %v0,%v15,0(%r1) */ /* Test and save the second half of 16 vector registers */ - "10: tmll %[m],12\n" /* KERNEL_VXR_HIGH */ - " jo 19f\n" /* 11 -> save V16..V31 */ - " brc 4,11f\n" /* 01 -> save V16..V23 */ - " brc 2,12f\n" /* 10 -> save V24..V31 */ - " j 20f\n" /* 00 -> done */ - - /* - * Below are the vstm combinations to save multiple vector - * registers at once. - */ - "2: .word 0xe70f,0x1000,0x003e\n" /* vstm 0,15,0(1) */ - " j 10b\n" /* -> VXR_HIGH */ - "3: .word 0xe707,0x1000,0x003e\n" /* vstm 0,7,0(1) */ - " j 10b\n" /* -> VXR_HIGH */ - "4: .word 0xe78f,0x1080,0x003e\n" /* vstm 8,15,128(1) */ - " j 10b\n" /* -> VXR_HIGH */ - "\n" - "11: .word 0xe707,0x1100,0x0c3e\n" /* vstm 16,23,256(1) */ - " j 20f\n" /* -> done */ - "12: .word 0xe78f,0x1180,0x0c3e\n" /* vstm 24,31,384(1) */ - " j 20f\n" /* -> done */ - "\n" - "17: .word 0xe787,0x1080,0x043e\n" /* vstm 8,23,128(1) */ - " nill %[m],249\n" /* m &= ~VXR_MID */ - " j 1b\n" /* -> VXR_LOW */ - "\n" - "18: .word 0xe70f,0x1000,0x003e\n" /* vstm 0,15,0(1) */ - "19: .word 0xe70f,0x1100,0x0c3e\n" /* vstm 16,31,256(1) */ - "20:" + "3: tmll %[m],24\n" /* KERNEL_VXR_HIGH */ + " jz 7f\n" + " jo 6f\n" /* 11 -> save V16..V31 */ + " brc 2,4f\n" /* 10 -> save V24..V31 */ + " VSTM 16,23,256,1\n" /* vstm %v16,%v23,256(%r1) */ + " j 7f\n" + "4: VSTM 24,31,384,1\n" /* vstm %v24,%v31,384(%r1) */ + " j 7f\n" + "5: VSTM 0,15,0,1\n" /* vstm %v0,%v15,0(%r1) */ + "6: VSTM 16,31,256,1\n" /* vstm %v16,%v31,256(%r1) */ + "7:" : [vxrs] "=Q" (*(struct vx_array *) &state->vxrs) - : [m] "d" (state->mask) + : [m] "d" (flags) : "1", "cc"); } EXPORT_SYMBOL(__kernel_fpu_begin); -void __kernel_fpu_end(struct kernel_fpu *state) +void __kernel_fpu_end(struct kernel_fpu *state, u32 flags) { - /* Just update the per-CPU state if there is nothing to restore */ - if (!(state->mask & KERNEL_FPU_STATE_MASK)) - goto update_fpu_state; - /* - * If KERNEL_FPR is specified, the vector facility is not available - * and, thus, restore floating-point control and registers only. + * Limit the restore to the FPU/vector registers of the + * previous context that have been overwritte by the + * current context */ - if (state->mask & KERNEL_FPR) { - asm volatile("lfpc %0" : : "Q" (state->fpc)); - asm volatile("ld 0,%0" : : "Q" (state->fprs[0])); - asm volatile("ld 1,%0" : : "Q" (state->fprs[1])); - asm volatile("ld 2,%0" : : "Q" (state->fprs[2])); - asm volatile("ld 3,%0" : : "Q" (state->fprs[3])); - asm volatile("ld 4,%0" : : "Q" (state->fprs[4])); - asm volatile("ld 5,%0" : : "Q" (state->fprs[5])); - asm volatile("ld 6,%0" : : "Q" (state->fprs[6])); - asm volatile("ld 7,%0" : : "Q" (state->fprs[7])); - asm volatile("ld 8,%0" : : "Q" (state->fprs[8])); - asm volatile("ld 9,%0" : : "Q" (state->fprs[9])); - asm volatile("ld 10,%0" : : "Q" (state->fprs[10])); - asm volatile("ld 11,%0" : : "Q" (state->fprs[11])); - asm volatile("ld 12,%0" : : "Q" (state->fprs[12])); - asm volatile("ld 13,%0" : : "Q" (state->fprs[13])); - asm volatile("ld 14,%0" : : "Q" (state->fprs[14])); - asm volatile("ld 15,%0" : : "Q" (state->fprs[15])); - goto update_fpu_state; - } + flags &= state->mask; - /* Test and restore floating-point controls */ - if (state->mask & KERNEL_FPC) + if (flags & KERNEL_FPC) + /* Restore floating-point controls */ asm volatile("lfpc %0" : : "Q" (state->fpc)); + if (!MACHINE_HAS_VX) { + if (flags & KERNEL_VXR_V0V7) { + /* Restore floating-point registers */ + asm volatile("ld 0,%0" : : "Q" (state->fprs[0])); + asm volatile("ld 1,%0" : : "Q" (state->fprs[1])); + asm volatile("ld 2,%0" : : "Q" (state->fprs[2])); + asm volatile("ld 3,%0" : : "Q" (state->fprs[3])); + asm volatile("ld 4,%0" : : "Q" (state->fprs[4])); + asm volatile("ld 5,%0" : : "Q" (state->fprs[5])); + asm volatile("ld 6,%0" : : "Q" (state->fprs[6])); + asm volatile("ld 7,%0" : : "Q" (state->fprs[7])); + asm volatile("ld 8,%0" : : "Q" (state->fprs[8])); + asm volatile("ld 9,%0" : : "Q" (state->fprs[9])); + asm volatile("ld 10,%0" : : "Q" (state->fprs[10])); + asm volatile("ld 11,%0" : : "Q" (state->fprs[11])); + asm volatile("ld 12,%0" : : "Q" (state->fprs[12])); + asm volatile("ld 13,%0" : : "Q" (state->fprs[13])); + asm volatile("ld 14,%0" : : "Q" (state->fprs[14])); + asm volatile("ld 15,%0" : : "Q" (state->fprs[15])); + } + return; + } + /* Test and restore (load) vector registers */ asm volatile ( /* - * Test if any vector registers must be loaded and, if so, + * Test if any vector register must be loaded and, if so, * test if all registers can be loaded at once. */ - " tmll %[m],15\n" /* KERNEL_VXR_MASK */ - " jz 20f\n" /* no work -> done */ - " la 1,%[vxrs]\n" /* load load area */ - " jo 18f\n" /* -> load V0..V31 */ - - /* - * Test if V8..V23 can be restored at once... this speeds up - * for KERNEL_VXR_MID only. Otherwise continue to split the - * range of vector registers into two halves and test them - * separately. - */ - " tmll %[m],6\n" /* KERNEL_VXR_MID */ - " jo 17f\n" /* -> load V8..V23 */ - - /* Test and load the first half of 16 vector registers */ - "1: tmll %[m],3\n" /* KERNEL_VXR_LOW */ - " jz 10f\n" /* -> KERNEL_VXR_HIGH */ - " jo 2f\n" /* 11 -> load V0..V15 */ - " brc 4,3f\n" /* 01 -> load V0..V7 */ - " brc 2,4f\n" /* 10 -> load V8..V15 */ - - /* Test and load the second half of 16 vector registers */ - "10: tmll %[m],12\n" /* KERNEL_VXR_HIGH */ - " jo 19f\n" /* 11 -> load V16..V31 */ - " brc 4,11f\n" /* 01 -> load V16..V23 */ - " brc 2,12f\n" /* 10 -> load V24..V31 */ - " j 20f\n" /* 00 -> done */ - + " la 1,%[vxrs]\n" /* load restore area */ + " tmll %[m],30\n" /* KERNEL_VXR */ + " jz 7f\n" /* no work -> done */ + " jo 5f\n" /* -> restore V0..V31 */ /* - * Below are the vstm combinations to load multiple vector - * registers at once. + * Test for special case KERNEL_FPU_MID only. In this + * case a vlm V8..V23 is the best instruction */ - "2: .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */ - " j 10b\n" /* -> VXR_HIGH */ - "3: .word 0xe707,0x1000,0x0036\n" /* vlm 0,7,0(1) */ - " j 10b\n" /* -> VXR_HIGH */ - "4: .word 0xe78f,0x1080,0x0036\n" /* vlm 8,15,128(1) */ - " j 10b\n" /* -> VXR_HIGH */ - "\n" - "11: .word 0xe707,0x1100,0x0c36\n" /* vlm 16,23,256(1) */ - " j 20f\n" /* -> done */ - "12: .word 0xe78f,0x1180,0x0c36\n" /* vlm 24,31,384(1) */ - " j 20f\n" /* -> done */ - "\n" - "17: .word 0xe787,0x1080,0x0436\n" /* vlm 8,23,128(1) */ - " nill %[m],249\n" /* m &= ~VXR_MID */ - " j 1b\n" /* -> VXR_LOW */ - "\n" - "18: .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */ - "19: .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */ - "20:" - : - : [vxrs] "Q" (*(struct vx_array *) &state->vxrs), - [m] "d" (state->mask) + " chi %[m],12\n" /* KERNEL_VXR_MID */ + " jne 0f\n" /* -> restore V8..V23 */ + " VLM 8,23,128,1\n" /* vlm %v8,%v23,128(%r1) */ + " j 7f\n" + /* Test and restore the first half of 16 vector registers */ + "0: tmll %[m],6\n" /* KERNEL_VXR_LOW */ + " jz 3f\n" /* -> KERNEL_VXR_HIGH */ + " jo 2f\n" /* 11 -> restore V0..V15 */ + " brc 2,1f\n" /* 10 -> restore V8..V15 */ + " VLM 0,7,0,1\n" /* vlm %v0,%v7,0(%r1) */ + " j 3f\n" + "1: VLM 8,15,128,1\n" /* vlm %v8,%v15,128(%r1) */ + " j 3f\n" + "2: VLM 0,15,0,1\n" /* vlm %v0,%v15,0(%r1) */ + /* Test and restore the second half of 16 vector registers */ + "3: tmll %[m],24\n" /* KERNEL_VXR_HIGH */ + " jz 7f\n" + " jo 6f\n" /* 11 -> restore V16..V31 */ + " brc 2,4f\n" /* 10 -> restore V24..V31 */ + " VLM 16,23,256,1\n" /* vlm %v16,%v23,256(%r1) */ + " j 7f\n" + "4: VLM 24,31,384,1\n" /* vlm %v24,%v31,384(%r1) */ + " j 7f\n" + "5: VLM 0,15,0,1\n" /* vlm %v0,%v15,0(%r1) */ + "6: VLM 16,31,256,1\n" /* vlm %v16,%v31,256(%r1) */ + "7:" + : [vxrs] "=Q" (*(struct vx_array *) &state->vxrs) + : [m] "d" (flags) : "1", "cc"); - -update_fpu_state: - /* Update current kernel VX state */ - __this_cpu_write(kernel_fpu_state, state->mask); } EXPORT_SYMBOL(__kernel_fpu_end); diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index dd6306c51bd6..fdb40424acfe 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -26,12 +26,14 @@ #include <linux/stop_machine.h> #include <linux/kdebug.h> #include <linux/uaccess.h> +#include <linux/extable.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/hardirq.h> #include <linux/ftrace.h> #include <asm/cacheflush.h> #include <asm/sections.h> +#include <asm/uaccess.h> #include <asm/dis.h> DEFINE_PER_CPU(struct kprobe *, current_kprobe); diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 29376f0e725c..9a32f7419d78 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(s390_handle_mcck); * returns 0 if all registers could be validated * returns 1 otherwise */ -static int notrace s390_validate_registers(union mci mci) +static int notrace s390_validate_registers(union mci mci, int umode) { int kill_task; u64 zero; @@ -110,26 +110,41 @@ static int notrace s390_validate_registers(union mci mci) if (!mci.gr) { /* * General purpose registers couldn't be restored and have - * unknown contents. Process needs to be terminated. + * unknown contents. Stop system or terminate process. */ + if (!umode) + s390_handle_damage(); kill_task = 1; } if (!mci.fp) { /* - * Floating point registers can't be restored and - * therefore the process needs to be terminated. + * Floating point registers can't be restored. If the + * kernel currently uses floating point registers the + * system is stopped. If the process has its floating + * pointer registers loaded it is terminated. + * Otherwise just revalidate the registers. */ - kill_task = 1; + if (S390_lowcore.fpu_flags & KERNEL_VXR_V0V7) + s390_handle_damage(); + if (!test_cpu_flag(CIF_FPU)) + kill_task = 1; } fpt_save_area = &S390_lowcore.floating_pt_save_area; fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area; if (!mci.fc) { /* * Floating point control register can't be restored. - * Task will be terminated. + * If the kernel currently uses the floating pointer + * registers and needs the FPC register the system is + * stopped. If the process has its floating pointer + * registers loaded it is terminated. Otherwiese the + * FPC is just revalidated. */ + if (S390_lowcore.fpu_flags & KERNEL_FPC) + s390_handle_damage(); asm volatile("lfpc 0(%0)" : : "a" (&zero), "m" (zero)); - kill_task = 1; + if (!test_cpu_flag(CIF_FPU)) + kill_task = 1; } else asm volatile("lfpc 0(%0)" : : "a" (fpt_creg_save_area)); @@ -159,10 +174,16 @@ static int notrace s390_validate_registers(union mci mci) if (!mci.vr) { /* - * Vector registers can't be restored and therefore - * the process needs to be terminated. + * Vector registers can't be restored. If the kernel + * currently uses vector registers the system is + * stopped. If the process has its vector registers + * loaded it is terminated. Otherwise just revalidate + * the registers. */ - kill_task = 1; + if (S390_lowcore.fpu_flags & KERNEL_VXR) + s390_handle_damage(); + if (!test_cpu_flag(CIF_FPU)) + kill_task = 1; } cr0.val = S390_lowcore.cregs_save_area[0]; cr0.afp = cr0.vx = 1; @@ -250,13 +271,11 @@ void notrace s390_do_machine_check(struct pt_regs *regs) struct mcck_struct *mcck; unsigned long long tmp; union mci mci; - int umode; nmi_enter(); inc_irq_stat(NMI_NMI); mci.val = S390_lowcore.mcck_interruption_code; mcck = this_cpu_ptr(&cpu_mcck); - umode = user_mode(regs); if (mci.sd) { /* System damage -> stopping machine */ @@ -297,22 +316,14 @@ void notrace s390_do_machine_check(struct pt_regs *regs) s390_handle_damage(); } } - if (s390_validate_registers(mci)) { - if (umode) { - /* - * Couldn't restore all register contents while in - * user mode -> mark task for termination. - */ - mcck->kill_task = 1; - mcck->mcck_code = mci.val; - set_cpu_flag(CIF_MCCK_PENDING); - } else { - /* - * Couldn't restore all register contents while in - * kernel mode -> stopping machine. - */ - s390_handle_damage(); - } + if (s390_validate_registers(mci, user_mode(regs))) { + /* + * Couldn't restore all register contents for the + * user space process -> mark task for termination. + */ + mcck->kill_task = 1; + mcck->mcck_code = mci.val; + set_cpu_flag(CIF_MCCK_PENDING); } if (mci.cd) { /* Timing facility damage */ diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index 050b8d067d3b..bfda6aa40280 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c @@ -454,7 +454,7 @@ void s390_adjust_jiffies(void) : "Q" (info->capability), "d" (10000000), "d" (0) : "cc" ); - kernel_fpu_end(&fpu); + kernel_fpu_end(&fpu, KERNEL_FPR); } else /* * Really old machine without stsi block for basic diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 4e9949800562..0bfcc492987e 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -50,10 +50,6 @@ #include <asm/cio.h> #include "entry.h" -/* change this if you have some constant time drift */ -#define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) -#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) - u64 sched_clock_base_cc = -1; /* Force to data section. */ EXPORT_SYMBOL_GPL(sched_clock_base_cc); @@ -282,13 +278,8 @@ extern struct timezone sys_tz; void update_vsyscall_tz(void) { - /* Make userspace gettimeofday spin until we're done. */ - ++vdso_data->tb_update_count; - smp_wmb(); vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; vdso_data->tz_dsttime = sys_tz.tz_dsttime; - smp_wmb(); - ++vdso_data->tb_update_count; } /* @@ -318,51 +309,12 @@ void __init time_init(void) vtime_init(); } -/* - * The time is "clock". old is what we think the time is. - * Adjust the value by a multiple of jiffies and add the delta to ntp. - * "delay" is an approximation how long the synchronization took. If - * the time correction is positive, then "delay" is subtracted from - * the time difference and only the remaining part is passed to ntp. - */ -static unsigned long long adjust_time(unsigned long long old, - unsigned long long clock, - unsigned long long delay) -{ - unsigned long long delta, ticks; - struct timex adjust; - - if (clock > old) { - /* It is later than we thought. */ - delta = ticks = clock - old; - delta = ticks = (delta < delay) ? 0 : delta - delay; - delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); - adjust.offset = ticks * (1000000 / HZ); - } else { - /* It is earlier than we thought. */ - delta = ticks = old - clock; - delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); - delta = -delta; - adjust.offset = -ticks * (1000000 / HZ); - } - sched_clock_base_cc += delta; - if (adjust.offset != 0) { - pr_notice("The ETR interface has adjusted the clock " - "by %li microseconds\n", adjust.offset); - adjust.modes = ADJ_OFFSET_SINGLESHOT; - do_adjtimex(&adjust); - } - return delta; -} - static DEFINE_PER_CPU(atomic_t, clock_sync_word); static DEFINE_MUTEX(clock_sync_mutex); static unsigned long clock_sync_flags; -#define CLOCK_SYNC_HAS_ETR 0 -#define CLOCK_SYNC_HAS_STP 1 -#define CLOCK_SYNC_ETR 2 -#define CLOCK_SYNC_STP 3 +#define CLOCK_SYNC_HAS_STP 0 +#define CLOCK_SYNC_STP 1 /* * The get_clock function for the physical clock. It will get the current @@ -384,34 +336,32 @@ int get_phys_clock(unsigned long long *clock) if (sw0 == sw1 && (sw0 & 0x80000000U)) /* Success: time is in sync. */ return 0; - if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags) && - !test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) + if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) return -EOPNOTSUPP; - if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags) && - !test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) + if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) return -EACCES; return -EAGAIN; } EXPORT_SYMBOL(get_phys_clock); /* - * Make get_sync_clock return -EAGAIN. + * Make get_phys_clock() return -EAGAIN. */ static void disable_sync_clock(void *dummy) { atomic_t *sw_ptr = this_cpu_ptr(&clock_sync_word); /* - * Clear the in-sync bit 2^31. All get_sync_clock calls will + * Clear the in-sync bit 2^31. All get_phys_clock calls will * fail until the sync bit is turned back on. In addition * increase the "sequence" counter to avoid the race of an - * etr event and the complete recovery against get_sync_clock. + * stp event and the complete recovery against get_phys_clock. */ atomic_andnot(0x80000000, sw_ptr); atomic_inc(sw_ptr); } /* - * Make get_sync_clock return 0 again. + * Make get_phys_clock() return 0 again. * Needs to be called from a context disabled for preemption. */ static void enable_sync_clock(void) @@ -434,7 +384,7 @@ static inline int check_sync_clock(void) return rc; } -/* Single threaded workqueue used for etr and stp sync events */ +/* Single threaded workqueue used for stp sync events */ static struct workqueue_struct *time_sync_wq; static void __init time_init_wq(void) @@ -448,20 +398,12 @@ struct clock_sync_data { atomic_t cpus; int in_sync; unsigned long long fixup_cc; - int etr_port; - struct etr_aib *etr_aib; }; static void clock_sync_cpu(struct clock_sync_data *sync) { atomic_dec(&sync->cpus); enable_sync_clock(); - /* - * This looks like a busy wait loop but it isn't. etr_sync_cpus - * is called on all other cpus while the TOD clocks is stopped. - * __udelay will stop the cpu on an enabled wait psw until the - * TOD is running again. - */ while (sync->in_sync == 0) { __udelay(1); /* @@ -582,7 +524,7 @@ void stp_queue_work(void) static int stp_sync_clock(void *data) { static int first; - unsigned long long old_clock, delta, new_clock, clock_delta; + unsigned long long clock_delta; struct clock_sync_data *stp_sync; struct ptff_qto qto; int rc; @@ -605,18 +547,18 @@ static int stp_sync_clock(void *data) if (stp_info.todoff[0] || stp_info.todoff[1] || stp_info.todoff[2] || stp_info.todoff[3] || stp_info.tmd != 2) { - old_clock = get_tod_clock(); rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0, &clock_delta); if (rc == 0) { - new_clock = old_clock + clock_delta; - delta = adjust_time(old_clock, new_clock, 0); + /* fixup the monotonic sched clock */ + sched_clock_base_cc += clock_delta; if (ptff_query(PTFF_QTO) && ptff(&qto, sizeof(qto), PTFF_QTO) == 0) /* Update LPAR offset */ lpar_offset = qto.tod_epoch_difference; atomic_notifier_call_chain(&s390_epoch_delta_notifier, 0, &clock_delta); - fixup_clock_comparator(delta); + stp_sync->fixup_cc = clock_delta; + fixup_clock_comparator(clock_delta); rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); if (rc == 0 && stp_info.tmd != 2) diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index dd97a3e8a34a..d0539f76fd24 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -14,11 +14,12 @@ */ #include <linux/kprobes.h> #include <linux/kdebug.h> -#include <linux/module.h> +#include <linux/extable.h> #include <linux/ptrace.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/slab.h> +#include <asm/uaccess.h> #include <asm/fpu/api.h> #include "entry.h" diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile index 68145456fee2..6cc947896c77 100644 --- a/arch/s390/kernel/vdso32/Makefile +++ b/arch/s390/kernel/vdso32/Makefile @@ -24,8 +24,9 @@ obj-y += vdso32_wrapper.o extra-y += vdso32.lds CPPFLAGS_vdso32.lds += -P -C -U$(ARCH) -# Disable gcov profiling for VDSO code +# Disable gcov profiling and ubsan for VDSO code GCOV_PROFILE := n +UBSAN_SANITIZE := n # Force dependency (incbin is bad) $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile index 0b0fd22c869a..2d54c18089eb 100644 --- a/arch/s390/kernel/vdso64/Makefile +++ b/arch/s390/kernel/vdso64/Makefile @@ -24,8 +24,9 @@ obj-y += vdso64_wrapper.o extra-y += vdso64.lds CPPFLAGS_vdso64.lds += -P -C -U$(ARCH) -# Disable gcov profiling for VDSO code +# Disable gcov profiling and ubsan for VDSO code GCOV_PROFILE := n +UBSAN_SANITIZE := n # Force dependency (incbin is bad) $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so |