Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+435 -45
+1
arch/s390/include/asm/elf.h
··· 105 105 #define HWCAP_S390_VXRS 2048 106 106 #define HWCAP_S390_VXRS_BCD 4096 107 107 #define HWCAP_S390_VXRS_EXT 8192 108 + #define HWCAP_S390_GS 16384 108 109 109 110 /* Internal bits, not exposed via elf */ 110 111 #define HWCAP_INT_SIE 1UL
+3 -6
arch/s390/include/asm/lowcore.h
··· 157 157 __u64 stfle_fac_list[32]; /* 0x0f00 */ 158 158 __u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */ 159 159 160 - /* Pointer to vector register save area */ 161 - __u64 vector_save_area_addr; /* 0x11b0 */ 160 + /* Pointer to the machine check extended save area */ 161 + __u64 mcesad; /* 0x11b0 */ 162 162 163 163 /* 64 bit extparam used for pfault/diag 250: defined by architecture */ 164 164 __u64 ext_params2; /* 0x11B8 */ ··· 182 182 183 183 /* Transaction abort diagnostic block */ 184 184 __u8 pgm_tdb[256]; /* 0x1800 */ 185 - __u8 pad_0x1900[0x1c00-0x1900]; /* 0x1900 */ 186 - 187 - /* Software defined save area for vector registers */ 188 - __u8 vector_save_area[1024]; /* 0x1c00 */ 185 + __u8 pad_0x1900[0x2000-0x1900]; /* 0x1900 */ 189 186 } __packed; 190 187 191 188 #define S390_lowcore (*((struct lowcore *) 0))
+11 -1
arch/s390/include/asm/nmi.h
··· 58 58 u64 ie : 1; /* 32 indirect storage error */ 59 59 u64 ar : 1; /* 33 access register validity */ 60 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 64 u64 pr : 1; /* 42 tod programmable register validity */ 63 65 u64 fc : 1; /* 43 fp control register validity */ 64 66 u64 ap : 1; /* 44 ancillary report */ ··· 69 67 u64 cc : 1; /* 47 clock comparator validity */ 70 68 u64 : 16; /* 47-63 */ 71 69 }; 70 + }; 71 + 72 + #define MCESA_ORIGIN_MASK (~0x3ffUL) 73 + #define MCESA_LC_MASK (0xfUL) 74 + 75 + struct mcesa { 76 + u8 vector_save_area[1024]; 77 + u8 guarded_storage_save_area[32]; 72 78 }; 73 79 74 80 struct pt_regs;
+5
arch/s390/include/asm/processor.h
··· 135 135 struct list_head list; 136 136 /* cpu runtime instrumentation */ 137 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 140 unsigned char trap_tdb[256]; /* Transaction abort diagnose block */ 139 141 /* 140 142 * Warning: 'fpu' is dynamically-sized. It *MUST* be at ··· 216 214 217 215 /* Free all resources held by a thread. */ 218 216 extern void release_thread(struct task_struct *); 217 + 218 + /* Free guarded storage control block for current */ 219 + void exit_thread_gs(void); 219 220 220 221 /* 221 222 * Return saved PC of a blocked thread.
+2
arch/s390/include/asm/setup.h
··· 31 31 #define MACHINE_FLAG_VX _BITUL(13) 32 32 #define MACHINE_FLAG_CAD _BITUL(14) 33 33 #define MACHINE_FLAG_NX _BITUL(15) 34 + #define MACHINE_FLAG_GS _BITUL(16) 34 35 35 36 #define LPP_MAGIC _BITUL(31) 36 37 #define LPP_PFAULT_PID_MASK _AC(0xffffffff, UL) ··· 71 70 #define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX) 72 71 #define MACHINE_HAS_CAD (S390_lowcore.machine_flags & MACHINE_FLAG_CAD) 73 72 #define MACHINE_HAS_NX (S390_lowcore.machine_flags & MACHINE_FLAG_NX) 73 + #define MACHINE_HAS_GS (S390_lowcore.machine_flags & MACHINE_FLAG_GS) 74 74 75 75 /* 76 76 * Console mode. Override with conmode=
+3
arch/s390/include/asm/switch_to.h
··· 10 10 #include <linux/thread_info.h> 11 11 #include <asm/fpu/api.h> 12 12 #include <asm/ptrace.h> 13 + #include <asm/guarded_storage.h> 13 14 14 15 extern struct task_struct *__switch_to(void *, void *); 15 16 extern void update_cr_regs(struct task_struct *task); ··· 34 33 save_fpu_regs(); \ 35 34 save_access_regs(&prev->thread.acrs[0]); \ 36 35 save_ri_cb(prev->thread.ri_cb); \ 36 + save_gs_cb(prev->thread.gs_cb); \ 37 37 } \ 38 38 if (next->mm) { \ 39 39 update_cr_regs(next); \ 40 40 set_cpu_flag(CIF_FPU); \ 41 41 restore_access_regs(&next->thread.acrs[0]); \ 42 42 restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ 43 + restore_gs_cb(next->thread.gs_cb); \ 43 44 } \ 44 45 prev = __switch_to(prev,next); \ 45 46 } while (0)
+7 -5
arch/s390/include/asm/thread_info.h
··· 54 54 #define TIF_NOTIFY_RESUME 0 /* callback before returning to user */ 55 55 #define TIF_SIGPENDING 1 /* signal pending */ 56 56 #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ 57 - #define TIF_SYSCALL_TRACE 3 /* syscall trace active */ 58 - #define TIF_SYSCALL_AUDIT 4 /* syscall auditing active */ 59 - #define TIF_SECCOMP 5 /* secure computing */ 60 - #define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */ 61 - #define TIF_UPROBE 7 /* breakpointed or single-stepping */ 57 + #define TIF_UPROBE 3 /* breakpointed or single-stepping */ 58 + #define TIF_GUARDED_STORAGE 4 /* load guarded storage control block */ 59 + #define TIF_SYSCALL_TRACE 8 /* syscall trace active */ 60 + #define TIF_SYSCALL_AUDIT 9 /* syscall auditing active */ 61 + #define TIF_SECCOMP 10 /* secure computing */ 62 + #define TIF_SYSCALL_TRACEPOINT 11 /* syscall tracepoint instrumentation */ 62 63 #define TIF_31BIT 16 /* 32bit process */ 63 64 #define TIF_MEMDIE 17 /* is terminating due to OOM killer */ 64 65 #define TIF_RESTORE_SIGMASK 18 /* restore signal mask in do_signal() */ ··· 77 76 #define _TIF_UPROBE _BITUL(TIF_UPROBE) 78 77 #define _TIF_31BIT _BITUL(TIF_31BIT) 79 78 #define _TIF_SINGLE_STEP _BITUL(TIF_SINGLE_STEP) 79 + #define _TIF_GUARDED_STORAGE _BITUL(TIF_GUARDED_STORAGE) 80 80 81 81 #endif /* _ASM_THREAD_INFO_H */
+1
arch/s390/include/uapi/asm/Kbuild
··· 12 12 header-y += debug.h 13 13 header-y += errno.h 14 14 header-y += fcntl.h 15 + header-y += guarded_storage.h 15 16 header-y += hypfs.h 16 17 header-y += ioctl.h 17 18 header-y += ioctls.h
+77
arch/s390/include/uapi/asm/guarded_storage.h
··· 1 + #ifndef _GUARDED_STORAGE_H 2 + #define _GUARDED_STORAGE_H 3 + 4 + #include <linux/types.h> 5 + 6 + struct gs_cb { 7 + __u64 reserved; 8 + __u64 gsd; 9 + __u64 gssm; 10 + __u64 gs_epl_a; 11 + }; 12 + 13 + struct 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 + 55 + static inline void load_gs_cb(struct gs_cb *gs_cb) 56 + { 57 + asm volatile(".insn rxy,0xe3000000004d,0,%0" : : "Q" (*gs_cb)); 58 + } 59 + 60 + static inline void store_gs_cb(struct gs_cb *gs_cb) 61 + { 62 + asm volatile(".insn rxy,0xe30000000049,0,%0" : : "Q" (*gs_cb)); 63 + } 64 + 65 + static inline void save_gs_cb(struct gs_cb *gs_cb) 66 + { 67 + if (gs_cb) 68 + store_gs_cb(gs_cb); 69 + } 70 + 71 + static 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 */
+1 -1
arch/s390/include/uapi/asm/unistd.h
··· 313 313 #define __NR_copy_file_range 375 314 314 #define __NR_preadv2 376 315 315 #define __NR_pwritev2 377 316 - /* Number 378 is reserved for guarded storage */ 316 + #define __NR_s390_guarded_storage 378 317 317 #define __NR_statx 379 318 318 #define NR_syscalls 380 319 319
+1 -1
arch/s390/kernel/Makefile
··· 57 57 obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o 58 58 obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o als.o 59 59 obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o 60 - obj-y += runtime_instr.o cache.o fpu.o dumpstack.o 60 + obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o 61 61 obj-y += entry.o reipl.o relocate_kernel.o 62 62 63 63 extra-y += head.o head64.o vmlinux.lds
+1 -1
arch/s390/kernel/asm-offsets.c
··· 175 175 /* software defined ABI-relevant lowcore locations 0xe00 - 0xe20 */ 176 176 OFFSET(__LC_DUMP_REIPL, lowcore, ipib); 177 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 179 OFFSET(__LC_EXT_PARAMS2, lowcore, ext_params2); 180 180 OFFSET(__LC_FPREGS_SAVE_AREA, lowcore, floating_pt_save_area); 181 181 OFFSET(__LC_GPREGS_SAVE_AREA, lowcore, gpregs_save_area);
+1
arch/s390/kernel/compat_wrapper.c
··· 178 178 COMPAT_SYSCALL_WRAP6(sendto, int, fd, void __user *, buff, size_t, len, unsigned int, flags, struct sockaddr __user *, addr, int, addr_len); 179 179 COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags); 180 180 COMPAT_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); 181 + COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb); 181 182 COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer);
+2
arch/s390/kernel/early.c
··· 358 358 S390_lowcore.machine_flags |= MACHINE_FLAG_NX; 359 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 363 365 static inline void save_vector_registers(void)
+25 -1
arch/s390/kernel/entry.S
··· 47 47 STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE 48 48 49 49 _TIF_WORK = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ 50 - _TIF_UPROBE) 50 + _TIF_UPROBE | _TIF_GUARDED_STORAGE) 51 51 _TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ 52 52 _TIF_SYSCALL_TRACEPOINT) 53 53 _CIF_WORK = (_CIF_MCCK_PENDING | _CIF_ASCE_PRIMARY | \ ··· 332 332 TSTMSK __TI_flags(%r12),_TIF_UPROBE 333 333 jo .Lsysc_uprobe_notify 334 334 #endif 335 + TSTMSK __TI_flags(%r12),_TIF_GUARDED_STORAGE 336 + jo .Lsysc_guarded_storage 335 337 TSTMSK __PT_FLAGS(%r11),_PIF_PER_TRAP 336 338 jo .Lsysc_singlestep 337 339 TSTMSK __TI_flags(%r12),_TIF_SIGPENDING ··· 409 407 larl %r14,.Lsysc_return 410 408 jg uprobe_notify_resume 411 409 #endif 410 + 411 + # 412 + # _TIF_GUARDED_STORAGE is set, call guarded_storage_load 413 + # 414 + .Lsysc_guarded_storage: 415 + lgr %r2,%r11 # pass pointer to pt_regs 416 + larl %r14,.Lsysc_return 417 + jg gs_load_bc_cb 412 418 413 419 # 414 420 # _PIF_PER_TRAP is set, call do_per_trap ··· 673 663 jo .Lio_sigpending 674 664 TSTMSK __TI_flags(%r12),_TIF_NOTIFY_RESUME 675 665 jo .Lio_notify_resume 666 + TSTMSK __TI_flags(%r12),_TIF_GUARDED_STORAGE 667 + jo .Lio_guarded_storage 676 668 TSTMSK __LC_CPU_FLAGS,_CIF_FPU 677 669 jo .Lio_vxrs 678 670 TSTMSK __LC_CPU_FLAGS,(_CIF_ASCE_PRIMARY|_CIF_ASCE_SECONDARY) ··· 707 695 .Lio_vxrs: 708 696 larl %r14,.Lio_return 709 697 jg load_fpu_regs 698 + 699 + # 700 + # _TIF_GUARDED_STORAGE is set, call guarded_storage_load 701 + # 702 + .Lio_guarded_storage: 703 + # TRACE_IRQS_ON already done at .Lio_return 704 + ssm __LC_SVC_NEW_PSW # reenable interrupts 705 + lgr %r2,%r11 # pass pointer to pt_regs 706 + brasl %r14,gs_load_bc_cb 707 + ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts 708 + TRACE_IRQS_OFF 709 + j .Lio_return 710 710 711 711 # 712 712 # _TIF_NEED_RESCHED is set, call schedule
+2
arch/s390/kernel/entry.h
··· 74 74 75 75 long sys_s390_personality(unsigned int personality); 76 76 long sys_s390_runtime_instr(int command, int signum); 77 + long sys_s390_guarded_storage(int command, struct gs_cb __user *); 77 78 long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t); 78 79 long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t); 79 80 80 81 DECLARE_PER_CPU(u64, mt_cycles[8]); 81 82 82 83 void verify_facilities(void); 84 + void gs_load_bc_cb(struct pt_regs *regs); 83 85 void set_fs_fixup(void); 84 86 85 87 #endif /* _ENTRY_H */
+128
arch/s390/kernel/guarded_storage.c
··· 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 + 14 + void 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 + 21 + static 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 + 39 + static 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 + 51 + static 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 + 67 + static 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 + 77 + void 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 + 94 + static 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 + 109 + SYSCALL_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 + }
+12 -1
arch/s390/kernel/machine_kexec.c
··· 27 27 #include <asm/cacheflush.h> 28 28 #include <asm/os_info.h> 29 29 #include <asm/switch_to.h> 30 + #include <asm/nmi.h> 30 31 31 32 typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long); 32 33 ··· 103 102 */ 104 103 static noinline void __machine_kdump(void *image) 105 104 { 105 + struct mcesa *mcesa; 106 + unsigned long cr2_old, cr2_new; 106 107 int this_cpu, cpu; 107 108 108 109 lgr_info_log(); ··· 117 114 continue; 118 115 } 119 116 /* Store status of the boot CPU */ 117 + mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK); 120 118 if (MACHINE_HAS_VX) 121 - save_vx_regs((void *) &S390_lowcore.vector_save_area); 119 + save_vx_regs((__vector128 *) mcesa->vector_save_area); 120 + if (MACHINE_HAS_GS) { 121 + __ctl_store(cr2_old, 2, 2); 122 + cr2_new = cr2_old | (1UL << 4); 123 + __ctl_load(cr2_new, 2, 2); 124 + save_gs_cb((struct gs_cb *) mcesa->guarded_storage_save_area); 125 + __ctl_load(cr2_old, 2, 2); 126 + } 122 127 /* 123 128 * To create a good backchain for this CPU in the dump store_status 124 129 * is passed the address of a function. The address is saved into
+17 -2
arch/s390/kernel/nmi.c
··· 106 106 int kill_task; 107 107 u64 zero; 108 108 void *fpt_save_area; 109 + struct mcesa *mcesa; 109 110 110 111 kill_task = 0; 111 112 zero = 0; ··· 166 165 : : "Q" (S390_lowcore.fpt_creg_save_area)); 167 166 } 168 167 168 + mcesa = (struct mcesa *)(S390_lowcore.mcesad & MCESA_ORIGIN_MASK); 169 169 if (!MACHINE_HAS_VX) { 170 170 /* Validate floating point registers */ 171 171 asm volatile( ··· 211 209 " la 1,%0\n" 212 210 " .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */ 213 211 " .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */ 214 - : : "Q" (*(struct vx_array *) 215 - &S390_lowcore.vector_save_area) : "1"); 212 + : : "Q" (*(struct vx_array *) mcesa->vector_save_area) 213 + : "1"); 216 214 __ctl_load(S390_lowcore.cregs_save_area[0], 0, 0); 217 215 } 218 216 /* Validate access registers */ ··· 225 223 * Terminating task. 226 224 */ 227 225 kill_task = 1; 226 + } 227 + /* Validate guarded storage registers */ 228 + if (MACHINE_HAS_GS && (S390_lowcore.cregs_save_area[2] & (1UL << 4))) { 229 + if (!mci.gs) 230 + /* 231 + * Guarded storage register can't be restored and 232 + * the current processes uses guarded storage. 233 + * It has to be terminated. 234 + */ 235 + kill_task = 1; 236 + else 237 + load_gs_cb((struct gs_cb *) 238 + mcesa->guarded_storage_save_area); 228 239 } 229 240 /* 230 241 * We don't even try to validate the TOD register, since we simply
+6 -1
arch/s390/kernel/process.c
··· 73 73 */ 74 74 void exit_thread(struct task_struct *tsk) 75 75 { 76 - if (tsk == current) 76 + if (tsk == current) { 77 77 exit_thread_runtime_instr(); 78 + exit_thread_gs(); 79 + } 78 80 } 79 81 80 82 void flush_thread(void) ··· 161 159 /* Don't copy runtime instrumentation info */ 162 160 p->thread.ri_cb = NULL; 163 161 frame->childregs.psw.mask &= ~PSW_MASK_RI; 162 + /* Don't copy guarded storage control block */ 163 + p->thread.gs_cb = NULL; 164 + p->thread.gs_bc_cb = NULL; 164 165 165 166 /* Set a new TLS ? */ 166 167 if (clone_flags & CLONE_SETTLS) {
+1 -1
arch/s390/kernel/processor.c
··· 95 95 { 96 96 static const char *hwcap_str[] = { 97 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 100 static const char * const int_hwcap_str[] = { 101 101 "sie"
+71 -13
arch/s390/kernel/ptrace.c
··· 44 44 struct pt_regs *regs = task_pt_regs(task); 45 45 struct thread_struct *thread = &task->thread; 46 46 struct per_regs old, new; 47 + unsigned long cr0_old, cr0_new; 48 + unsigned long cr2_old, cr2_new; 49 + int cr0_changed, cr2_changed; 47 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 55 /* Take care of the enable/disable of transactional execution. */ 49 56 if (MACHINE_HAS_TE) { 50 - unsigned long cr, cr_new; 51 - 52 - __ctl_store(cr, 0, 0); 53 57 /* Set or clear transaction execution TXC bit 8. */ 54 - cr_new = cr | (1UL << 55); 58 + cr0_new |= (1UL << 55); 55 59 if (task->thread.per_flags & PER_FLAG_NO_TE) 56 - cr_new &= ~(1UL << 55); 57 - if (cr_new != cr) 58 - __ctl_load(cr_new, 0, 0); 60 + cr0_new &= ~(1UL << 55); 59 61 /* Set or clear transaction execution TDC bits 62 and 63. */ 60 - __ctl_store(cr, 2, 2); 61 - cr_new = cr & ~3UL; 62 + cr2_new &= ~3UL; 62 63 if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) { 63 64 if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND) 64 - cr_new |= 1UL; 65 + cr2_new |= 1UL; 65 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 83 /* Copy user specified PER registers */ 72 84 new.control = thread->per_user.control; 73 85 new.start = thread->per_user.start; ··· 1149 1137 data, 0, sizeof(unsigned int)); 1150 1138 } 1151 1139 1140 + static int s390_gs_cb_get(struct task_struct *target, 1141 + const struct user_regset *regset, 1142 + unsigned int pos, unsigned int count, 1143 + void *kbuf, void __user *ubuf) 1144 + { 1145 + struct gs_cb *data = target->thread.gs_cb; 1146 + 1147 + if (!MACHINE_HAS_GS) 1148 + return -ENODEV; 1149 + if (!data) 1150 + return -ENODATA; 1151 + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 1152 + data, 0, sizeof(struct gs_cb)); 1153 + } 1154 + 1155 + static int s390_gs_cb_set(struct task_struct *target, 1156 + const struct user_regset *regset, 1157 + unsigned int pos, unsigned int count, 1158 + const void *kbuf, const void __user *ubuf) 1159 + { 1160 + struct gs_cb *data = target->thread.gs_cb; 1161 + 1162 + if (!MACHINE_HAS_GS) 1163 + return -ENODEV; 1164 + if (!data) 1165 + return -ENODATA; 1166 + return user_regset_copyin(&pos, &count, &kbuf, &ubuf, 1167 + data, 0, sizeof(struct gs_cb)); 1168 + } 1169 + 1152 1170 static const struct user_regset s390_regsets[] = { 1153 1171 { 1154 1172 .core_note_type = NT_PRSTATUS, ··· 1235 1193 .align = sizeof(__vector128), 1236 1194 .get = s390_vxrs_high_get, 1237 1195 .set = s390_vxrs_high_set, 1196 + }, 1197 + { 1198 + .core_note_type = NT_S390_GS_CB, 1199 + .n = sizeof(struct gs_cb) / sizeof(__u64), 1200 + .size = sizeof(__u64), 1201 + .align = sizeof(__u64), 1202 + .get = s390_gs_cb_get, 1203 + .set = s390_gs_cb_set, 1238 1204 }, 1239 1205 }; 1240 1206 ··· 1471 1421 .align = sizeof(compat_long_t), 1472 1422 .get = s390_compat_regs_high_get, 1473 1423 .set = s390_compat_regs_high_set, 1424 + }, 1425 + { 1426 + .core_note_type = NT_S390_GS_CB, 1427 + .n = sizeof(struct gs_cb) / sizeof(__u64), 1428 + .size = sizeof(__u64), 1429 + .align = sizeof(__u64), 1430 + .get = s390_gs_cb_get, 1431 + .set = s390_gs_cb_set, 1474 1432 }, 1475 1433 }; 1476 1434
+15 -3
arch/s390/kernel/setup.c
··· 339 339 lc->stfl_fac_list = S390_lowcore.stfl_fac_list; 340 340 memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list, 341 341 MAX_FACILITY_BIT/8); 342 - if (MACHINE_HAS_VX) 343 - lc->vector_save_area_addr = 344 - (unsigned long) &lc->vector_save_area; 342 + if (MACHINE_HAS_VX || MACHINE_HAS_GS) { 343 + unsigned long bits, size; 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 351 lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; 346 352 lc->sync_enter_timer = S390_lowcore.sync_enter_timer; 347 353 lc->async_enter_timer = S390_lowcore.async_enter_timer; ··· 784 778 if (test_facility(135)) 785 779 elf_hwcap |= HWCAP_S390_VXRS_BCD; 786 780 } 781 + 782 + /* 783 + * Guarded storage support HWCAP_S390_GS is bit 12. 784 + */ 785 + if (MACHINE_HAS_GS) 786 + elf_hwcap |= HWCAP_S390_GS; 787 787 788 788 get_cpu_id(&cpu_id); 789 789 add_device_randomness(&cpu_id, sizeof(cpu_id));
+38 -5
arch/s390/kernel/smp.c
··· 51 51 #include <asm/os_info.h> 52 52 #include <asm/sigp.h> 53 53 #include <asm/idle.h> 54 + #include <asm/nmi.h> 54 55 #include "entry.h" 55 56 56 57 enum { ··· 78 77 79 78 static u8 boot_core_type; 80 79 static struct pcpu pcpu_devices[NR_CPUS]; 80 + 81 + static struct kmem_cache *pcpu_mcesa_cache; 81 82 82 83 unsigned int smp_cpu_mt_shift; 83 84 EXPORT_SYMBOL(smp_cpu_mt_shift); ··· 191 188 static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu) 192 189 { 193 190 unsigned long async_stack, panic_stack; 191 + unsigned long mcesa_origin, mcesa_bits; 194 192 struct lowcore *lc; 195 193 194 + mcesa_origin = mcesa_bits = 0; 196 195 if (pcpu != &pcpu_devices[0]) { 197 196 pcpu->lowcore = (struct lowcore *) 198 197 __get_free_pages(GFP_KERNEL | GFP_DMA, LC_ORDER); ··· 202 197 panic_stack = __get_free_page(GFP_KERNEL); 203 198 if (!pcpu->lowcore || !panic_stack || !async_stack) 204 199 goto out; 200 + if (MACHINE_HAS_VX || MACHINE_HAS_GS) { 201 + mcesa_origin = (unsigned long) 202 + kmem_cache_alloc(pcpu_mcesa_cache, GFP_KERNEL); 203 + if (!mcesa_origin) 204 + goto out; 205 + mcesa_bits = MACHINE_HAS_GS ? 11 : 0; 206 + } 205 207 } else { 206 208 async_stack = pcpu->lowcore->async_stack - ASYNC_FRAME_OFFSET; 207 209 panic_stack = pcpu->lowcore->panic_stack - PANIC_FRAME_OFFSET; 210 + mcesa_origin = pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK; 211 + mcesa_bits = pcpu->lowcore->mcesad & MCESA_LC_MASK; 208 212 } 209 213 lc = pcpu->lowcore; 210 214 memcpy(lc, &S390_lowcore, 512); 211 215 memset((char *) lc + 512, 0, sizeof(*lc) - 512); 212 216 lc->async_stack = async_stack + ASYNC_FRAME_OFFSET; 213 217 lc->panic_stack = panic_stack + PANIC_FRAME_OFFSET; 218 + lc->mcesad = mcesa_origin | mcesa_bits; 214 219 lc->cpu_nr = cpu; 215 220 lc->spinlock_lockval = arch_spin_lockval(cpu); 216 - if (MACHINE_HAS_VX) 217 - lc->vector_save_area_addr = 218 - (unsigned long) &lc->vector_save_area; 219 221 if (vdso_alloc_per_cpu(lc)) 220 222 goto out; 221 223 lowcore_ptr[cpu] = lc; ··· 230 218 return 0; 231 219 out: 232 220 if (pcpu != &pcpu_devices[0]) { 221 + if (mcesa_origin) 222 + kmem_cache_free(pcpu_mcesa_cache, 223 + (void *) mcesa_origin); 233 224 free_page(panic_stack); 234 225 free_pages(async_stack, ASYNC_ORDER); 235 226 free_pages((unsigned long) pcpu->lowcore, LC_ORDER); ··· 244 229 245 230 static void pcpu_free_lowcore(struct pcpu *pcpu) 246 231 { 232 + unsigned long mcesa_origin; 233 + 247 234 pcpu_sigp_retry(pcpu, SIGP_SET_PREFIX, 0); 248 235 lowcore_ptr[pcpu - pcpu_devices] = NULL; 249 236 vdso_free_per_cpu(pcpu->lowcore); 250 237 if (pcpu == &pcpu_devices[0]) 251 238 return; 239 + if (MACHINE_HAS_VX || MACHINE_HAS_GS) { 240 + mcesa_origin = pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK; 241 + kmem_cache_free(pcpu_mcesa_cache, (void *) mcesa_origin); 242 + } 252 243 free_page(pcpu->lowcore->panic_stack-PANIC_FRAME_OFFSET); 253 244 free_pages(pcpu->lowcore->async_stack-ASYNC_FRAME_OFFSET, ASYNC_ORDER); 254 245 free_pages((unsigned long) pcpu->lowcore, LC_ORDER); ··· 571 550 if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS, 572 551 pa) != SIGP_CC_ORDER_CODE_ACCEPTED) 573 552 return -EIO; 574 - if (!MACHINE_HAS_VX) 553 + if (!MACHINE_HAS_VX && !MACHINE_HAS_GS) 575 554 return 0; 576 - pa = __pa(pcpu->lowcore->vector_save_area_addr); 555 + pa = __pa(pcpu->lowcore->mcesad & MCESA_ORIGIN_MASK); 556 + if (MACHINE_HAS_GS) 557 + pa |= pcpu->lowcore->mcesad & MCESA_LC_MASK; 577 558 if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_ADDITIONAL_STATUS, 578 559 pa) != SIGP_CC_ORDER_CODE_ACCEPTED) 579 560 return -EIO; ··· 920 897 921 898 void __init smp_prepare_cpus(unsigned int max_cpus) 922 899 { 900 + unsigned long size; 901 + 923 902 /* request the 0x1201 emergency signal external interrupt */ 924 903 if (register_external_irq(EXT_IRQ_EMERGENCY_SIG, do_ext_call_interrupt)) 925 904 panic("Couldn't request external interrupt 0x1201"); 926 905 /* request the 0x1202 external call external interrupt */ 927 906 if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt)) 928 907 panic("Couldn't request external interrupt 0x1202"); 908 + /* create slab cache for the machine-check-extended-save-areas */ 909 + if (MACHINE_HAS_VX || MACHINE_HAS_GS) { 910 + size = 1UL << (MACHINE_HAS_GS ? 11 : 10); 911 + pcpu_mcesa_cache = kmem_cache_create("nmi_save_areas", 912 + size, size, 0, NULL); 913 + if (!pcpu_mcesa_cache) 914 + panic("Couldn't create nmi save area cache"); 915 + } 929 916 } 930 917 931 918 void __init smp_prepare_boot_cpu(void)
+1 -1
arch/s390/kernel/syscalls.S
··· 386 386 SYSCALL(sys_copy_file_range,compat_sys_copy_file_range) /* 375 */ 387 387 SYSCALL(sys_preadv2,compat_sys_preadv2) 388 388 SYSCALL(sys_pwritev2,compat_sys_pwritev2) 389 - NI_SYSCALL 389 + SYSCALL(sys_s390_guarded_storage,compat_sys_s390_guarded_storage) /* 378 */ 390 390 SYSCALL(sys_statx,compat_sys_statx)
+2 -2
arch/s390/kvm/interrupt.c
··· 420 420 save_access_regs(vcpu->run->s.regs.acrs); 421 421 422 422 /* Extended save area */ 423 - rc = read_guest_lc(vcpu, __LC_VX_SAVE_AREA_ADDR, &ext_sa_addr, 424 - sizeof(unsigned long)); 423 + rc = read_guest_lc(vcpu, __LC_MCESAD, &ext_sa_addr, 424 + sizeof(unsigned long)); 425 425 /* Only bits 0-53 are used for address formation */ 426 426 ext_sa_addr &= ~0x3ffUL; 427 427 if (!rc && mci.vr && ext_sa_addr && test_kvm_facility(vcpu->kvm, 129)) {
+1
include/uapi/linux/elf.h
··· 409 409 #define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ 410 410 #define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */ 411 411 #define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */ 412 + #define NT_S390_GS_CB 0x30b /* s390 guarded storage registers */ 412 413 #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ 413 414 #define NT_ARM_TLS 0x401 /* ARM TLS register */ 414 415 #define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */