aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2016-01-26 08:10:34 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2017-03-22 03:14:25 -0400
commit916cda1aa1b412d7cf2991c3af7479544942d121 (patch)
tree51e373acacf962c1635899f1567484be0baed745
parent093b995e3b55a0ae0670226ddfcb05bfbf0099ae (diff)
s390: add a system call for guarded storage
This adds a new system call to enable the use of guarded storage for user space processes. The system call takes two arguments, a command and pointer to a guarded storage control block: s390_guarded_storage(int command, struct gs_cb *gs_cb); The second argument is relevant only for the GS_SET_BC_CB command. The commands in detail: 0 - GS_ENABLE Enable the guarded storage facility for the current task. The initial content of the guarded storage control block will be all zeros. After the enablement the user space code can use load-guarded-storage-controls instruction (LGSC) to load an arbitrary control block. While a task is enabled the kernel will save and restore the current content of the guarded storage registers on context switch. 1 - GS_DISABLE Disables the use of the guarded storage facility for the current task. The kernel will cease to save and restore the content of the guarded storage registers, the task specific content of these registers is lost. 2 - GS_SET_BC_CB Set a broadcast guarded storage control block. This is called per thread and stores a specific guarded storage control block in the task struct of the current task. This control block will be used for the broadcast event GS_BROADCAST. 3 - GS_CLEAR_BC_CB Clears the broadcast guarded storage control block. The guarded- storage control block is removed from the task struct that was established by GS_SET_BC_CB. 4 - GS_BROADCAST Sends a broadcast to all thread siblings of the current task. Every sibling that has established a broadcast guarded storage control block will load this control block and will be enabled for guarded storage. The broadcast guarded storage control block is used up, a second broadcast without a refresh of the stored control block with GS_SET_BC_CB will not have any effect. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/elf.h1
-rw-r--r--arch/s390/include/asm/lowcore.h9
-rw-r--r--arch/s390/include/asm/nmi.h12
-rw-r--r--arch/s390/include/asm/processor.h5
-rw-r--r--arch/s390/include/asm/setup.h2
-rw-r--r--arch/s390/include/asm/switch_to.h3
-rw-r--r--arch/s390/include/asm/thread_info.h12
-rw-r--r--arch/s390/include/uapi/asm/Kbuild1
-rw-r--r--arch/s390/include/uapi/asm/guarded_storage.h77
-rw-r--r--arch/s390/include/uapi/asm/unistd.h2
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/asm-offsets.c2
-rw-r--r--arch/s390/kernel/compat_wrapper.c1
-rw-r--r--arch/s390/kernel/early.c2
-rw-r--r--arch/s390/kernel/entry.S26
-rw-r--r--arch/s390/kernel/entry.h2
-rw-r--r--arch/s390/kernel/guarded_storage.c128
-rw-r--r--arch/s390/kernel/machine_kexec.c13
-rw-r--r--arch/s390/kernel/nmi.c19
-rw-r--r--arch/s390/kernel/process.c7
-rw-r--r--arch/s390/kernel/processor.c2
-rw-r--r--arch/s390/kernel/ptrace.c86
-rw-r--r--arch/s390/kernel/setup.c18
-rw-r--r--arch/s390/kernel/smp.c43
-rw-r--r--arch/s390/kernel/syscalls.S2
-rw-r--r--arch/s390/kvm/interrupt.c4
-rw-r--r--include/uapi/linux/elf.h1
27 files changed, 436 insertions, 46 deletions
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 1d48880b3cc1..e8f623041769 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -105,6 +105,7 @@
105#define HWCAP_S390_VXRS 2048 105#define HWCAP_S390_VXRS 2048
106#define HWCAP_S390_VXRS_BCD 4096 106#define HWCAP_S390_VXRS_BCD 4096
107#define HWCAP_S390_VXRS_EXT 8192 107#define HWCAP_S390_VXRS_EXT 8192
108#define HWCAP_S390_GS 16384
108 109
109/* Internal bits, not exposed via elf */ 110/* Internal bits, not exposed via elf */
110#define HWCAP_INT_SIE 1UL 111#define HWCAP_INT_SIE 1UL
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index 61261e0e95c0..8a5b082797f8 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -157,8 +157,8 @@ struct lowcore {
157 __u64 stfle_fac_list[32]; /* 0x0f00 */ 157 __u64 stfle_fac_list[32]; /* 0x0f00 */
158 __u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */ 158 __u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */
159 159
160 /* Pointer to vector register save area */ 160 /* Pointer to the machine check extended save area */
161 __u64 vector_save_area_addr; /* 0x11b0 */ 161 __u64 mcesad; /* 0x11b0 */
162 162
163 /* 64 bit extparam used for pfault/diag 250: defined by architecture */ 163 /* 64 bit extparam used for pfault/diag 250: defined by architecture */
164 __u64 ext_params2; /* 0x11B8 */ 164 __u64 ext_params2; /* 0x11B8 */
@@ -182,10 +182,7 @@ struct lowcore {
182 182
183 /* Transaction abort diagnostic block */ 183 /* Transaction abort diagnostic block */
184 __u8 pgm_tdb[256]; /* 0x1800 */ 184 __u8 pgm_tdb[256]; /* 0x1800 */
185 __u8 pad_0x1900[0x1c00-0x1900]; /* 0x1900 */ 185 __u8 pad_0x1900[0x2000-0x1900]; /* 0x1900 */
186
187 /* Software defined save area for vector registers */
188 __u8 vector_save_area[1024]; /* 0x1c00 */
189} __packed; 186} __packed;
190 187
191#define S390_lowcore (*((struct lowcore *) 0)) 188#define S390_lowcore (*((struct lowcore *) 0))
diff --git a/arch/s390/include/asm/nmi.h b/arch/s390/include/asm/nmi.h
index b75fd910386a..e3e8895f5d3e 100644
--- a/arch/s390/include/asm/nmi.h
+++ b/arch/s390/include/asm/nmi.h
@@ -58,7 +58,9 @@ union mci {
58 u64 ie : 1; /* 32 indirect storage error */ 58 u64 ie : 1; /* 32 indirect storage error */
59 u64 ar : 1; /* 33 access register validity */ 59 u64 ar : 1; /* 33 access register validity */
60 u64 da : 1; /* 34 delayed access exception */ 60 u64 da : 1; /* 34 delayed access exception */
61 u64 : 7; /* 35-41 */ 61 u64 : 1; /* 35 */
62 u64 gs : 1; /* 36 guarded storage registers */
63 u64 : 5; /* 37-41 */
62 u64 pr : 1; /* 42 tod programmable register validity */ 64 u64 pr : 1; /* 42 tod programmable register validity */
63 u64 fc : 1; /* 43 fp control register validity */ 65 u64 fc : 1; /* 43 fp control register validity */
64 u64 ap : 1; /* 44 ancillary report */ 66 u64 ap : 1; /* 44 ancillary report */
@@ -69,6 +71,14 @@ union mci {
69 }; 71 };
70}; 72};
71 73
74#define MCESA_ORIGIN_MASK (~0x3ffUL)
75#define MCESA_LC_MASK (0xfUL)
76
77struct mcesa {
78 u8 vector_save_area[1024];
79 u8 guarded_storage_save_area[32];
80};
81
72struct pt_regs; 82struct pt_regs;
73 83
74extern void s390_handle_mcck(void); 84extern void s390_handle_mcck(void);
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index e4988710aa86..cc101f9371cb 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -135,6 +135,8 @@ struct thread_struct {
135 struct list_head list; 135 struct list_head list;
136 /* cpu runtime instrumentation */ 136 /* cpu runtime instrumentation */
137 struct runtime_instr_cb *ri_cb; 137 struct runtime_instr_cb *ri_cb;
138 struct gs_cb *gs_cb; /* Current guarded storage cb */
139 struct gs_cb *gs_bc_cb; /* Broadcast guarded storage cb */
138 unsigned char trap_tdb[256]; /* Transaction abort diagnose block */ 140 unsigned char trap_tdb[256]; /* Transaction abort diagnose block */
139 /* 141 /*
140 * Warning: 'fpu' is dynamically-sized. It *MUST* be at 142 * Warning: 'fpu' is dynamically-sized. It *MUST* be at
@@ -215,6 +217,9 @@ void show_cacheinfo(struct seq_file *m);
215/* Free all resources held by a thread. */ 217/* Free all resources held by a thread. */
216extern void release_thread(struct task_struct *); 218extern void release_thread(struct task_struct *);
217 219
220/* Free guarded storage control block for current */
221void exit_thread_gs(void);
222
218/* 223/*
219 * Return saved PC of a blocked thread. 224 * Return saved PC of a blocked thread.
220 */ 225 */
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index 30bdb5a027f3..383bd8358a8c 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -31,6 +31,7 @@
31#define MACHINE_FLAG_VX _BITUL(13) 31#define MACHINE_FLAG_VX _BITUL(13)
32#define MACHINE_FLAG_CAD _BITUL(14) 32#define MACHINE_FLAG_CAD _BITUL(14)
33#define MACHINE_FLAG_NX _BITUL(15) 33#define MACHINE_FLAG_NX _BITUL(15)
34#define MACHINE_FLAG_GS _BITUL(16)
34 35
35#define LPP_MAGIC _BITUL(31) 36#define LPP_MAGIC _BITUL(31)
36#define LPP_PFAULT_PID_MASK _AC(0xffffffff, UL) 37#define LPP_PFAULT_PID_MASK _AC(0xffffffff, UL)
@@ -70,6 +71,7 @@ extern void detect_memory_memblock(void);
70#define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX) 71#define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX)
71#define MACHINE_HAS_CAD (S390_lowcore.machine_flags & MACHINE_FLAG_CAD) 72#define MACHINE_HAS_CAD (S390_lowcore.machine_flags & MACHINE_FLAG_CAD)
72#define MACHINE_HAS_NX (S390_lowcore.machine_flags & MACHINE_FLAG_NX) 73#define MACHINE_HAS_NX (S390_lowcore.machine_flags & MACHINE_FLAG_NX)
74#define MACHINE_HAS_GS (S390_lowcore.machine_flags & MACHINE_FLAG_GS)
73 75
74/* 76/*
75 * Console mode. Override with conmode= 77 * Console mode. Override with conmode=
diff --git a/arch/s390/include/asm/switch_to.h b/arch/s390/include/asm/switch_to.h
index 12d45f0cfdd9..f6c2b5814ab0 100644
--- a/arch/s390/include/asm/switch_to.h
+++ b/arch/s390/include/asm/switch_to.h
@@ -10,6 +10,7 @@
10#include <linux/thread_info.h> 10#include <linux/thread_info.h>
11#include <asm/fpu/api.h> 11#include <asm/fpu/api.h>
12#include <asm/ptrace.h> 12#include <asm/ptrace.h>
13#include <asm/guarded_storage.h>
13 14
14extern struct task_struct *__switch_to(void *, void *); 15extern struct task_struct *__switch_to(void *, void *);
15extern void update_cr_regs(struct task_struct *task); 16extern void update_cr_regs(struct task_struct *task);
@@ -33,12 +34,14 @@ static inline void restore_access_regs(unsigned int *acrs)
33 save_fpu_regs(); \ 34 save_fpu_regs(); \
34 save_access_regs(&prev->thread.acrs[0]); \ 35 save_access_regs(&prev->thread.acrs[0]); \
35 save_ri_cb(prev->thread.ri_cb); \ 36 save_ri_cb(prev->thread.ri_cb); \
37 save_gs_cb(prev->thread.gs_cb); \
36 } \ 38 } \
37 if (next->mm) { \ 39 if (next->mm) { \
38 update_cr_regs(next); \ 40 update_cr_regs(next); \
39 set_cpu_flag(CIF_FPU); \ 41 set_cpu_flag(CIF_FPU); \
40 restore_access_regs(&next->thread.acrs[0]); \ 42 restore_access_regs(&next->thread.acrs[0]); \
41 restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ 43 restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \
44 restore_gs_cb(next->thread.gs_cb); \
42 } \ 45 } \
43 prev = __switch_to(prev,next); \ 46 prev = __switch_to(prev,next); \
44} while (0) 47} while (0)
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index a5b54a445eb8..f36e6e2b73f0 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -54,11 +54,12 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
54#define TIF_NOTIFY_RESUME 0 /* callback before returning to user */ 54#define TIF_NOTIFY_RESUME 0 /* callback before returning to user */
55#define TIF_SIGPENDING 1 /* signal pending */ 55#define TIF_SIGPENDING 1 /* signal pending */
56#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ 56#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
57#define TIF_SYSCALL_TRACE 3 /* syscall trace active */ 57#define TIF_UPROBE 3 /* breakpointed or single-stepping */
58#define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */ 58#define TIF_GUARDED_STORAGE 4 /* load guarded storage control block */
59#define TIF_SECCOMP 5 /* secure computing */ 59#define TIF_SYSCALL_TRACE 8 /* syscall trace active */
60#define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */ 60#define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */
61#define TIF_UPROBE 7 /* breakpointed or single-stepping */ 61#define TIF_SECCOMP 10 /* secure computing */
62#define TIF_SYSCALL_TRACEPOINT 11 /* syscall tracepoint instrumentation */
62#define TIF_31BIT 16 /* 32bit process */ 63#define TIF_31BIT 16 /* 32bit process */
63#define TIF_MEMDIE 17 /* is terminating due to OOM killer */ 64#define TIF_MEMDIE 17 /* is terminating due to OOM killer */
64#define TIF_RESTORE_SIGMASK 18 /* restore signal mask in do_signal() */ 65#define TIF_RESTORE_SIGMASK 18 /* restore signal mask in do_signal() */
@@ -76,5 +77,6 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
76#define _TIF_UPROBE _BITUL(TIF_UPROBE) 77#define _TIF_UPROBE _BITUL(TIF_UPROBE)
77#define _TIF_31BIT _BITUL(TIF_31BIT) 78#define _TIF_31BIT _BITUL(TIF_31BIT)
78#define _TIF_SINGLE_STEP _BITUL(TIF_SINGLE_STEP) 79#define _TIF_SINGLE_STEP _BITUL(TIF_SINGLE_STEP)
80#define _TIF_GUARDED_STORAGE _BITUL(TIF_GUARDED_STORAGE)
79 81
80#endif /* _ASM_THREAD_INFO_H */ 82#endif /* _ASM_THREAD_INFO_H */
diff --git a/arch/s390/include/uapi/asm/Kbuild b/arch/s390/include/uapi/asm/Kbuild
index 6848ba5c1454..86b761e583e3 100644
--- a/arch/s390/include/uapi/asm/Kbuild
+++ b/arch/s390/include/uapi/asm/Kbuild
@@ -12,6 +12,7 @@ header-y += dasd.h
12header-y += debug.h 12header-y += debug.h
13header-y += errno.h 13header-y += errno.h
14header-y += fcntl.h 14header-y += fcntl.h
15header-y += guarded_storage.h
15header-y += hypfs.h 16header-y += hypfs.h
16header-y += ioctl.h 17header-y += ioctl.h
17header-y += ioctls.h 18header-y += ioctls.h
diff --git a/arch/s390/include/uapi/asm/guarded_storage.h b/arch/s390/include/uapi/asm/guarded_storage.h
new file mode 100644
index 000000000000..852850e8e17e
--- /dev/null
+++ b/arch/s390/include/uapi/asm/guarded_storage.h
@@ -0,0 +1,77 @@
1#ifndef _GUARDED_STORAGE_H
2#define _GUARDED_STORAGE_H
3
4#include <linux/types.h>
5
6struct gs_cb {
7 __u64 reserved;
8 __u64 gsd;
9 __u64 gssm;
10 __u64 gs_epl_a;
11};
12
13struct gs_epl {
14 __u8 pad1;
15 union {
16 __u8 gs_eam;
17 struct {
18 __u8 : 6;
19 __u8 e : 1;
20 __u8 b : 1;
21 };
22 };
23 union {
24 __u8 gs_eci;
25 struct {
26 __u8 tx : 1;
27 __u8 cx : 1;
28 __u8 : 5;
29 __u8 in : 1;
30 };
31 };
32 union {
33 __u8 gs_eai;
34 struct {
35 __u8 : 1;
36 __u8 t : 1;
37 __u8 as : 2;
38 __u8 ar : 4;
39 };
40 };
41 __u32 pad2;
42 __u64 gs_eha;
43 __u64 gs_eia;
44 __u64 gs_eoa;
45 __u64 gs_eir;
46 __u64 gs_era;
47};
48
49#define GS_ENABLE 0
50#define GS_DISABLE 1
51#define GS_SET_BC_CB 2
52#define GS_CLEAR_BC_CB 3
53#define GS_BROADCAST 4
54
55static inline void load_gs_cb(struct gs_cb *gs_cb)
56{
57 asm volatile(".insn rxy,0xe3000000004d,0,%0" : : "Q" (*gs_cb));
58}
59
60static inline void store_gs_cb(struct gs_cb *gs_cb)
61{
62 asm volatile(".insn rxy,0xe30000000049,0,%0" : : "Q" (*gs_cb));
63}
64
65static inline void save_gs_cb(struct gs_cb *gs_cb)
66{
67 if (gs_cb)
68 store_gs_cb(gs_cb);
69}
70
71static inline void restore_gs_cb(struct gs_cb *gs_cb)
72{
73 if (gs_cb)
74 load_gs_cb(gs_cb);
75}
76
77#endif /* _GUARDED_STORAGE_H */
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h
index 152de9b796e1..ea42290e7d51 100644
--- a/arch/s390/include/uapi/asm/unistd.h
+++ b/arch/s390/include/uapi/asm/unistd.h
@@ -313,7 +313,7 @@
313#define __NR_copy_file_range 375 313#define __NR_copy_file_range 375
314#define __NR_preadv2 376 314#define __NR_preadv2 376
315#define __NR_pwritev2 377 315#define __NR_pwritev2 377
316/* Number 378 is reserved for guarded storage */ 316#define __NR_s390_guarded_storage 378
317#define __NR_statx 379 317#define __NR_statx 379
318#define NR_syscalls 380 318#define NR_syscalls 380
319 319
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 060ce548fe8b..aa5adbdaf200 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -57,7 +57,7 @@ obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o
57obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o 57obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
58obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o 58obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o
59obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o 59obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
60obj-y += runtime_instr.o cache.o fpu.o dumpstack.o 60obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o
61obj-y += entry.o reipl.o relocate_kernel.o 61obj-y += entry.o reipl.o relocate_kernel.o
62 62
63extra-y += head.o head64.o vmlinux.lds 63extra-y += head.o head64.o vmlinux.lds
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index c4b3570ded5b..6bb29633e1f1 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -175,7 +175,7 @@ int main(void)
175 /* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */ 175 /* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */
176 OFFSET(__LC_DUMP_REIPL, lowcore, ipib); 176 OFFSET(__LC_DUMP_REIPL, lowcore, ipib);
177 /* hardware defined lowcore locations 0x1000 - 0x18ff */ 177 /* hardware defined lowcore locations 0x1000 - 0x18ff */
178 OFFSET(__LC_VX_SAVE_AREA_ADDR, lowcore, vector_save_area_addr); 178 OFFSET(__LC_MCESAD, lowcore, mcesad);
179 OFFSET(__LC_EXT_PARAMS2, lowcore, ext_params2); 179 OFFSET(__LC_EXT_PARAMS2, lowcore, ext_params2);
180 OFFSET(__LC_FPREGS_SAVE_AREA, lowcore, floating_pt_save_area); 180 OFFSET(__LC_FPREGS_SAVE_AREA, lowcore, floating_pt_save_area);
181 OFFSET(__LC_GPREGS_SAVE_AREA, lowcore, gpregs_save_area); 181 OFFSET(__LC_GPREGS_SAVE_AREA, lowcore, gpregs_save_area);
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c
index e89cc2e71db1..986642a3543b 100644
--- a/arch/s390/kernel/compat_wrapper.c
+++ b/arch/s390/kernel/compat_wrapper.c
@@ -178,4 +178,5 @@ COMPAT_SYSCALL_WRAP3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
178COMPAT_SYSCALL_WRAP6(sendto, int, fd, void __user *, buff, size_t, len, unsigned int, flags, struct sockaddr __user *, addr, int, addr_len); 178COMPAT_SYSCALL_WRAP6(sendto, int, fd, void __user *, buff, size_t, len, unsigned int, flags, struct sockaddr __user *, addr, int, addr_len);
179COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags); 179COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags);
180COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags); 180COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags);
181COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb);
181COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer); 182COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer);
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 4e65c79cc5f2..95298a41076f 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -358,6 +358,8 @@ static __init void detect_machine_facilities(void)
358 S390_lowcore.machine_flags |= MACHINE_FLAG_NX; 358 S390_lowcore.machine_flags |= MACHINE_FLAG_NX;
359 __ctl_set_bit(0, 20); 359 __ctl_set_bit(0, 20);
360 } 360 }
361 if (test_facility(133))
362 S390_lowcore.machine_flags |= MACHINE_FLAG_GS;
361} 363}
362 364
363static inline void save_vector_registers(void) 365static inline void save_vector_registers(void)
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 6a7d737d514c..fa8b8f28e08b 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -47,7 +47,7 @@ STACK_SIZE = 1 << STACK_SHIFT
47STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE 47STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
48 48
49_TIF_WORK = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ 49_TIF_WORK = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
50 _TIF_UPROBE) 50 _TIF_UPROBE | _TIF_GUARDED_STORAGE)
51_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ 51_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
52 _TIF_SYSCALL_TRACEPOINT) 52 _TIF_SYSCALL_TRACEPOINT)
53_CIF_WORK = (_CIF_MCCK_PENDING | _CIF_ASCE_PRIMARY | \ 53_CIF_WORK = (_CIF_MCCK_PENDING | _CIF_ASCE_PRIMARY | \
@@ -332,6 +332,8 @@ ENTRY(system_call)
332 TSTMSK __TI_flags(%r12),_TIF_UPROBE 332 TSTMSK __TI_flags(%r12),_TIF_UPROBE
333 jo .Lsysc_uprobe_notify 333 jo .Lsysc_uprobe_notify
334#endif 334#endif
335 TSTMSK __TI_flags(%r12),_TIF_GUARDED_STORAGE
336 jo .Lsysc_guarded_storage
335 TSTMSK __PT_FLAGS(%r11),_PIF_PER_TRAP 337 TSTMSK __PT_FLAGS(%r11),_PIF_PER_TRAP
336 jo .Lsysc_singlestep 338 jo .Lsysc_singlestep
337 TSTMSK __TI_flags(%r12),_TIF_SIGPENDING 339 TSTMSK __TI_flags(%r12),_TIF_SIGPENDING
@@ -409,6 +411,14 @@ ENTRY(system_call)
409#endif 411#endif
410 412
411# 413#
414# _TIF_GUARDED_STORAGE is set, call guarded_storage_load
415#
416.Lsysc_guarded_storage:
417 lgr %r2,%r11 # pass pointer to pt_regs
418 larl %r14,.Lsysc_return
419 jg gs_load_bc_cb
420
421#
412# _PIF_PER_TRAP is set, call do_per_trap 422# _PIF_PER_TRAP is set, call do_per_trap
413# 423#
414.Lsysc_singlestep: 424.Lsysc_singlestep:
@@ -663,6 +673,8 @@ ENTRY(io_int_handler)
663 jo .Lio_sigpending 673 jo .Lio_sigpending
664 TSTMSK __TI_flags(%r12),_TIF_NOTIFY_RESUME 674 TSTMSK __TI_flags(%r12),_TIF_NOTIFY_RESUME
665 jo .Lio_notify_resume 675 jo .Lio_notify_resume
676 TSTMSK __TI_flags(%r12),_TIF_GUARDED_STORAGE
677 jo .Lio_guarded_storage
666 TSTMSK __LC_CPU_FLAGS,_CIF_FPU 678 TSTMSK __LC_CPU_FLAGS,_CIF_FPU
667 jo .Lio_vxrs 679 jo .Lio_vxrs
668 TSTMSK __LC_CPU_FLAGS,(_CIF_ASCE_PRIMARY|_CIF_ASCE_SECONDARY) 680 TSTMSK __LC_CPU_FLAGS,(_CIF_ASCE_PRIMARY|_CIF_ASCE_SECONDARY)
@@ -697,6 +709,18 @@ ENTRY(io_int_handler)
697 jg load_fpu_regs 709 jg load_fpu_regs
698 710
699# 711#
712# _TIF_GUARDED_STORAGE is set, call guarded_storage_load
713#
714.Lio_guarded_storage:
715 # TRACE_IRQS_ON already done at .Lio_return
716 ssm __LC_SVC_NEW_PSW # reenable interrupts
717 lgr %r2,%r11 # pass pointer to pt_regs
718 brasl %r14,gs_load_bc_cb
719 ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
720 TRACE_IRQS_OFF
721 j .Lio_return
722
723#
700# _TIF_NEED_RESCHED is set, call schedule 724# _TIF_NEED_RESCHED is set, call schedule
701# 725#
702.Lio_reschedule: 726.Lio_reschedule:
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index 33f901865326..dbf5f7e18246 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -74,12 +74,14 @@ long sys_sigreturn(void);
74 74
75long sys_s390_personality(unsigned int personality); 75long sys_s390_personality(unsigned int personality);
76long sys_s390_runtime_instr(int command, int signum); 76long sys_s390_runtime_instr(int command, int signum);
77long sys_s390_guarded_storage(int command, struct gs_cb __user *);
77long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t); 78long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t);
78long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t); 79long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
79 80
80DECLARE_PER_CPU(u64, mt_cycles[8]); 81DECLARE_PER_CPU(u64, mt_cycles[8]);
81 82
82void verify_facilities(void); 83void verify_facilities(void);
84void gs_load_bc_cb(struct pt_regs *regs);
83void set_fs_fixup(void); 85void set_fs_fixup(void);
84 86
85#endif /* _ENTRY_H */ 87#endif /* _ENTRY_H */
diff --git a/arch/s390/kernel/guarded_storage.c b/arch/s390/kernel/guarded_storage.c
new file mode 100644
index 000000000000..6f064745c3b1
--- /dev/null
+++ b/arch/s390/kernel/guarded_storage.c
@@ -0,0 +1,128 @@
1/*
2 * Copyright IBM Corp. 2016
3 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
4 */
5
6#include <linux/kernel.h>
7#include <linux/syscalls.h>
8#include <linux/signal.h>
9#include <linux/mm.h>
10#include <linux/slab.h>
11#include <asm/guarded_storage.h>
12#include "entry.h"
13
14void exit_thread_gs(void)
15{
16 kfree(current->thread.gs_cb);
17 kfree(current->thread.gs_bc_cb);
18 current->thread.gs_cb = current->thread.gs_bc_cb = NULL;
19}
20
21static int gs_enable(void)
22{
23 struct gs_cb *gs_cb;
24
25 if (!current->thread.gs_cb) {
26 gs_cb = kzalloc(sizeof(*gs_cb), GFP_KERNEL);
27 if (!gs_cb)
28 return -ENOMEM;
29 gs_cb->gsd = 25;
30 preempt_disable();
31 __ctl_set_bit(2, 4);
32 load_gs_cb(gs_cb);
33 current->thread.gs_cb = gs_cb;
34 preempt_enable();
35 }
36 return 0;
37}
38
39static int gs_disable(void)
40{
41 if (current->thread.gs_cb) {
42 preempt_disable();
43 kfree(current->thread.gs_cb);
44 current->thread.gs_cb = NULL;
45 __ctl_clear_bit(2, 4);
46 preempt_enable();
47 }
48 return 0;
49}
50
51static int gs_set_bc_cb(struct gs_cb __user *u_gs_cb)
52{
53 struct gs_cb *gs_cb;
54
55 gs_cb = current->thread.gs_bc_cb;
56 if (!gs_cb) {
57 gs_cb = kzalloc(sizeof(*gs_cb), GFP_KERNEL);
58 if (!gs_cb)
59 return -ENOMEM;
60 current->thread.gs_bc_cb = gs_cb;
61 }
62 if (copy_from_user(gs_cb, u_gs_cb, sizeof(*gs_cb)))
63 return -EFAULT;
64 return 0;
65}
66
67static int gs_clear_bc_cb(void)
68{
69 struct gs_cb *gs_cb;
70
71 gs_cb = current->thread.gs_bc_cb;
72 current->thread.gs_bc_cb = NULL;
73 kfree(gs_cb);
74 return 0;
75}
76
77void gs_load_bc_cb(struct pt_regs *regs)
78{
79 struct gs_cb *gs_cb;
80
81 preempt_disable();
82 clear_thread_flag(TIF_GUARDED_STORAGE);
83 gs_cb = current->thread.gs_bc_cb;
84 if (gs_cb) {
85 kfree(current->thread.gs_cb);
86 current->thread.gs_bc_cb = NULL;
87 __ctl_set_bit(2, 4);
88 load_gs_cb(gs_cb);
89 current->thread.gs_cb = gs_cb;
90 }
91 preempt_enable();
92}
93
94static int gs_broadcast(void)
95{
96 struct task_struct *sibling;
97
98 read_lock(&tasklist_lock);
99 for_each_thread(current, sibling) {
100 if (!sibling->thread.gs_bc_cb)
101 continue;
102 if (test_and_set_tsk_thread_flag(sibling, TIF_GUARDED_STORAGE))
103 kick_process(sibling);
104 }
105 read_unlock(&tasklist_lock);
106 return 0;
107}
108
109SYSCALL_DEFINE2(s390_guarded_storage, int, command,
110 struct gs_cb __user *, gs_cb)
111{
112 if (!MACHINE_HAS_GS)
113 return -EOPNOTSUPP;
114 switch (command) {
115 case GS_ENABLE:
116 return gs_enable();
117 case GS_DISABLE:
118 return gs_disable();
119 case GS_SET_BC_CB:
120 return gs_set_bc_cb(gs_cb);
121 case GS_CLEAR_BC_CB:
122 return gs_clear_bc_cb();
123 case GS_BROADCAST:
124 return gs_broadcast();
125 default:
126 return -EINVAL;
127 }
128}
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
index 3074c1d83829..db5658daf994 100644
--- a/arch/s390/kernel/machine_kexec.c
+++ b/arch/s390/kernel/machine_kexec.c
@@ -27,6 +27,7 @@
27#include <asm/cacheflush.h> 27#include <asm/cacheflush.h>
28#include <asm/os_info.h> 28#include <asm/os_info.h>
29#include <asm/switch_to.h> 29#include <asm/switch_to.h>
30#include <asm/nmi.h>
30 31
31typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long); 32typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long);
32 33
@@ -102,6 +103,8 @@ static void __do_machine_kdump(void *image)
102 */ 103 */
103static noinline void __machine_kdump(void *image) 104static noinline void __machine_kdump(void *image)
104{ 105{
106 struct mcesa *mcesa;
107 unsigned long cr2_old, cr2_new;
105 int this_cpu, cpu; 108 int this_cpu, cpu;
106 109
107 lgr_info_log(); 110 lgr_info_log();
@@ -114,8 +117,16 @@ static noinline void __machine_kdump(void *image)
114 continue; 117 continue;
115 } 118 }
116 /* Store status of the boot CPU */ 119 /* Store status of the boot CPU */
120 mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK);
117 if (MACHINE_HAS_VX) 121 if (MACHINE_HAS_VX)
118 save_vx_regs((void *) &S390_lowcore.vector_save_area); 122 save_vx_regs((__vector128 *) mcesa->vector_save_area);
123 if (MACHINE_HAS_GS) {
124 __ctl_store(cr2_old, 2, 2);
125 cr2_new = cr2_old | (1UL << 4);
126 __ctl_load(cr2_new, 2, 2);
127 save_gs_cb((struct gs_cb *) mcesa->guarded_storage_save_area);
128 __ctl_load(cr2_old, 2, 2);
129 }
119 /* 130 /*
120 * To create a good backchain for this CPU in the dump store_status 131 * To create a good backchain for this CPU in the dump store_status
121 * is passed the address of a function. The address is saved into 132 * is passed the address of a function. The address is saved into
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c
index 9bf8327154ee..985589523970 100644
--- a/arch/s390/kernel/nmi.c
+++ b/arch/s390/kernel/nmi.c
@@ -106,6 +106,7 @@ static int notrace s390_validate_registers(union mci mci, int umode)
106 int kill_task; 106 int kill_task;
107 u64 zero; 107 u64 zero;
108 void *fpt_save_area; 108 void *fpt_save_area;
109 struct mcesa *mcesa;
109 110
110 kill_task = 0; 111 kill_task = 0;
111 zero = 0; 112 zero = 0;
@@ -165,6 +166,7 @@ static int notrace s390_validate_registers(union mci mci, int umode)
165 : : "Q" (S390_lowcore.fpt_creg_save_area)); 166 : : "Q" (S390_lowcore.fpt_creg_save_area));
166 } 167 }
167 168
169 mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK);
168 if (!MACHINE_HAS_VX) { 170 if (!MACHINE_HAS_VX) {
169 /* Validate floating point registers */ 171 /* Validate floating point registers */
170 asm volatile( 172 asm volatile(
@@ -209,8 +211,8 @@ static int notrace s390_validate_registers(union mci mci, int umode)
209 " la 1,%0\n" 211 " la 1,%0\n"
210 " .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */ 212 " .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */
211 " .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */ 213 " .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */
212 : : "Q" (*(struct vx_array *) 214 : : "Q" (*(struct vx_array *) mcesa->vector_save_area)
213 &S390_lowcore.vector_save_area) : "1"); 215 : "1");
214 __ctl_load(S390_lowcore.cregs_save_area[0], 0, 0); 216 __ctl_load(S390_lowcore.cregs_save_area[0], 0, 0);
215 } 217 }
216 /* Validate access registers */ 218 /* Validate access registers */
@@ -224,6 +226,19 @@ static int notrace s390_validate_registers(union mci mci, int umode)
224 */ 226 */
225 kill_task = 1; 227 kill_task = 1;
226 } 228 }
229 /* Validate guarded storage registers */
230 if (MACHINE_HAS_GS && (S390_lowcore.cregs_save_area[2] & (1UL << 4))) {
231 if (!mci.gs)
232 /*
233 * Guarded storage register can't be restored and
234 * the current processes uses guarded storage.
235 * It has to be terminated.
236 */
237 kill_task = 1;
238 else
239 load_gs_cb((struct gs_cb *)
240 mcesa->guarded_storage_save_area);
241 }
227 /* 242 /*
228 * We don't even try to validate the TOD register, since we simply 243 * We don't even try to validate the TOD register, since we simply
229 * can't write something sensible into that register. 244 * can't write something sensible into that register.
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index f29e41c5e2ec..999d7154bbdc 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -73,8 +73,10 @@ extern void kernel_thread_starter(void);
73 */ 73 */
74void exit_thread(struct task_struct *tsk) 74void exit_thread(struct task_struct *tsk)
75{ 75{
76 if (tsk == current) 76 if (tsk == current) {
77 exit_thread_runtime_instr(); 77 exit_thread_runtime_instr();
78 exit_thread_gs();
79 }
78} 80}
79 81
80void flush_thread(void) 82void flush_thread(void)
@@ -159,6 +161,9 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long new_stackp,
159 /* Don't copy runtime instrumentation info */ 161 /* Don't copy runtime instrumentation info */
160 p->thread.ri_cb = NULL; 162 p->thread.ri_cb = NULL;
161 frame->childregs.psw.mask &= ~PSW_MASK_RI; 163 frame->childregs.psw.mask &= ~PSW_MASK_RI;
164 /* Don't copy guarded storage control block */
165 p->thread.gs_cb = NULL;
166 p->thread.gs_bc_cb = NULL;
162 167
163 /* Set a new TLS ? */ 168 /* Set a new TLS ? */
164 if (clone_flags & CLONE_SETTLS) { 169 if (clone_flags & CLONE_SETTLS) {
diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c
index 928b929a6261..c73709869447 100644
--- a/arch/s390/kernel/processor.c
+++ b/arch/s390/kernel/processor.c
@@ -95,7 +95,7 @@ static void show_cpu_summary(struct seq_file *m, void *v)
95{ 95{
96 static const char *hwcap_str[] = { 96 static const char *hwcap_str[] = {
97 "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", 97 "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
98 "edat", "etf3eh", "highgprs", "te", "vx", "vxd", "vxe" 98 "edat", "etf3eh", "highgprs", "te", "vx", "vxd", "vxe", "gs"
99 }; 99 };
100 static const char * const int_hwcap_str[] = { 100 static const char * const int_hwcap_str[] = {
101 "sie" 101 "sie"
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index c14df0a1ec3c..c933e255b5d5 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -44,30 +44,42 @@ void update_cr_regs(struct task_struct *task)
44 struct pt_regs *regs = task_pt_regs(task); 44 struct pt_regs *regs = task_pt_regs(task);
45 struct thread_struct *thread = &task->thread; 45 struct thread_struct *thread = &task->thread;
46 struct per_regs old, new; 46 struct per_regs old, new;
47 47 unsigned long cr0_old, cr0_new;
48 unsigned long cr2_old, cr2_new;
49 int cr0_changed, cr2_changed;
50
51 __ctl_store(cr0_old, 0, 0);
52 __ctl_store(cr2_old, 2, 2);
53 cr0_new = cr0_old;
54 cr2_new = cr2_old;
48 /* Take care of the enable/disable of transactional execution. */ 55 /* Take care of the enable/disable of transactional execution. */
49 if (MACHINE_HAS_TE) { 56 if (MACHINE_HAS_TE) {
50 unsigned long cr, cr_new;
51
52 __ctl_store(cr, 0, 0);
53 /* Set or clear transaction execution TXC bit 8. */ 57 /* Set or clear transaction execution TXC bit 8. */
54 cr_new = cr | (1UL << 55); 58 cr0_new |= (1UL << 55);
55 if (task->thread.per_flags & PER_FLAG_NO_TE) 59 if (task->thread.per_flags & PER_FLAG_NO_TE)
56 cr_new &= ~(1UL << 55); 60 cr0_new &= ~(1UL << 55);
57 if (cr_new != cr)
58 __ctl_load(cr_new, 0, 0);
59 /* Set or clear transaction execution TDC bits 62 and 63. */ 61 /* Set or clear transaction execution TDC bits 62 and 63. */
60 __ctl_store(cr, 2, 2); 62 cr2_new &= ~3UL;
61 cr_new = cr & ~3UL;
62 if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) { 63 if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
63 if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND) 64 if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND)
64 cr_new |= 1UL; 65 cr2_new |= 1UL;
65 else 66 else
66 cr_new |= 2UL; 67 cr2_new |= 2UL;
67 } 68 }
68 if (cr_new != cr)
69 __ctl_load(cr_new, 2, 2);
70 } 69 }
70 /* Take care of enable/disable of guarded storage. */
71 if (MACHINE_HAS_GS) {
72 cr2_new &= ~(1UL << 4);
73 if (task->thread.gs_cb)
74 cr2_new |= (1UL << 4);
75 }
76 /* Load control register 0/2 iff changed */
77 cr0_changed = cr0_new != cr0_old;
78 cr2_changed = cr2_new != cr2_old;
79 if (cr0_changed)
80 __ctl_load(cr0_new, 0, 0);
81 if (cr2_changed)
82 __ctl_load(cr2_new, 2, 2);
71 /* Copy user specified PER registers */ 83 /* Copy user specified PER registers */
72 new.control = thread->per_user.control; 84 new.control = thread->per_user.control;
73 new.start = thread->per_user.start; 85 new.start = thread->per_user.start;
@@ -1137,6 +1149,36 @@ static int s390_system_call_set(struct task_struct *target,
1137 data, 0, sizeof(unsigned int)); 1149 data, 0, sizeof(unsigned int));
1138} 1150}
1139 1151
1152static int s390_gs_cb_get(struct task_struct *target,
1153 const struct user_regset *regset,
1154 unsigned int pos, unsigned int count,
1155 void *kbuf, void __user *ubuf)
1156{
1157 struct gs_cb *data = target->thread.gs_cb;
1158
1159 if (!MACHINE_HAS_GS)
1160 return -ENODEV;
1161 if (!data)
1162 return -ENODATA;
1163 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
1164 data, 0, sizeof(struct gs_cb));
1165}
1166
1167static int s390_gs_cb_set(struct task_struct *target,
1168 const struct user_regset *regset,
1169 unsigned int pos, unsigned int count,
1170 const void *kbuf, const void __user *ubuf)
1171{
1172 struct gs_cb *data = target->thread.gs_cb;
1173
1174 if (!MACHINE_HAS_GS)
1175 return -ENODEV;
1176 if (!data)
1177 return -ENODATA;
1178 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
1179 data, 0, sizeof(struct gs_cb));
1180}
1181
1140static const struct user_regset s390_regsets[] = { 1182static const struct user_regset s390_regsets[] = {
1141 { 1183 {
1142 .core_note_type = NT_PRSTATUS, 1184 .core_note_type = NT_PRSTATUS,
@@ -1194,6 +1236,14 @@ static const struct user_regset s390_regsets[] = {
1194 .get = s390_vxrs_high_get, 1236 .get = s390_vxrs_high_get,
1195 .set = s390_vxrs_high_set, 1237 .set = s390_vxrs_high_set,
1196 }, 1238 },
1239 {
1240 .core_note_type = NT_S390_GS_CB,
1241 .n = sizeof(struct gs_cb) / sizeof(__u64),
1242 .size = sizeof(__u64),
1243 .align = sizeof(__u64),
1244 .get = s390_gs_cb_get,
1245 .set = s390_gs_cb_set,
1246 },
1197}; 1247};
1198 1248
1199static const struct user_regset_view user_s390_view = { 1249static const struct user_regset_view user_s390_view = {
@@ -1422,6 +1472,14 @@ static const struct user_regset s390_compat_regsets[] = {
1422 .get = s390_compat_regs_high_get, 1472 .get = s390_compat_regs_high_get,
1423 .set = s390_compat_regs_high_set, 1473 .set = s390_compat_regs_high_set,
1424 }, 1474 },
1475 {
1476 .core_note_type = NT_S390_GS_CB,
1477 .n = sizeof(struct gs_cb) / sizeof(__u64),
1478 .size = sizeof(__u64),
1479 .align = sizeof(__u64),
1480 .get = s390_gs_cb_get,
1481 .set = s390_gs_cb_set,
1482 },
1425}; 1483};
1426 1484
1427static const struct user_regset_view user_s390_compat_view = { 1485static const struct user_regset_view user_s390_compat_view = {
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 911dc0b49be0..3ae756c0db3d 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -339,9 +339,15 @@ static void __init setup_lowcore(void)
339 lc->stfl_fac_list = S390_lowcore.stfl_fac_list; 339 lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
340 memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, 340 memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
341 MAX_FACILITY_BIT/8); 341 MAX_FACILITY_BIT/8);
342 if (MACHINE_HAS_VX) 342 if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
343 lc->vector_save_area_addr = 343 unsigned long bits, size;
344 (unsigned long) &lc->vector_save_area; 344
345 bits = MACHINE_HAS_GS ? 11 : 10;
346 size = 1UL << bits;
347 lc->mcesad = (__u64) memblock_virt_alloc(size, size);
348 if (MACHINE_HAS_GS)
349 lc->mcesad |= bits;
350 }
345 lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; 351 lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0];
346 lc->sync_enter_timer = S390_lowcore.sync_enter_timer; 352 lc->sync_enter_timer = S390_lowcore.sync_enter_timer;
347 lc->async_enter_timer = S390_lowcore.async_enter_timer; 353 lc->async_enter_timer = S390_lowcore.async_enter_timer;
@@ -779,6 +785,12 @@ static int __init setup_hwcaps(void)
779 elf_hwcap |= HWCAP_S390_VXRS_BCD; 785 elf_hwcap |= HWCAP_S390_VXRS_BCD;
780 } 786 }
781 787
788 /*
789 * Guarded storage support HWCAP_S390_GS is bit 12.
790 */
791 if (MACHINE_HAS_GS)
792 elf_hwcap |= HWCAP_S390_GS;
793
782 get_cpu_id(&cpu_id); 794 get_cpu_id(&cpu_id);
783 add_device_randomness(&cpu_id, sizeof(cpu_id)); 795 add_device_randomness(&cpu_id, sizeof(cpu_id));
784 switch (cpu_id.machine) { 796 switch (cpu_id.machine) {
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 47a973b5b4f1..286bcee800f4 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -51,6 +51,7 @@
51#include <asm/os_info.h> 51#include <asm/os_info.h>
52#include <asm/sigp.h> 52#include <asm/sigp.h>
53#include <asm/idle.h> 53#include <asm/idle.h>
54#include <asm/nmi.h>
54#include "entry.h" 55#include "entry.h"
55 56
56enum { 57enum {
@@ -78,6 +79,8 @@ struct pcpu {
78static u8 boot_core_type; 79static u8 boot_core_type;
79static struct pcpu pcpu_devices[NR_CPUS]; 80static struct pcpu pcpu_devices[NR_CPUS];
80 81
82static struct kmem_cache *pcpu_mcesa_cache;
83
81unsigned int smp_cpu_mt_shift; 84unsigned int smp_cpu_mt_shift;
82EXPORT_SYMBOL(smp_cpu_mt_shift); 85EXPORT_SYMBOL(smp_cpu_mt_shift);
83 86
@@ -188,8 +191,10 @@ static void pcpu_ec_call(struct pcpu *pcpu, int ec_bit)
188static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) 191static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
189{ 192{
190 unsigned long async_stack, panic_stack; 193 unsigned long async_stack, panic_stack;
194 unsigned long mcesa_origin, mcesa_bits;
191 struct lowcore *lc; 195 struct lowcore *lc;
192 196
197 mcesa_origin = mcesa_bits = 0;
193 if (pcpu != &pcpu_devices[0]) { 198 if (pcpu != &pcpu_devices[0]) {
194 pcpu->lowcore = (struct lowcore *) 199 pcpu->lowcore = (struct lowcore *)
195 __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); 200 __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER);
@@ -197,20 +202,27 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
197 panic_stack = __get_free_page(GFP_KERNEL); 202 panic_stack = __get_free_page(GFP_KERNEL);
198 if (!pcpu->lowcore || !panic_stack || !async_stack) 203 if (!pcpu->lowcore || !panic_stack || !async_stack)
199 goto out; 204 goto out;
205 if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
206 mcesa_origin = (unsigned long)
207 kmem_cache_alloc(pcpu_mcesa_cache, GFP_KERNEL);
208 if (!mcesa_origin)
209 goto out;
210 mcesa_bits = MACHINE_HAS_GS ? 11 : 0;
211 }
200 } else { 212 } else {
201 async_stack = pcpu->lowcore->async_stack - ASYNC_FRAME_OFFSET; 213 async_stack = pcpu->lowcore->async_stack - ASYNC_FRAME_OFFSET;
202 panic_stack = pcpu->lowcore->panic_stack - PANIC_FRAME_OFFSET; 214 panic_stack = pcpu->lowcore->panic_stack - PANIC_FRAME_OFFSET;
215 mcesa_origin = pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK;
216 mcesa_bits = pcpu->lowcore->mcesad & MCESA_LC_MASK;
203 } 217 }
204 lc = pcpu->lowcore; 218 lc = pcpu->lowcore;
205 memcpy(lc, &S390_lowcore, 512); 219 memcpy(lc, &S390_lowcore, 512);
206 memset((char *) lc + 512, 0, sizeof(*lc) - 512); 220 memset((char *) lc + 512, 0, sizeof(*lc) - 512);
207 lc->async_stack = async_stack + ASYNC_FRAME_OFFSET; 221 lc->async_stack = async_stack + ASYNC_FRAME_OFFSET;
208 lc->panic_stack = panic_stack + PANIC_FRAME_OFFSET; 222 lc->panic_stack = panic_stack + PANIC_FRAME_OFFSET;
223 lc->mcesad = mcesa_origin | mcesa_bits;
209 lc->cpu_nr = cpu; 224 lc->cpu_nr = cpu;
210 lc->spinlock_lockval = arch_spin_lockval(cpu); 225 lc->spinlock_lockval = arch_spin_lockval(cpu);
211 if (MACHINE_HAS_VX)
212 lc->vector_save_area_addr =
213 (unsigned long) &lc->vector_save_area;
214 if (vdso_alloc_per_cpu(lc)) 226 if (vdso_alloc_per_cpu(lc))
215 goto out; 227 goto out;
216 lowcore_ptr[cpu] = lc; 228 lowcore_ptr[cpu] = lc;
@@ -218,6 +230,9 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
218 return 0; 230 return 0;
219out: 231out:
220 if (pcpu != &pcpu_devices[0]) { 232 if (pcpu != &pcpu_devices[0]) {
233 if (mcesa_origin)
234 kmem_cache_free(pcpu_mcesa_cache,
235 (void *) mcesa_origin);
221 free_page(panic_stack); 236 free_page(panic_stack);
222 free_pages(async_stack, ASYNC_ORDER); 237 free_pages(async_stack, ASYNC_ORDER);
223 free_pages((unsigned long) pcpu->lowcore, LC_ORDER); 238 free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
@@ -229,11 +244,17 @@ out:
229 244
230static void pcpu_free_lowcore(struct pcpu *pcpu) 245static void pcpu_free_lowcore(struct pcpu *pcpu)
231{ 246{
247 unsigned long mcesa_origin;
248
232 pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0); 249 pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0);
233 lowcore_ptr[pcpu - pcpu_devices] = NULL; 250 lowcore_ptr[pcpu - pcpu_devices] = NULL;
234 vdso_free_per_cpu(pcpu->lowcore); 251 vdso_free_per_cpu(pcpu->lowcore);
235 if (pcpu == &pcpu_devices[0]) 252 if (pcpu == &pcpu_devices[0])
236 return; 253 return;
254 if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
255 mcesa_origin = pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK;
256 kmem_cache_free(pcpu_mcesa_cache, (void *) mcesa_origin);
257 }
237 free_page(pcpu->lowcore->panic_stack-PANIC_FRAME_OFFSET); 258 free_page(pcpu->lowcore->panic_stack-PANIC_FRAME_OFFSET);
238 free_pages(pcpu->lowcore->async_stack-ASYNC_FRAME_OFFSET, ASYNC_ORDER); 259 free_pages(pcpu->lowcore->async_stack-ASYNC_FRAME_OFFSET, ASYNC_ORDER);
239 free_pages((unsigned long) pcpu->lowcore, LC_ORDER); 260 free_pages((unsigned long) pcpu->lowcore, LC_ORDER);
@@ -550,9 +571,11 @@ int smp_store_status(int cpu)
550 if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS, 571 if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS,
551 pa) != SIGP_CC_ORDER_CODE_ACCEPTED) 572 pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
552 return -EIO; 573 return -EIO;
553 if (!MACHINE_HAS_VX) 574 if (!MACHINE_HAS_VX && !MACHINE_HAS_GS)
554 return 0; 575 return 0;
555 pa = __pa(pcpu->lowcore->vector_save_area_addr); 576 pa = __pa(pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK);
577 if (MACHINE_HAS_GS)
578 pa |= pcpu->lowcore->mcesad & MCESA_LC_MASK;
556 if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS, 579 if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS,
557 pa) != SIGP_CC_ORDER_CODE_ACCEPTED) 580 pa) != SIGP_CC_ORDER_CODE_ACCEPTED)
558 return -EIO; 581 return -EIO;
@@ -897,12 +920,22 @@ void __init smp_fill_possible_mask(void)
897 920
898void __init smp_prepare_cpus(unsigned int max_cpus) 921void __init smp_prepare_cpus(unsigned int max_cpus)
899{ 922{
923 unsigned long size;
924
900 /* request the 0x1201 emergency signal external interrupt */ 925 /* request the 0x1201 emergency signal external interrupt */
901 if (register_external_irq(EXT_IRQ_EMERGENCY_SIG, do_ext_call_interrupt)) 926 if (register_external_irq(EXT_IRQ_EMERGENCY_SIG, do_ext_call_interrupt))
902 panic("Couldn't request external interrupt 0x1201"); 927 panic("Couldn't request external interrupt 0x1201");
903 /* request the 0x1202 external call external interrupt */ 928 /* request the 0x1202 external call external interrupt */
904 if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt)) 929 if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt))
905 panic("Couldn't request external interrupt 0x1202"); 930 panic("Couldn't request external interrupt 0x1202");
931 /* create slab cache for the machine-check-extended-save-areas */
932 if (MACHINE_HAS_VX || MACHINE_HAS_GS) {
933 size = 1UL << (MACHINE_HAS_GS ? 11 : 10);
934 pcpu_mcesa_cache = kmem_cache_create("nmi_save_areas",
935 size, size, 0, NULL);
936 if (!pcpu_mcesa_cache)
937 panic("Couldn't create nmi save area cache");
938 }
906} 939}
907 940
908void __init smp_prepare_boot_cpu(void) 941void __init smp_prepare_boot_cpu(void)
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 2659b5cfeddb..54fce7b065de 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -386,5 +386,5 @@ SYSCALL(sys_mlock2,compat_sys_mlock2)
386SYSCALL(sys_copy_file_range,compat_sys_copy_file_range) /* 375 */ 386SYSCALL(sys_copy_file_range,compat_sys_copy_file_range) /* 375 */
387SYSCALL(sys_preadv2,compat_sys_preadv2) 387SYSCALL(sys_preadv2,compat_sys_preadv2)
388SYSCALL(sys_pwritev2,compat_sys_pwritev2) 388SYSCALL(sys_pwritev2,compat_sys_pwritev2)
389NI_SYSCALL 389SYSCALL(sys_s390_guarded_storage,compat_sys_s390_guarded_storage) /* 378 */
390SYSCALL(sys_statx,compat_sys_statx) 390SYSCALL(sys_statx,compat_sys_statx)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 0f8f14199734..169558dc7daf 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -420,8 +420,8 @@ static int __write_machine_check(struct kvm_vcpu *vcpu,
420 save_access_regs(vcpu->run->s.regs.acrs); 420 save_access_regs(vcpu->run->s.regs.acrs);
421 421
422 /* Extended save area */ 422 /* Extended save area */
423 rc = read_guest_lc(vcpu, __LC_VX_SAVE_AREA_ADDR, &ext_sa_addr, 423 rc = read_guest_lc(vcpu, __LC_MCESAD, &ext_sa_addr,
424 sizeof(unsigned long)); 424 sizeof(unsigned long));
425 /* Only bits 0-53 are used for address formation */ 425 /* Only bits 0-53 are used for address formation */
426 ext_sa_addr &= ~0x3ffUL; 426 ext_sa_addr &= ~0x3ffUL;
427 if (!rc && mci.vr && ext_sa_addr && test_kvm_facility(vcpu->kvm, 129)) { 427 if (!rc && mci.vr && ext_sa_addr && test_kvm_facility(vcpu->kvm, 129)) {
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index b59ee077a596..8c6d3bdb9a00 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -409,6 +409,7 @@ typedef struct elf64_shdr {
409#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ 409#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */
410#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */ 410#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */
411#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */ 411#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */
412#define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */
412#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ 413#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
413#define NT_ARM_TLS 0x401 /* ARM TLS register */ 414#define NT_ARM_TLS 0x401 /* ARM TLS register */
414#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ 415#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */