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

s390: add support for vector extension

The vector extension introduces 32 128-bit vector registers and a set of
instruction to operate on the vector registers.

The kernel can control the use of vector registers for the problem state
program with a bit in control register 0. Once enabled for a process the
kernel needs to retain the content of the vector registers on context
switch. The signal frame is extended to include the vector registers.
Two new register sets NT_S390_VXRS_LOW and NT_S390_VXRS_HIGH are added
to the regset interface for the debugger and core dumps.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

+855 -238
+1
arch/s390/include/asm/elf.h
··· 102 102 #define HWCAP_S390_ETF3EH 256 103 103 #define HWCAP_S390_HIGH_GPRS 512 104 104 #define HWCAP_S390_TE 1024 105 + #define HWCAP_S390_VXRS 2048 105 106 106 107 /* 107 108 * These are used to set parameters in the core dumps.
+7 -3
arch/s390/include/asm/lowcore.h
··· 310 310 311 311 /* Extended facility list */ 312 312 __u64 stfle_fac_list[32]; /* 0x0f00 */ 313 - __u8 pad_0x1000[0x11b8-0x1000]; /* 0x1000 */ 313 + __u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */ 314 + 315 + /* Pointer to vector register save area */ 316 + __u64 vector_save_area_addr; /* 0x11b0 */ 314 317 315 318 /* 64 bit extparam used for pfault/diag 250: defined by architecture */ 316 319 __u64 ext_params2; /* 0x11B8 */ ··· 337 334 338 335 /* Transaction abort diagnostic block */ 339 336 __u8 pgm_tdb[256]; /* 0x1800 */ 337 + __u8 pad_0x1900[0x1c00-0x1900]; /* 0x1900 */ 340 338 341 - /* align to the top of the prefix area */ 342 - __u8 pad_0x1900[0x2000-0x1900]; /* 0x1900 */ 339 + /* Software defined save area for vector registers */ 340 + __u8 vector_save_area[1024]; /* 0x1c00 */ 343 341 } __packed; 344 342 345 343 #endif /* CONFIG_32BIT */
+1 -1
arch/s390/include/asm/nmi.h
··· 38 38 __u32 pm : 1; /* 22 psw program mask and cc validity */ 39 39 __u32 ia : 1; /* 23 psw instruction address validity */ 40 40 __u32 fa : 1; /* 24 failing storage address validity */ 41 - __u32 : 1; /* 25 */ 41 + __u32 vr : 1; /* 25 vector register validity */ 42 42 __u32 ec : 1; /* 26 external damage code validity */ 43 43 __u32 fp : 1; /* 27 floating point register validity */ 44 44 __u32 gr : 1; /* 28 general register validity */
+1
arch/s390/include/asm/processor.h
··· 117 117 int ri_signum; 118 118 #ifdef CONFIG_64BIT 119 119 unsigned char trap_tdb[256]; /* Transaction abort diagnose block */ 120 + __vector128 *vxrs; /* Vector register save area */ 120 121 #endif 121 122 }; 122 123
+3
arch/s390/include/asm/setup.h
··· 56 56 #define MACHINE_FLAG_TOPOLOGY (1UL << 14) 57 57 #define MACHINE_FLAG_TE (1UL << 15) 58 58 #define MACHINE_FLAG_TLB_LC (1UL << 17) 59 + #define MACHINE_FLAG_VX (1UL << 18) 59 60 60 61 #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) 61 62 #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) ··· 79 78 #define MACHINE_HAS_TOPOLOGY (0) 80 79 #define MACHINE_HAS_TE (0) 81 80 #define MACHINE_HAS_TLB_LC (0) 81 + #define MACHINE_HAS_VX (0) 82 82 #else /* CONFIG_64BIT */ 83 83 #define MACHINE_HAS_IEEE (1) 84 84 #define MACHINE_HAS_CSP (1) ··· 92 90 #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) 93 91 #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) 94 92 #define MACHINE_HAS_TLB_LC (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC) 93 + #define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX) 95 94 #endif /* CONFIG_64BIT */ 96 95 97 96 /*
+45 -3
arch/s390/include/asm/switch_to.h
··· 103 103 asm volatile("ld 15,%0" : : "Q" (fprs[15])); 104 104 } 105 105 106 + static inline void save_vx_regs(__vector128 *vxrs) 107 + { 108 + typedef struct { __vector128 _[__NUM_VXRS]; } addrtype; 109 + 110 + asm volatile( 111 + " la 1,%0\n" 112 + " .word 0xe70f,0x1000,0x003e\n" /* vstm 0,15,0(1) */ 113 + " .word 0xe70f,0x1100,0x0c3e\n" /* vstm 16,31,256(1) */ 114 + : "=Q" (*(addrtype *) vxrs) : : "1"); 115 + } 116 + 117 + static inline void restore_vx_regs(__vector128 *vxrs) 118 + { 119 + typedef struct { __vector128 _[__NUM_VXRS]; } addrtype; 120 + 121 + asm volatile( 122 + " la 1,%0\n" 123 + " .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */ 124 + " .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */ 125 + : : "Q" (*(addrtype *) vxrs) : "1"); 126 + } 127 + 128 + static inline void save_fp_vx_regs(struct task_struct *task) 129 + { 130 + #ifdef CONFIG_64BIT 131 + if (task->thread.vxrs) 132 + save_vx_regs(task->thread.vxrs); 133 + else 134 + #endif 135 + save_fp_regs(task->thread.fp_regs.fprs); 136 + } 137 + 138 + static inline void restore_fp_vx_regs(struct task_struct *task) 139 + { 140 + #ifdef CONFIG_64BIT 141 + if (task->thread.vxrs) 142 + restore_vx_regs(task->thread.vxrs); 143 + else 144 + #endif 145 + restore_fp_regs(task->thread.fp_regs.fprs); 146 + } 147 + 106 148 static inline void save_access_regs(unsigned int *acrs) 107 149 { 108 150 typedef struct { int _[NUM_ACRS]; } acrstype; ··· 162 120 #define switch_to(prev,next,last) do { \ 163 121 if (prev->mm) { \ 164 122 save_fp_ctl(&prev->thread.fp_regs.fpc); \ 165 - save_fp_regs(prev->thread.fp_regs.fprs); \ 123 + save_fp_vx_regs(prev); \ 166 124 save_access_regs(&prev->thread.acrs[0]); \ 167 125 save_ri_cb(prev->thread.ri_cb); \ 168 126 } \ 169 127 if (next->mm) { \ 128 + update_cr_regs(next); \ 170 129 restore_fp_ctl(&next->thread.fp_regs.fpc); \ 171 - restore_fp_regs(next->thread.fp_regs.fprs); \ 130 + restore_fp_vx_regs(next); \ 172 131 restore_access_regs(&next->thread.acrs[0]); \ 173 132 restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ 174 - update_cr_regs(next); \ 175 133 } \ 176 134 prev = __switch_to(prev,next); \ 177 135 } while (0)
+17 -3
arch/s390/include/uapi/asm/sigcontext.h
··· 7 7 #define _ASM_S390_SIGCONTEXT_H 8 8 9 9 #include <linux/compiler.h> 10 + #include <linux/types.h> 10 11 11 - #define __NUM_GPRS 16 12 - #define __NUM_FPRS 16 13 - #define __NUM_ACRS 16 12 + #define __NUM_GPRS 16 13 + #define __NUM_FPRS 16 14 + #define __NUM_ACRS 16 15 + #define __NUM_VXRS 32 16 + #define __NUM_VXRS_LOW 16 17 + #define __NUM_VXRS_HIGH 16 14 18 15 19 #ifndef __s390x__ 16 20 ··· 62 58 _s390_regs_common regs; 63 59 _s390_fp_regs fpregs; 64 60 } _sigregs; 61 + 62 + typedef struct 63 + { 64 + #ifndef __s390x__ 65 + unsigned long gprs_high[__NUM_GPRS]; 66 + #endif 67 + unsigned long long vxrs_low[__NUM_VXRS_LOW]; 68 + __vector128 vxrs_high[__NUM_VXRS_HIGH]; 69 + unsigned char __reserved[128]; 70 + } _sigregs_ext; 65 71 66 72 struct sigcontext 67 73 {
+4
arch/s390/include/uapi/asm/types.h
··· 17 17 typedef unsigned long addr_t; 18 18 typedef __signed__ long saddr_t; 19 19 20 + typedef struct { 21 + __u32 u[4]; 22 + } __vector128; 23 + 20 24 #endif /* __ASSEMBLY__ */ 21 25 22 26 #endif /* _UAPI_S390_TYPES_H */
+9 -6
arch/s390/include/uapi/asm/ucontext.h
··· 7 7 #ifndef _ASM_S390_UCONTEXT_H 8 8 #define _ASM_S390_UCONTEXT_H 9 9 10 - #define UC_EXTENDED 0x00000001 10 + #define UC_GPRS_HIGH 1 /* uc_mcontext_ext has valid high gprs */ 11 + #define UC_VXRS 2 /* uc_mcontext_ext has valid vector regs */ 11 12 12 - #ifndef __s390x__ 13 - 13 + /* 14 + * The struct ucontext_extended describes how the registers are stored 15 + * on a rt signal frame. Please note that the structure is not fixed, 16 + * if new CPU registers are added to the user state the size of the 17 + * struct ucontext_extended will increase. 18 + */ 14 19 struct ucontext_extended { 15 20 unsigned long uc_flags; 16 21 struct ucontext *uc_link; ··· 24 19 sigset_t uc_sigmask; 25 20 /* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */ 26 21 unsigned char __unused[128 - sizeof(sigset_t)]; 27 - unsigned long uc_gprs_high[16]; 22 + _sigregs_ext uc_mcontext_ext; 28 23 }; 29 - 30 - #endif 31 24 32 25 struct ucontext { 33 26 unsigned long uc_flags;
+9
arch/s390/kernel/compat_linux.h
··· 50 50 _s390_fp_regs32 fpregs; 51 51 } _sigregs32; 52 52 53 + typedef struct 54 + { 55 + __u32 gprs_high[__NUM_GPRS]; 56 + __u64 vxrs_low[__NUM_VXRS_LOW]; 57 + __vector128 vxrs_high[__NUM_VXRS_HIGH]; 58 + __u8 __reserved[128]; 59 + } _sigregs_ext32; 60 + 53 61 #define _SIGCONTEXT_NSIG32 64 54 62 #define _SIGCONTEXT_NSIG_BPW32 32 55 63 #define __SIGNAL_FRAMESIZE32 96 ··· 80 72 compat_sigset_t uc_sigmask; 81 73 /* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */ 82 74 unsigned char __unused[128 - sizeof(compat_sigset_t)]; 75 + _sigregs_ext32 uc_mcontext_ext; 83 76 }; 84 77 85 78 struct stat64_emu31;
+174 -68
arch/s390/kernel/compat_signal.c
··· 36 36 struct sigcontext32 sc; 37 37 _sigregs32 sregs; 38 38 int signo; 39 - __u32 gprs_high[NUM_GPRS]; 40 - __u8 retcode[S390_SYSCALL_SIZE]; 39 + _sigregs_ext32 sregs_ext; 40 + __u16 svc_insn; /* Offset of svc_insn is NOT fixed! */ 41 41 } sigframe32; 42 42 43 43 typedef struct 44 44 { 45 45 __u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; 46 - __u8 retcode[S390_SYSCALL_SIZE]; 46 + __u16 svc_insn; 47 47 compat_siginfo_t info; 48 48 struct ucontext32 uc; 49 - __u32 gprs_high[NUM_GPRS]; 50 49 } rt_sigframe32; 51 50 52 51 int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) ··· 150 151 return err ? -EFAULT : 0; 151 152 } 152 153 154 + /* Store registers needed to create the signal frame */ 155 + static void store_sigregs(void) 156 + { 157 + int i; 158 + 159 + save_access_regs(current->thread.acrs); 160 + save_fp_ctl(&current->thread.fp_regs.fpc); 161 + if (current->thread.vxrs) { 162 + save_vx_regs(current->thread.vxrs); 163 + for (i = 0; i < __NUM_FPRS; i++) 164 + current->thread.fp_regs.fprs[i] = 165 + *(freg_t *)(current->thread.vxrs + i); 166 + } else 167 + save_fp_regs(current->thread.fp_regs.fprs); 168 + } 169 + 170 + /* Load registers after signal return */ 171 + static void load_sigregs(void) 172 + { 173 + int i; 174 + 175 + restore_access_regs(current->thread.acrs); 176 + /* restore_fp_ctl is done in restore_sigregs */ 177 + if (current->thread.vxrs) { 178 + for (i = 0; i < __NUM_FPRS; i++) 179 + *(freg_t *)(current->thread.vxrs + i) = 180 + current->thread.fp_regs.fprs[i]; 181 + restore_vx_regs(current->thread.vxrs); 182 + } else 183 + restore_fp_regs(current->thread.fp_regs.fprs); 184 + } 185 + 153 186 static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs) 154 187 { 155 188 _sigregs32 user_sregs; ··· 194 163 (__u32)(regs->psw.mask & PSW_MASK_BA); 195 164 for (i = 0; i < NUM_GPRS; i++) 196 165 user_sregs.regs.gprs[i] = (__u32) regs->gprs[i]; 197 - save_access_regs(current->thread.acrs); 198 166 memcpy(&user_sregs.regs.acrs, current->thread.acrs, 199 167 sizeof(user_sregs.regs.acrs)); 200 - save_fp_ctl(&current->thread.fp_regs.fpc); 201 - save_fp_regs(current->thread.fp_regs.fprs); 202 168 memcpy(&user_sregs.fpregs, &current->thread.fp_regs, 203 169 sizeof(user_sregs.fpregs)); 204 170 if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs32))) ··· 235 207 regs->gprs[i] = (__u64) user_sregs.regs.gprs[i]; 236 208 memcpy(&current->thread.acrs, &user_sregs.regs.acrs, 237 209 sizeof(current->thread.acrs)); 238 - restore_access_regs(current->thread.acrs); 239 210 240 211 memcpy(&current->thread.fp_regs, &user_sregs.fpregs, 241 212 sizeof(current->thread.fp_regs)); 242 213 243 - restore_fp_regs(current->thread.fp_regs.fprs); 244 214 clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */ 245 215 return 0; 246 216 } 247 217 248 - static int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs) 218 + static int save_sigregs_ext32(struct pt_regs *regs, 219 + _sigregs_ext32 __user *sregs_ext) 249 220 { 250 221 __u32 gprs_high[NUM_GPRS]; 222 + __u64 vxrs[__NUM_VXRS_LOW]; 251 223 int i; 252 224 225 + /* Save high gprs to signal stack */ 253 226 for (i = 0; i < NUM_GPRS; i++) 254 227 gprs_high[i] = regs->gprs[i] >> 32; 255 - if (__copy_to_user(uregs, &gprs_high, sizeof(gprs_high))) 228 + if (__copy_to_user(&sregs_ext->gprs_high, &gprs_high, 229 + sizeof(sregs_ext->gprs_high))) 256 230 return -EFAULT; 231 + 232 + /* Save vector registers to signal stack */ 233 + if (current->thread.vxrs) { 234 + for (i = 0; i < __NUM_VXRS_LOW; i++) 235 + vxrs[i] = *((__u64 *)(current->thread.vxrs + i) + 1); 236 + if (__copy_to_user(&sregs_ext->vxrs_low, vxrs, 237 + sizeof(sregs_ext->vxrs_low)) || 238 + __copy_to_user(&sregs_ext->vxrs_high, 239 + current->thread.vxrs + __NUM_VXRS_LOW, 240 + sizeof(sregs_ext->vxrs_high))) 241 + return -EFAULT; 242 + } 257 243 return 0; 258 244 } 259 245 260 - static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs) 246 + static int restore_sigregs_ext32(struct pt_regs *regs, 247 + _sigregs_ext32 __user *sregs_ext) 261 248 { 262 249 __u32 gprs_high[NUM_GPRS]; 250 + __u64 vxrs[__NUM_VXRS_LOW]; 263 251 int i; 264 252 265 - if (__copy_from_user(&gprs_high, uregs, sizeof(gprs_high))) 253 + /* Restore high gprs from signal stack */ 254 + if (__copy_from_user(&gprs_high, &sregs_ext->gprs_high, 255 + sizeof(&sregs_ext->gprs_high))) 266 256 return -EFAULT; 267 257 for (i = 0; i < NUM_GPRS; i++) 268 258 *(__u32 *)&regs->gprs[i] = gprs_high[i]; 259 + 260 + /* Restore vector registers from signal stack */ 261 + if (current->thread.vxrs) { 262 + if (__copy_from_user(vxrs, &sregs_ext->vxrs_low, 263 + sizeof(sregs_ext->vxrs_low)) || 264 + __copy_from_user(current->thread.vxrs + __NUM_VXRS_LOW, 265 + &sregs_ext->vxrs_high, 266 + sizeof(sregs_ext->vxrs_high))) 267 + return -EFAULT; 268 + for (i = 0; i < __NUM_VXRS_LOW; i++) 269 + *((__u64 *)(current->thread.vxrs + i) + 1) = vxrs[i]; 270 + } 269 271 return 0; 270 272 } 271 273 ··· 310 252 set_current_blocked(&set); 311 253 if (restore_sigregs32(regs, &frame->sregs)) 312 254 goto badframe; 313 - if (restore_sigregs_gprs_high(regs, frame->gprs_high)) 255 + if (restore_sigregs_ext32(regs, &frame->sregs_ext)) 314 256 goto badframe; 257 + load_sigregs(); 315 258 return regs->gprs[2]; 316 259 badframe: 317 260 force_sig(SIGSEGV, current); ··· 328 269 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) 329 270 goto badframe; 330 271 set_current_blocked(&set); 272 + if (compat_restore_altstack(&frame->uc.uc_stack)) 273 + goto badframe; 331 274 if (restore_sigregs32(regs, &frame->uc.uc_mcontext)) 332 275 goto badframe; 333 - if (restore_sigregs_gprs_high(regs, frame->gprs_high)) 276 + if (restore_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext)) 334 277 goto badframe; 335 - if (compat_restore_altstack(&frame->uc.uc_stack)) 336 - goto badframe; 278 + load_sigregs(); 337 279 return regs->gprs[2]; 338 280 badframe: 339 281 force_sig(SIGSEGV, current); ··· 384 324 struct pt_regs *regs) 385 325 { 386 326 int sig = ksig->sig; 387 - sigframe32 __user *frame = get_sigframe(&ksig->ka, regs, sizeof(sigframe32)); 327 + sigframe32 __user *frame; 328 + struct sigcontext32 sc; 329 + unsigned long restorer; 330 + size_t frame_size; 388 331 332 + /* 333 + * gprs_high are always present for 31-bit compat tasks. 334 + * The space for vector registers is only allocated if 335 + * the machine supports it 336 + */ 337 + frame_size = sizeof(*frame) - sizeof(frame->sregs_ext.__reserved); 338 + if (!MACHINE_HAS_VX) 339 + frame_size -= sizeof(frame->sregs_ext.vxrs_low) + 340 + sizeof(frame->sregs_ext.vxrs_high); 341 + frame = get_sigframe(&ksig->ka, regs, frame_size); 389 342 if (frame == (void __user *) -1UL) 390 343 return -EFAULT; 391 - 392 - if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32)) 393 - return -EFAULT; 394 - 395 - if (save_sigregs32(regs, &frame->sregs)) 396 - return -EFAULT; 397 - if (save_sigregs_gprs_high(regs, frame->gprs_high)) 398 - return -EFAULT; 399 - if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs)) 400 - return -EFAULT; 401 - 402 - /* Set up to return from userspace. If provided, use a stub 403 - already in userspace. */ 404 - if (ksig->ka.sa.sa_flags & SA_RESTORER) { 405 - regs->gprs[14] = (__u64 __force) ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE; 406 - } else { 407 - regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE; 408 - if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, 409 - (u16 __force __user *)(frame->retcode))) 410 - return -EFAULT; 411 - } 412 344 413 345 /* Set up backchain. */ 414 346 if (__put_user(regs->gprs[15], (unsigned int __user *) frame)) 415 347 return -EFAULT; 416 348 349 + /* Create struct sigcontext32 on the signal stack */ 350 + memcpy(&sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32); 351 + sc.sregs = (__u32)(unsigned long __force) &frame->sregs; 352 + if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc))) 353 + return -EFAULT; 354 + 355 + /* Store registers needed to create the signal frame */ 356 + store_sigregs(); 357 + 358 + /* Create _sigregs32 on the signal stack */ 359 + if (save_sigregs32(regs, &frame->sregs)) 360 + return -EFAULT; 361 + 362 + /* Place signal number on stack to allow backtrace from handler. */ 363 + if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo)) 364 + return -EFAULT; 365 + 366 + /* Create _sigregs_ext32 on the signal stack */ 367 + if (save_sigregs_ext32(regs, &frame->sregs_ext)) 368 + return -EFAULT; 369 + 370 + /* Set up to return from userspace. If provided, use a stub 371 + already in userspace. */ 372 + if (ksig->ka.sa.sa_flags & SA_RESTORER) { 373 + restorer = (unsigned long __force) 374 + ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE; 375 + } else { 376 + /* Signal frames without vectors registers are short ! */ 377 + __u16 __user *svc = (void *) frame + frame_size - 2; 378 + if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) 379 + return -EFAULT; 380 + restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE; 381 + } 382 + 417 383 /* Set up registers for signal handler */ 384 + regs->gprs[14] = restorer; 418 385 regs->gprs[15] = (__force __u64) frame; 419 386 /* Force 31 bit amode and default user address space control. */ 420 387 regs->psw.mask = PSW_MASK_BA | ··· 462 375 regs->gprs[6] = task_thread_info(current)->last_break; 463 376 } 464 377 465 - /* Place signal number on stack to allow backtrace from handler. */ 466 - if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo)) 467 - return -EFAULT; 468 378 return 0; 469 379 } 470 380 471 381 static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set, 472 382 struct pt_regs *regs) 473 383 { 474 - int err = 0; 475 - rt_sigframe32 __user *frame = get_sigframe(&ksig->ka, regs, sizeof(rt_sigframe32)); 384 + rt_sigframe32 __user *frame; 385 + unsigned long restorer; 386 + size_t frame_size; 387 + u32 uc_flags; 476 388 389 + frame_size = sizeof(*frame) - 390 + sizeof(frame->uc.uc_mcontext_ext.__reserved); 391 + /* 392 + * gprs_high are always present for 31-bit compat tasks. 393 + * The space for vector registers is only allocated if 394 + * the machine supports it 395 + */ 396 + uc_flags = UC_GPRS_HIGH; 397 + if (MACHINE_HAS_VX) { 398 + if (current->thread.vxrs) 399 + uc_flags |= UC_VXRS; 400 + } else 401 + frame_size -= sizeof(frame->uc.uc_mcontext_ext.vxrs_low) + 402 + sizeof(frame->uc.uc_mcontext_ext.vxrs_high); 403 + frame = get_sigframe(&ksig->ka, regs, frame_size); 477 404 if (frame == (void __user *) -1UL) 478 405 return -EFAULT; 479 - 480 - if (copy_siginfo_to_user32(&frame->info, &ksig->info)) 481 - return -EFAULT; 482 - 483 - /* Create the ucontext. */ 484 - err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags); 485 - err |= __put_user(0, &frame->uc.uc_link); 486 - err |= __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]); 487 - err |= save_sigregs32(regs, &frame->uc.uc_mcontext); 488 - err |= save_sigregs_gprs_high(regs, frame->gprs_high); 489 - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 490 - if (err) 491 - return -EFAULT; 492 - 493 - /* Set up to return from userspace. If provided, use a stub 494 - already in userspace. */ 495 - if (ksig->ka.sa.sa_flags & SA_RESTORER) { 496 - regs->gprs[14] = (__u64 __force) ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE; 497 - } else { 498 - regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE; 499 - if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, 500 - (u16 __force __user *)(frame->retcode))) 501 - return -EFAULT; 502 - } 503 406 504 407 /* Set up backchain. */ 505 408 if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame)) 506 409 return -EFAULT; 507 410 411 + /* Set up to return from userspace. If provided, use a stub 412 + already in userspace. */ 413 + if (ksig->ka.sa.sa_flags & SA_RESTORER) { 414 + restorer = (unsigned long __force) 415 + ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE; 416 + } else { 417 + __u16 __user *svc = &frame->svc_insn; 418 + if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, svc)) 419 + return -EFAULT; 420 + restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE; 421 + } 422 + 423 + /* Create siginfo on the signal stack */ 424 + if (copy_siginfo_to_user32(&frame->info, &ksig->info)) 425 + return -EFAULT; 426 + 427 + /* Store registers needed to create the signal frame */ 428 + store_sigregs(); 429 + 430 + /* Create ucontext on the signal stack. */ 431 + if (__put_user(uc_flags, &frame->uc.uc_flags) || 432 + __put_user(0, &frame->uc.uc_link) || 433 + __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]) || 434 + save_sigregs32(regs, &frame->uc.uc_mcontext) || 435 + __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)) || 436 + save_sigregs_ext32(regs, &frame->uc.uc_mcontext_ext)) 437 + return -EFAULT; 438 + 508 439 /* Set up registers for signal handler */ 440 + regs->gprs[14] = restorer; 509 441 regs->gprs[15] = (__force __u64) frame; 510 442 /* Force 31 bit amode and default user address space control. */ 511 443 regs->psw.mask = PSW_MASK_BA |
+2
arch/s390/kernel/early.c
··· 392 392 S390_lowcore.machine_flags |= MACHINE_FLAG_TE; 393 393 if (test_facility(51)) 394 394 S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC; 395 + if (test_facility(129)) 396 + S390_lowcore.machine_flags |= MACHINE_FLAG_VX; 395 397 #endif 396 398 } 397 399
+3
arch/s390/kernel/entry.h
··· 21 21 asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); 22 22 asmlinkage void do_syscall_trace_exit(struct pt_regs *regs); 23 23 24 + int alloc_vector_registers(struct task_struct *tsk); 25 + 24 26 void do_protection_exception(struct pt_regs *regs); 25 27 void do_dat_exception(struct pt_regs *regs); 26 28 ··· 45 43 void specification_exception(struct pt_regs *regs); 46 44 void transaction_exception(struct pt_regs *regs); 47 45 void translation_exception(struct pt_regs *regs); 46 + void vector_exception(struct pt_regs *regs); 48 47 49 48 void do_per_trap(struct pt_regs *regs); 50 49 void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str);
+16
arch/s390/kernel/nmi.c
··· 20 20 #include <asm/cputime.h> 21 21 #include <asm/nmi.h> 22 22 #include <asm/crw.h> 23 + #include <asm/switch_to.h> 23 24 24 25 struct mcck_struct { 25 26 int kill_task; ··· 164 163 " ld 15,120(%0)\n" 165 164 : : "a" (fpt_save_area)); 166 165 } 166 + 167 + #ifdef CONFIG_64BIT 168 + /* Revalidate vector registers */ 169 + if (MACHINE_HAS_VX && current->thread.vxrs) { 170 + if (!mci->vr) { 171 + /* 172 + * Vector registers can't be restored and therefore 173 + * the process needs to be terminated. 174 + */ 175 + kill_task = 1; 176 + } 177 + restore_vx_regs((__vector128 *) 178 + S390_lowcore.vector_save_area_addr); 179 + } 180 + #endif 167 181 /* Revalidate access registers */ 168 182 asm volatile( 169 183 " lam 0,15,0(%0)"
+1 -1
arch/s390/kernel/pgm_check.S
··· 49 49 PGM_CHECK_64BIT(transaction_exception) /* 18 */ 50 50 PGM_CHECK_DEFAULT /* 19 */ 51 51 PGM_CHECK_DEFAULT /* 1a */ 52 - PGM_CHECK_DEFAULT /* 1b */ 52 + PGM_CHECK_64BIT(vector_exception) /* 1b */ 53 53 PGM_CHECK(space_switch_exception) /* 1c */ 54 54 PGM_CHECK(hfp_sqrt_exception) /* 1d */ 55 55 PGM_CHECK_DEFAULT /* 1e */
+1 -1
arch/s390/kernel/processor.c
··· 39 39 { 40 40 static const char *hwcap_str[] = { 41 41 "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", 42 - "edat", "etf3eh", "highgprs", "te" 42 + "edat", "etf3eh", "highgprs", "te", "vx" 43 43 }; 44 44 unsigned long n = (unsigned long) v - 1; 45 45 int i;
+216 -69
arch/s390/kernel/ptrace.c
··· 38 38 #define CREATE_TRACE_POINTS 39 39 #include <trace/events/syscalls.h> 40 40 41 - enum s390_regset { 42 - REGSET_GENERAL, 43 - REGSET_FP, 44 - REGSET_LAST_BREAK, 45 - REGSET_TDB, 46 - REGSET_SYSTEM_CALL, 47 - REGSET_GENERAL_EXTENDED, 48 - }; 49 - 50 41 void update_cr_regs(struct task_struct *task) 51 42 { 52 43 struct pt_regs *regs = task_pt_regs(task); ··· 46 55 47 56 #ifdef CONFIG_64BIT 48 57 /* Take care of the enable/disable of transactional execution. */ 49 - if (MACHINE_HAS_TE) { 58 + if (MACHINE_HAS_TE || MACHINE_HAS_VX) { 50 59 unsigned long cr, cr_new; 51 60 52 61 __ctl_store(cr, 0, 0); 53 - /* Set or clear transaction execution TXC bit 8. */ 54 - cr_new = cr | (1UL << 55); 55 - 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); 59 - /* Set or clear transaction execution TDC bits 62 and 63. */ 60 - __ctl_store(cr, 2, 2); 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_TEND) 64 - cr_new |= 1UL; 65 - else 66 - cr_new |= 2UL; 62 + cr_new = cr; 63 + if (MACHINE_HAS_TE) { 64 + /* Set or clear transaction execution TXC bit 8. */ 65 + cr_new |= (1UL << 55); 66 + if (task->thread.per_flags & PER_FLAG_NO_TE) 67 + cr_new &= ~(1UL << 55); 68 + } 69 + if (MACHINE_HAS_VX) { 70 + /* Enable/disable of vector extension */ 71 + cr_new &= ~(1UL << 17); 72 + if (task->thread.vxrs) 73 + cr_new |= (1UL << 17); 67 74 } 68 75 if (cr_new != cr) 69 - __ctl_load(cr_new, 2, 2); 76 + __ctl_load(cr_new, 0, 0); 77 + if (MACHINE_HAS_TE) { 78 + /* Set/clear transaction execution TDC bits 62/63. */ 79 + __ctl_store(cr, 2, 2); 80 + cr_new = cr & ~3UL; 81 + if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) { 82 + if (task->thread.per_flags & 83 + PER_FLAG_TE_ABORT_RAND_TEND) 84 + cr_new |= 1UL; 85 + else 86 + cr_new |= 2UL; 87 + } 88 + if (cr_new != cr) 89 + __ctl_load(cr_new, 2, 2); 90 + } 70 91 } 71 92 #endif 72 93 /* Copy user specified PER registers */ ··· 929 926 save_fp_ctl(&target->thread.fp_regs.fpc); 930 927 save_fp_regs(target->thread.fp_regs.fprs); 931 928 } 929 + #ifdef CONFIG_64BIT 930 + else if (target->thread.vxrs) { 931 + int i; 932 932 933 + for (i = 0; i < __NUM_VXRS_LOW; i++) 934 + target->thread.fp_regs.fprs[i] = 935 + *(freg_t *)(target->thread.vxrs + i); 936 + } 937 + #endif 933 938 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, 934 939 &target->thread.fp_regs, 0, -1); 935 940 } ··· 971 960 target->thread.fp_regs.fprs, 972 961 offsetof(s390_fp_regs, fprs), -1); 973 962 974 - if (rc == 0 && target == current) { 975 - restore_fp_ctl(&target->thread.fp_regs.fpc); 976 - restore_fp_regs(target->thread.fp_regs.fprs); 963 + if (rc == 0) { 964 + if (target == current) { 965 + restore_fp_ctl(&target->thread.fp_regs.fpc); 966 + restore_fp_regs(target->thread.fp_regs.fprs); 967 + } 968 + #ifdef CONFIG_64BIT 969 + else if (target->thread.vxrs) { 970 + int i; 971 + 972 + for (i = 0; i < __NUM_VXRS_LOW; i++) 973 + *(freg_t *)(target->thread.vxrs + i) = 974 + target->thread.fp_regs.fprs[i]; 975 + } 976 + #endif 977 977 } 978 978 979 979 return rc; ··· 1040 1018 return 0; 1041 1019 } 1042 1020 1021 + static int s390_vxrs_active(struct task_struct *target, 1022 + const struct user_regset *regset) 1023 + { 1024 + return !!target->thread.vxrs; 1025 + } 1026 + 1027 + static int s390_vxrs_low_get(struct task_struct *target, 1028 + const struct user_regset *regset, 1029 + unsigned int pos, unsigned int count, 1030 + void *kbuf, void __user *ubuf) 1031 + { 1032 + __u64 vxrs[__NUM_VXRS_LOW]; 1033 + int i; 1034 + 1035 + if (target->thread.vxrs) { 1036 + if (target == current) 1037 + save_vx_regs(target->thread.vxrs); 1038 + for (i = 0; i < __NUM_VXRS_LOW; i++) 1039 + vxrs[i] = *((__u64 *)(target->thread.vxrs + i) + 1); 1040 + } else 1041 + memset(vxrs, 0, sizeof(vxrs)); 1042 + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1); 1043 + } 1044 + 1045 + static int s390_vxrs_low_set(struct task_struct *target, 1046 + const struct user_regset *regset, 1047 + unsigned int pos, unsigned int count, 1048 + const void *kbuf, const void __user *ubuf) 1049 + { 1050 + __u64 vxrs[__NUM_VXRS_LOW]; 1051 + int i, rc; 1052 + 1053 + if (!target->thread.vxrs) { 1054 + rc = alloc_vector_registers(target); 1055 + if (rc) 1056 + return rc; 1057 + } else if (target == current) 1058 + save_vx_regs(target->thread.vxrs); 1059 + 1060 + rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1); 1061 + if (rc == 0) { 1062 + for (i = 0; i < __NUM_VXRS_LOW; i++) 1063 + *((__u64 *)(target->thread.vxrs + i) + 1) = vxrs[i]; 1064 + if (target == current) 1065 + restore_vx_regs(target->thread.vxrs); 1066 + } 1067 + 1068 + return rc; 1069 + } 1070 + 1071 + static int s390_vxrs_high_get(struct task_struct *target, 1072 + const struct user_regset *regset, 1073 + unsigned int pos, unsigned int count, 1074 + void *kbuf, void __user *ubuf) 1075 + { 1076 + __vector128 vxrs[__NUM_VXRS_HIGH]; 1077 + 1078 + if (target->thread.vxrs) { 1079 + if (target == current) 1080 + save_vx_regs(target->thread.vxrs); 1081 + memcpy(vxrs, target->thread.vxrs + __NUM_VXRS_LOW, 1082 + sizeof(vxrs)); 1083 + } else 1084 + memset(vxrs, 0, sizeof(vxrs)); 1085 + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1); 1086 + } 1087 + 1088 + static int s390_vxrs_high_set(struct task_struct *target, 1089 + const struct user_regset *regset, 1090 + unsigned int pos, unsigned int count, 1091 + const void *kbuf, const void __user *ubuf) 1092 + { 1093 + int rc; 1094 + 1095 + if (!target->thread.vxrs) { 1096 + rc = alloc_vector_registers(target); 1097 + if (rc) 1098 + return rc; 1099 + } else if (target == current) 1100 + save_vx_regs(target->thread.vxrs); 1101 + 1102 + rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, 1103 + target->thread.vxrs + __NUM_VXRS_LOW, 0, -1); 1104 + if (rc == 0 && target == current) 1105 + restore_vx_regs(target->thread.vxrs); 1106 + 1107 + return rc; 1108 + } 1109 + 1043 1110 #endif 1044 1111 1045 1112 static int s390_system_call_get(struct task_struct *target, ··· 1152 1041 } 1153 1042 1154 1043 static const struct user_regset s390_regsets[] = { 1155 - [REGSET_GENERAL] = { 1044 + { 1156 1045 .core_note_type = NT_PRSTATUS, 1157 1046 .n = sizeof(s390_regs) / sizeof(long), 1158 1047 .size = sizeof(long), ··· 1160 1049 .get = s390_regs_get, 1161 1050 .set = s390_regs_set, 1162 1051 }, 1163 - [REGSET_FP] = { 1052 + { 1164 1053 .core_note_type = NT_PRFPREG, 1165 1054 .n = sizeof(s390_fp_regs) / sizeof(long), 1166 1055 .size = sizeof(long), ··· 1168 1057 .get = s390_fpregs_get, 1169 1058 .set = s390_fpregs_set, 1170 1059 }, 1171 - #ifdef CONFIG_64BIT 1172 - [REGSET_LAST_BREAK] = { 1173 - .core_note_type = NT_S390_LAST_BREAK, 1174 - .n = 1, 1175 - .size = sizeof(long), 1176 - .align = sizeof(long), 1177 - .get = s390_last_break_get, 1178 - .set = s390_last_break_set, 1179 - }, 1180 - [REGSET_TDB] = { 1181 - .core_note_type = NT_S390_TDB, 1182 - .n = 1, 1183 - .size = 256, 1184 - .align = 1, 1185 - .get = s390_tdb_get, 1186 - .set = s390_tdb_set, 1187 - }, 1188 - #endif 1189 - [REGSET_SYSTEM_CALL] = { 1060 + { 1190 1061 .core_note_type = NT_S390_SYSTEM_CALL, 1191 1062 .n = 1, 1192 1063 .size = sizeof(unsigned int), ··· 1176 1083 .get = s390_system_call_get, 1177 1084 .set = s390_system_call_set, 1178 1085 }, 1086 + #ifdef CONFIG_64BIT 1087 + { 1088 + .core_note_type = NT_S390_LAST_BREAK, 1089 + .n = 1, 1090 + .size = sizeof(long), 1091 + .align = sizeof(long), 1092 + .get = s390_last_break_get, 1093 + .set = s390_last_break_set, 1094 + }, 1095 + { 1096 + .core_note_type = NT_S390_TDB, 1097 + .n = 1, 1098 + .size = 256, 1099 + .align = 1, 1100 + .get = s390_tdb_get, 1101 + .set = s390_tdb_set, 1102 + }, 1103 + { 1104 + .core_note_type = NT_S390_VXRS_LOW, 1105 + .n = __NUM_VXRS_LOW, 1106 + .size = sizeof(__u64), 1107 + .align = sizeof(__u64), 1108 + .active = s390_vxrs_active, 1109 + .get = s390_vxrs_low_get, 1110 + .set = s390_vxrs_low_set, 1111 + }, 1112 + { 1113 + .core_note_type = NT_S390_VXRS_HIGH, 1114 + .n = __NUM_VXRS_HIGH, 1115 + .size = sizeof(__vector128), 1116 + .align = sizeof(__vector128), 1117 + .active = s390_vxrs_active, 1118 + .get = s390_vxrs_high_get, 1119 + .set = s390_vxrs_high_set, 1120 + }, 1121 + #endif 1179 1122 }; 1180 1123 1181 1124 static const struct user_regset_view user_s390_view = { ··· 1376 1247 } 1377 1248 1378 1249 static const struct user_regset s390_compat_regsets[] = { 1379 - [REGSET_GENERAL] = { 1250 + { 1380 1251 .core_note_type = NT_PRSTATUS, 1381 1252 .n = sizeof(s390_compat_regs) / sizeof(compat_long_t), 1382 1253 .size = sizeof(compat_long_t), ··· 1384 1255 .get = s390_compat_regs_get, 1385 1256 .set = s390_compat_regs_set, 1386 1257 }, 1387 - [REGSET_FP] = { 1258 + { 1388 1259 .core_note_type = NT_PRFPREG, 1389 1260 .n = sizeof(s390_fp_regs) / sizeof(compat_long_t), 1390 1261 .size = sizeof(compat_long_t), ··· 1392 1263 .get = s390_fpregs_get, 1393 1264 .set = s390_fpregs_set, 1394 1265 }, 1395 - [REGSET_LAST_BREAK] = { 1396 - .core_note_type = NT_S390_LAST_BREAK, 1397 - .n = 1, 1398 - .size = sizeof(long), 1399 - .align = sizeof(long), 1400 - .get = s390_compat_last_break_get, 1401 - .set = s390_compat_last_break_set, 1402 - }, 1403 - [REGSET_TDB] = { 1404 - .core_note_type = NT_S390_TDB, 1405 - .n = 1, 1406 - .size = 256, 1407 - .align = 1, 1408 - .get = s390_tdb_get, 1409 - .set = s390_tdb_set, 1410 - }, 1411 - [REGSET_SYSTEM_CALL] = { 1266 + { 1412 1267 .core_note_type = NT_S390_SYSTEM_CALL, 1413 1268 .n = 1, 1414 1269 .size = sizeof(compat_uint_t), ··· 1400 1287 .get = s390_system_call_get, 1401 1288 .set = s390_system_call_set, 1402 1289 }, 1403 - [REGSET_GENERAL_EXTENDED] = { 1290 + { 1291 + .core_note_type = NT_S390_LAST_BREAK, 1292 + .n = 1, 1293 + .size = sizeof(long), 1294 + .align = sizeof(long), 1295 + .get = s390_compat_last_break_get, 1296 + .set = s390_compat_last_break_set, 1297 + }, 1298 + { 1299 + .core_note_type = NT_S390_TDB, 1300 + .n = 1, 1301 + .size = 256, 1302 + .align = 1, 1303 + .get = s390_tdb_get, 1304 + .set = s390_tdb_set, 1305 + }, 1306 + { 1307 + .core_note_type = NT_S390_VXRS_LOW, 1308 + .n = __NUM_VXRS_LOW, 1309 + .size = sizeof(__u64), 1310 + .align = sizeof(__u64), 1311 + .active = s390_vxrs_active, 1312 + .get = s390_vxrs_low_get, 1313 + .set = s390_vxrs_low_set, 1314 + }, 1315 + { 1316 + .core_note_type = NT_S390_VXRS_HIGH, 1317 + .n = __NUM_VXRS_HIGH, 1318 + .size = sizeof(__vector128), 1319 + .align = sizeof(__vector128), 1320 + .active = s390_vxrs_active, 1321 + .get = s390_vxrs_high_get, 1322 + .set = s390_vxrs_high_set, 1323 + }, 1324 + { 1404 1325 .core_note_type = NT_S390_HIGH_GPRS, 1405 1326 .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), 1406 1327 .size = sizeof(compat_long_t),
+9
arch/s390/kernel/setup.c
··· 343 343 __ctl_set_bit(14, 29); 344 344 } 345 345 #else 346 + if (MACHINE_HAS_VX) 347 + lc->vector_save_area_addr = 348 + (unsigned long) &lc->vector_save_area; 346 349 lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; 347 350 #endif 348 351 lc->sync_enter_timer = S390_lowcore.sync_enter_timer; ··· 768 765 */ 769 766 if (test_facility(50) && test_facility(73)) 770 767 elf_hwcap |= HWCAP_S390_TE; 768 + 769 + /* 770 + * Vector extension HWCAP_S390_VXRS is bit 11. 771 + */ 772 + if (test_facility(129)) 773 + elf_hwcap |= HWCAP_S390_VXRS; 771 774 #endif 772 775 773 776 get_cpu_id(&cpu_id);
+249 -83
arch/s390/kernel/signal.c
··· 31 31 #include <asm/switch_to.h> 32 32 #include "entry.h" 33 33 34 - typedef struct 34 + /* 35 + * Layout of an old-style signal-frame: 36 + * ----------------------------------------- 37 + * | save area (_SIGNAL_FRAMESIZE) | 38 + * ----------------------------------------- 39 + * | struct sigcontext | 40 + * | oldmask | 41 + * | _sigregs * | 42 + * ----------------------------------------- 43 + * | _sigregs with | 44 + * | _s390_regs_common | 45 + * | _s390_fp_regs | 46 + * ----------------------------------------- 47 + * | int signo | 48 + * ----------------------------------------- 49 + * | _sigregs_ext with | 50 + * | gprs_high 64 byte (opt) | 51 + * | vxrs_low 128 byte (opt) | 52 + * | vxrs_high 256 byte (opt) | 53 + * | reserved 128 byte (opt) | 54 + * ----------------------------------------- 55 + * | __u16 svc_insn | 56 + * ----------------------------------------- 57 + * The svc_insn entry with the sigreturn system call opcode does not 58 + * have a fixed position and moves if gprs_high or vxrs exist. 59 + * Future extensions will be added to _sigregs_ext. 60 + */ 61 + struct sigframe 35 62 { 36 63 __u8 callee_used_stack[__SIGNAL_FRAMESIZE]; 37 64 struct sigcontext sc; 38 65 _sigregs sregs; 39 66 int signo; 40 - __u8 retcode[S390_SYSCALL_SIZE]; 41 - } sigframe; 67 + _sigregs_ext sregs_ext; 68 + __u16 svc_insn; /* Offset of svc_insn is NOT fixed! */ 69 + }; 42 70 43 - typedef struct 71 + /* 72 + * Layout of an rt signal-frame: 73 + * ----------------------------------------- 74 + * | save area (_SIGNAL_FRAMESIZE) | 75 + * ----------------------------------------- 76 + * | svc __NR_rt_sigreturn 2 byte | 77 + * ----------------------------------------- 78 + * | struct siginfo | 79 + * ----------------------------------------- 80 + * | struct ucontext_extended with | 81 + * | unsigned long uc_flags | 82 + * | struct ucontext *uc_link | 83 + * | stack_t uc_stack | 84 + * | _sigregs uc_mcontext with | 85 + * | _s390_regs_common | 86 + * | _s390_fp_regs | 87 + * | sigset_t uc_sigmask | 88 + * | _sigregs_ext uc_mcontext_ext | 89 + * | gprs_high 64 byte (opt) | 90 + * | vxrs_low 128 byte (opt) | 91 + * | vxrs_high 256 byte (opt)| 92 + * | reserved 128 byte (opt) | 93 + * ----------------------------------------- 94 + * Future extensions will be added to _sigregs_ext. 95 + */ 96 + struct rt_sigframe 44 97 { 45 98 __u8 callee_used_stack[__SIGNAL_FRAMESIZE]; 46 - __u8 retcode[S390_SYSCALL_SIZE]; 99 + __u16 svc_insn; 47 100 struct siginfo info; 48 - struct ucontext uc; 49 - } rt_sigframe; 101 + struct ucontext_extended uc; 102 + }; 103 + 104 + /* Store registers needed to create the signal frame */ 105 + static void store_sigregs(void) 106 + { 107 + save_access_regs(current->thread.acrs); 108 + save_fp_ctl(&current->thread.fp_regs.fpc); 109 + #ifdef CONFIG_64BIT 110 + if (current->thread.vxrs) { 111 + int i; 112 + 113 + save_vx_regs(current->thread.vxrs); 114 + for (i = 0; i < __NUM_FPRS; i++) 115 + current->thread.fp_regs.fprs[i] = 116 + *(freg_t *)(current->thread.vxrs + i); 117 + } else 118 + #endif 119 + save_fp_regs(current->thread.fp_regs.fprs); 120 + } 121 + 122 + /* Load registers after signal return */ 123 + static void load_sigregs(void) 124 + { 125 + restore_access_regs(current->thread.acrs); 126 + /* restore_fp_ctl is done in restore_sigregs */ 127 + #ifdef CONFIG_64BIT 128 + if (current->thread.vxrs) { 129 + int i; 130 + 131 + for (i = 0; i < __NUM_FPRS; i++) 132 + *(freg_t *)(current->thread.vxrs + i) = 133 + current->thread.fp_regs.fprs[i]; 134 + restore_vx_regs(current->thread.vxrs); 135 + } else 136 + #endif 137 + restore_fp_regs(current->thread.fp_regs.fprs); 138 + } 50 139 51 140 /* Returns non-zero on fault. */ 52 141 static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) 53 142 { 54 143 _sigregs user_sregs; 55 - 56 - save_access_regs(current->thread.acrs); 57 144 58 145 /* Copy a 'clean' PSW mask to the user to avoid leaking 59 146 information about whether PER is currently on. */ ··· 150 63 memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs)); 151 64 memcpy(&user_sregs.regs.acrs, current->thread.acrs, 152 65 sizeof(user_sregs.regs.acrs)); 153 - /* 154 - * We have to store the fp registers to current->thread.fp_regs 155 - * to merge them with the emulated registers. 156 - */ 157 - save_fp_ctl(&current->thread.fp_regs.fpc); 158 - save_fp_regs(current->thread.fp_regs.fprs); 159 66 memcpy(&user_sregs.fpregs, &current->thread.fp_regs, 160 67 sizeof(user_sregs.fpregs)); 161 68 if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs))) ··· 188 107 memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs)); 189 108 memcpy(&current->thread.acrs, &user_sregs.regs.acrs, 190 109 sizeof(current->thread.acrs)); 191 - restore_access_regs(current->thread.acrs); 192 110 193 111 memcpy(&current->thread.fp_regs, &user_sregs.fpregs, 194 112 sizeof(current->thread.fp_regs)); 195 113 196 - restore_fp_regs(current->thread.fp_regs.fprs); 197 114 clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */ 115 + return 0; 116 + } 117 + 118 + /* Returns non-zero on fault. */ 119 + static int save_sigregs_ext(struct pt_regs *regs, 120 + _sigregs_ext __user *sregs_ext) 121 + { 122 + #ifdef CONFIG_64BIT 123 + __u64 vxrs[__NUM_VXRS_LOW]; 124 + int i; 125 + 126 + /* Save vector registers to signal stack */ 127 + if (current->thread.vxrs) { 128 + for (i = 0; i < __NUM_VXRS_LOW; i++) 129 + vxrs[i] = *((__u64 *)(current->thread.vxrs + i) + 1); 130 + if (__copy_to_user(&sregs_ext->vxrs_low, vxrs, 131 + sizeof(sregs_ext->vxrs_low)) || 132 + __copy_to_user(&sregs_ext->vxrs_high, 133 + current->thread.vxrs + __NUM_VXRS_LOW, 134 + sizeof(sregs_ext->vxrs_high))) 135 + return -EFAULT; 136 + } 137 + #endif 138 + return 0; 139 + } 140 + 141 + static int restore_sigregs_ext(struct pt_regs *regs, 142 + _sigregs_ext __user *sregs_ext) 143 + { 144 + #ifdef CONFIG_64BIT 145 + __u64 vxrs[__NUM_VXRS_LOW]; 146 + int i; 147 + 148 + /* Restore vector registers from signal stack */ 149 + if (current->thread.vxrs) { 150 + if (__copy_from_user(vxrs, &sregs_ext->vxrs_low, 151 + sizeof(sregs_ext->vxrs_low)) || 152 + __copy_from_user(current->thread.vxrs + __NUM_VXRS_LOW, 153 + &sregs_ext->vxrs_high, 154 + sizeof(sregs_ext->vxrs_high))) 155 + return -EFAULT; 156 + for (i = 0; i < __NUM_VXRS_LOW; i++) 157 + *((__u64 *)(current->thread.vxrs + i) + 1) = vxrs[i]; 158 + } 159 + #endif 198 160 return 0; 199 161 } 200 162 201 163 SYSCALL_DEFINE0(sigreturn) 202 164 { 203 165 struct pt_regs *regs = task_pt_regs(current); 204 - sigframe __user *frame = (sigframe __user *)regs->gprs[15]; 166 + struct sigframe __user *frame = 167 + (struct sigframe __user *) regs->gprs[15]; 205 168 sigset_t set; 206 169 207 170 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE)) ··· 253 128 set_current_blocked(&set); 254 129 if (restore_sigregs(regs, &frame->sregs)) 255 130 goto badframe; 131 + if (restore_sigregs_ext(regs, &frame->sregs_ext)) 132 + goto badframe; 133 + load_sigregs(); 256 134 return regs->gprs[2]; 257 135 badframe: 258 136 force_sig(SIGSEGV, current); ··· 265 137 SYSCALL_DEFINE0(rt_sigreturn) 266 138 { 267 139 struct pt_regs *regs = task_pt_regs(current); 268 - rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15]; 140 + struct rt_sigframe __user *frame = 141 + (struct rt_sigframe __user *)regs->gprs[15]; 269 142 sigset_t set; 270 143 271 144 if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set))) 272 145 goto badframe; 273 146 set_current_blocked(&set); 274 - if (restore_sigregs(regs, &frame->uc.uc_mcontext)) 275 - goto badframe; 276 147 if (restore_altstack(&frame->uc.uc_stack)) 277 148 goto badframe; 149 + if (restore_sigregs(regs, &frame->uc.uc_mcontext)) 150 + goto badframe; 151 + if (restore_sigregs_ext(regs, &frame->uc.uc_mcontext_ext)) 152 + goto badframe; 153 + load_sigregs(); 278 154 return regs->gprs[2]; 279 155 badframe: 280 156 force_sig(SIGSEGV, current); 281 157 return 0; 282 158 } 283 - 284 - /* 285 - * Set up a signal frame. 286 - */ 287 - 288 159 289 160 /* 290 161 * Determine which stack to use.. ··· 322 195 static int setup_frame(int sig, struct k_sigaction *ka, 323 196 sigset_t *set, struct pt_regs * regs) 324 197 { 325 - sigframe __user *frame; 198 + struct sigframe __user *frame; 199 + struct sigcontext sc; 200 + unsigned long restorer; 201 + size_t frame_size; 326 202 327 - frame = get_sigframe(ka, regs, sizeof(sigframe)); 328 - 203 + /* 204 + * gprs_high are only present for a 31-bit task running on 205 + * a 64-bit kernel (see compat_signal.c) but the space for 206 + * gprs_high need to be allocated if vector registers are 207 + * included in the signal frame on a 31-bit system. 208 + */ 209 + frame_size = sizeof(*frame) - sizeof(frame->sregs_ext); 210 + if (MACHINE_HAS_VX) 211 + frame_size += sizeof(frame->sregs_ext); 212 + frame = get_sigframe(ka, regs, frame_size); 329 213 if (frame == (void __user *) -1UL) 330 214 return -EFAULT; 331 - 332 - if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE)) 333 - return -EFAULT; 334 - 335 - if (save_sigregs(regs, &frame->sregs)) 336 - return -EFAULT; 337 - if (__put_user(&frame->sregs, &frame->sc.sregs)) 338 - return -EFAULT; 339 - 340 - /* Set up to return from userspace. If provided, use a stub 341 - already in userspace. */ 342 - if (ka->sa.sa_flags & SA_RESTORER) { 343 - regs->gprs[14] = (unsigned long) 344 - ka->sa.sa_restorer | PSW_ADDR_AMODE; 345 - } else { 346 - regs->gprs[14] = (unsigned long) 347 - frame->retcode | PSW_ADDR_AMODE; 348 - if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, 349 - (u16 __user *)(frame->retcode))) 350 - return -EFAULT; 351 - } 352 215 353 216 /* Set up backchain. */ 354 217 if (__put_user(regs->gprs[15], (addr_t __user *) frame)) 355 218 return -EFAULT; 356 219 220 + /* Create struct sigcontext on the signal stack */ 221 + memcpy(&sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE); 222 + sc.sregs = (_sigregs __user __force *) &frame->sregs; 223 + if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc))) 224 + return -EFAULT; 225 + 226 + /* Store registers needed to create the signal frame */ 227 + store_sigregs(); 228 + 229 + /* Create _sigregs on the signal stack */ 230 + if (save_sigregs(regs, &frame->sregs)) 231 + return -EFAULT; 232 + 233 + /* Place signal number on stack to allow backtrace from handler. */ 234 + if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) 235 + return -EFAULT; 236 + 237 + /* Create _sigregs_ext on the signal stack */ 238 + if (save_sigregs_ext(regs, &frame->sregs_ext)) 239 + return -EFAULT; 240 + 241 + /* Set up to return from userspace. If provided, use a stub 242 + already in userspace. */ 243 + if (ka->sa.sa_flags & SA_RESTORER) { 244 + restorer = (unsigned long) ka->sa.sa_restorer | PSW_ADDR_AMODE; 245 + } else { 246 + /* Signal frame without vector registers are short ! */ 247 + __u16 __user *svc = (void *) frame + frame_size - 2; 248 + if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) 249 + return -EFAULT; 250 + restorer = (unsigned long) svc | PSW_ADDR_AMODE; 251 + } 252 + 357 253 /* Set up registers for signal handler */ 254 + regs->gprs[14] = restorer; 358 255 regs->gprs[15] = (unsigned long) frame; 359 256 /* Force default amode and default user address space control. */ 360 257 regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA | ··· 398 247 regs->gprs[5] = regs->int_parm_long; 399 248 regs->gprs[6] = task_thread_info(current)->last_break; 400 249 } 401 - 402 - /* Place signal number on stack to allow backtrace from handler. */ 403 - if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) 404 - return -EFAULT; 405 250 return 0; 406 251 } 407 252 408 253 static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, 409 254 struct pt_regs *regs) 410 255 { 411 - int err = 0; 412 - rt_sigframe __user *frame; 256 + struct rt_sigframe __user *frame; 257 + unsigned long uc_flags, restorer; 258 + size_t frame_size; 413 259 414 - frame = get_sigframe(&ksig->ka, regs, sizeof(rt_sigframe)); 415 - 260 + frame_size = sizeof(struct rt_sigframe) - sizeof(_sigregs_ext); 261 + /* 262 + * gprs_high are only present for a 31-bit task running on 263 + * a 64-bit kernel (see compat_signal.c) but the space for 264 + * gprs_high need to be allocated if vector registers are 265 + * included in the signal frame on a 31-bit system. 266 + */ 267 + uc_flags = 0; 268 + #ifdef CONFIG_64BIT 269 + if (MACHINE_HAS_VX) { 270 + frame_size += sizeof(_sigregs_ext); 271 + if (current->thread.vxrs) 272 + uc_flags |= UC_VXRS; 273 + } 274 + #endif 275 + frame = get_sigframe(&ksig->ka, regs, frame_size); 416 276 if (frame == (void __user *) -1UL) 417 277 return -EFAULT; 418 - 419 - if (copy_siginfo_to_user(&frame->info, &ksig->info)) 420 - return -EFAULT; 421 - 422 - /* Create the ucontext. */ 423 - err |= __put_user(0, &frame->uc.uc_flags); 424 - err |= __put_user(NULL, &frame->uc.uc_link); 425 - err |= __save_altstack(&frame->uc.uc_stack, regs->gprs[15]); 426 - err |= save_sigregs(regs, &frame->uc.uc_mcontext); 427 - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); 428 - if (err) 429 - return -EFAULT; 430 - 431 - /* Set up to return from userspace. If provided, use a stub 432 - already in userspace. */ 433 - if (ksig->ka.sa.sa_flags & SA_RESTORER) { 434 - regs->gprs[14] = (unsigned long) 435 - ksig->ka.sa.sa_restorer | PSW_ADDR_AMODE; 436 - } else { 437 - regs->gprs[14] = (unsigned long) 438 - frame->retcode | PSW_ADDR_AMODE; 439 - if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, 440 - (u16 __user *)(frame->retcode))) 441 - return -EFAULT; 442 - } 443 278 444 279 /* Set up backchain. */ 445 280 if (__put_user(regs->gprs[15], (addr_t __user *) frame)) 446 281 return -EFAULT; 447 282 283 + /* Set up to return from userspace. If provided, use a stub 284 + already in userspace. */ 285 + if (ksig->ka.sa.sa_flags & SA_RESTORER) { 286 + restorer = (unsigned long) 287 + ksig->ka.sa.sa_restorer | PSW_ADDR_AMODE; 288 + } else { 289 + __u16 __user *svc = &frame->svc_insn; 290 + if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, svc)) 291 + return -EFAULT; 292 + restorer = (unsigned long) svc | PSW_ADDR_AMODE; 293 + } 294 + 295 + /* Create siginfo on the signal stack */ 296 + if (copy_siginfo_to_user(&frame->info, &ksig->info)) 297 + return -EFAULT; 298 + 299 + /* Store registers needed to create the signal frame */ 300 + store_sigregs(); 301 + 302 + /* Create ucontext on the signal stack. */ 303 + if (__put_user(uc_flags, &frame->uc.uc_flags) || 304 + __put_user(NULL, &frame->uc.uc_link) || 305 + __save_altstack(&frame->uc.uc_stack, regs->gprs[15]) || 306 + save_sigregs(regs, &frame->uc.uc_mcontext) || 307 + __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)) || 308 + save_sigregs_ext(regs, &frame->uc.uc_mcontext_ext)) 309 + return -EFAULT; 310 + 448 311 /* Set up registers for signal handler */ 312 + regs->gprs[14] = restorer; 449 313 regs->gprs[15] = (unsigned long) frame; 450 314 /* Force default amode and default user address space control. */ 451 315 regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
+3
arch/s390/kernel/smp.c
··· 179 179 goto out; 180 180 } 181 181 #else 182 + if (MACHINE_HAS_VX) 183 + lc->vector_save_area_addr = 184 + (unsigned long) &lc->vector_save_area; 182 185 if (vdso_alloc_per_cpu(lc)) 183 186 goto out; 184 187 #endif
+82
arch/s390/kernel/traps.c
··· 18 18 #include <linux/ptrace.h> 19 19 #include <linux/sched.h> 20 20 #include <linux/mm.h> 21 + #include <linux/slab.h> 22 + #include <asm/switch_to.h> 21 23 #include "entry.h" 22 24 23 25 int show_unhandled_signals = 1; ··· 305 303 "specification exception"); 306 304 #endif 307 305 306 + #ifdef CONFIG_64BIT 307 + int alloc_vector_registers(struct task_struct *tsk) 308 + { 309 + __vector128 *vxrs; 310 + int i; 311 + 312 + /* Allocate vector register save area. */ 313 + vxrs = kzalloc(sizeof(__vector128) * __NUM_VXRS, 314 + GFP_KERNEL|__GFP_REPEAT); 315 + if (!vxrs) 316 + return -ENOMEM; 317 + preempt_disable(); 318 + if (tsk == current) 319 + save_fp_regs(tsk->thread.fp_regs.fprs); 320 + /* Copy the 16 floating point registers */ 321 + for (i = 0; i < 16; i++) 322 + *(freg_t *) &vxrs[i] = tsk->thread.fp_regs.fprs[i]; 323 + tsk->thread.vxrs = vxrs; 324 + if (tsk == current) { 325 + __ctl_set_bit(0, 17); 326 + restore_vx_regs(vxrs); 327 + } 328 + preempt_enable(); 329 + return 0; 330 + } 331 + 332 + void vector_exception(struct pt_regs *regs) 333 + { 334 + int si_code, vic; 335 + 336 + if (!MACHINE_HAS_VX) { 337 + do_trap(regs, SIGILL, ILL_ILLOPN, "illegal operation"); 338 + return; 339 + } 340 + 341 + /* get vector interrupt code from fpc */ 342 + asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); 343 + vic = (current->thread.fp_regs.fpc & 0xf00) >> 8; 344 + switch (vic) { 345 + case 1: /* invalid vector operation */ 346 + si_code = FPE_FLTINV; 347 + break; 348 + case 2: /* division by zero */ 349 + si_code = FPE_FLTDIV; 350 + break; 351 + case 3: /* overflow */ 352 + si_code = FPE_FLTOVF; 353 + break; 354 + case 4: /* underflow */ 355 + si_code = FPE_FLTUND; 356 + break; 357 + case 5: /* inexact */ 358 + si_code = FPE_FLTRES; 359 + break; 360 + default: /* unknown cause */ 361 + si_code = 0; 362 + } 363 + do_trap(regs, SIGFPE, si_code, "vector exception"); 364 + } 365 + 366 + static int __init disable_vector_extension(char *str) 367 + { 368 + S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; 369 + return 1; 370 + } 371 + __setup("novx", disable_vector_extension); 372 + #endif 373 + 308 374 void data_exception(struct pt_regs *regs) 309 375 { 310 376 __u16 __user *location; ··· 438 368 } 439 369 } 440 370 #endif 371 + #ifdef CONFIG_64BIT 372 + /* Check for vector register enablement */ 373 + if (MACHINE_HAS_VX && !current->thread.vxrs && 374 + (current->thread.fp_regs.fpc & FPC_DXC_MASK) == 0xfe00) { 375 + alloc_vector_registers(current); 376 + /* Vector data exception is suppressing, rewind psw. */ 377 + regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16); 378 + clear_pt_regs_flag(regs, PIF_PER_TRAP); 379 + return; 380 + } 381 + #endif 382 + 441 383 if (current->thread.fp_regs.fpc & FPC_DXC_MASK) 442 384 signal = SIGFPE; 443 385 else
+2
include/uapi/linux/elf.h
··· 391 391 #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ 392 392 #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ 393 393 #define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ 394 + #define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */ 395 + #define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */ 394 396 #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ 395 397 #define NT_ARM_TLS 0x401 /* ARM TLS register */ 396 398 #define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */