diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/include/asm/elf.h | 12 | ||||
-rw-r--r-- | arch/s390/include/asm/ptrace.h | 4 | ||||
-rw-r--r-- | arch/s390/include/asm/ucontext.h | 15 | ||||
-rw-r--r-- | arch/s390/kernel/compat_signal.c | 35 | ||||
-rw-r--r-- | arch/s390/kernel/ptrace.c | 70 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 15 |
6 files changed, 147 insertions, 4 deletions
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 74d0bbb7d955..e885442c1dfe 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h | |||
@@ -92,6 +92,18 @@ | |||
92 | /* Keep this the last entry. */ | 92 | /* Keep this the last entry. */ |
93 | #define R_390_NUM 61 | 93 | #define R_390_NUM 61 |
94 | 94 | ||
95 | /* Bits present in AT_HWCAP. */ | ||
96 | #define HWCAP_S390_ESAN3 1 | ||
97 | #define HWCAP_S390_ZARCH 2 | ||
98 | #define HWCAP_S390_STFLE 4 | ||
99 | #define HWCAP_S390_MSA 8 | ||
100 | #define HWCAP_S390_LDISP 16 | ||
101 | #define HWCAP_S390_EIMM 32 | ||
102 | #define HWCAP_S390_DFP 64 | ||
103 | #define HWCAP_S390_HPAGE 128 | ||
104 | #define HWCAP_S390_ETF3EH 256 | ||
105 | #define HWCAP_S390_HIGH_GPRS 512 | ||
106 | |||
95 | /* | 107 | /* |
96 | * These are used to set parameters in the core dumps. | 108 | * These are used to set parameters in the core dumps. |
97 | */ | 109 | */ |
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 539263fc9ab9..95dcf183a28d 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
@@ -311,6 +311,10 @@ typedef struct | |||
311 | __u32 orig_gpr2; | 311 | __u32 orig_gpr2; |
312 | } s390_compat_regs; | 312 | } s390_compat_regs; |
313 | 313 | ||
314 | typedef struct | ||
315 | { | ||
316 | __u32 gprs_high[NUM_GPRS]; | ||
317 | } s390_compat_regs_high; | ||
314 | 318 | ||
315 | #ifdef __KERNEL__ | 319 | #ifdef __KERNEL__ |
316 | 320 | ||
diff --git a/arch/s390/include/asm/ucontext.h b/arch/s390/include/asm/ucontext.h index d69bec0b03f5..cfb874e66c9a 100644 --- a/arch/s390/include/asm/ucontext.h +++ b/arch/s390/include/asm/ucontext.h | |||
@@ -9,6 +9,21 @@ | |||
9 | #ifndef _ASM_S390_UCONTEXT_H | 9 | #ifndef _ASM_S390_UCONTEXT_H |
10 | #define _ASM_S390_UCONTEXT_H | 10 | #define _ASM_S390_UCONTEXT_H |
11 | 11 | ||
12 | #define UC_EXTENDED 0x00000001 | ||
13 | |||
14 | #ifndef __s390x__ | ||
15 | |||
16 | struct ucontext_extended { | ||
17 | unsigned long uc_flags; | ||
18 | struct ucontext *uc_link; | ||
19 | stack_t uc_stack; | ||
20 | _sigregs uc_mcontext; | ||
21 | unsigned long uc_sigmask[2]; | ||
22 | unsigned long uc_gprs_high[16]; | ||
23 | }; | ||
24 | |||
25 | #endif | ||
26 | |||
12 | struct ucontext { | 27 | struct ucontext { |
13 | unsigned long uc_flags; | 28 | unsigned long uc_flags; |
14 | struct ucontext *uc_link; | 29 | struct ucontext *uc_link; |
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index b537cb0e9b55..eee999853a7c 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c | |||
@@ -39,6 +39,7 @@ typedef struct | |||
39 | struct sigcontext32 sc; | 39 | struct sigcontext32 sc; |
40 | _sigregs32 sregs; | 40 | _sigregs32 sregs; |
41 | int signo; | 41 | int signo; |
42 | __u32 gprs_high[NUM_GPRS]; | ||
42 | __u8 retcode[S390_SYSCALL_SIZE]; | 43 | __u8 retcode[S390_SYSCALL_SIZE]; |
43 | } sigframe32; | 44 | } sigframe32; |
44 | 45 | ||
@@ -48,6 +49,7 @@ typedef struct | |||
48 | __u8 retcode[S390_SYSCALL_SIZE]; | 49 | __u8 retcode[S390_SYSCALL_SIZE]; |
49 | compat_siginfo_t info; | 50 | compat_siginfo_t info; |
50 | struct ucontext32 uc; | 51 | struct ucontext32 uc; |
52 | __u32 gprs_high[NUM_GPRS]; | ||
51 | } rt_sigframe32; | 53 | } rt_sigframe32; |
52 | 54 | ||
53 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) | 55 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) |
@@ -344,6 +346,30 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) | |||
344 | return 0; | 346 | return 0; |
345 | } | 347 | } |
346 | 348 | ||
349 | static int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs) | ||
350 | { | ||
351 | __u32 gprs_high[NUM_GPRS]; | ||
352 | int i; | ||
353 | |||
354 | for (i = 0; i < NUM_GPRS; i++) | ||
355 | gprs_high[i] = regs->gprs[i] >> 32; | ||
356 | |||
357 | return __copy_to_user(uregs, &gprs_high, sizeof(gprs_high)); | ||
358 | } | ||
359 | |||
360 | static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs) | ||
361 | { | ||
362 | __u32 gprs_high[NUM_GPRS]; | ||
363 | int err, i; | ||
364 | |||
365 | err = __copy_from_user(&gprs_high, uregs, sizeof(gprs_high)); | ||
366 | if (err) | ||
367 | return err; | ||
368 | for (i = 0; i < NUM_GPRS; i++) | ||
369 | *(__u32 *)®s->gprs[i] = gprs_high[i]; | ||
370 | return 0; | ||
371 | } | ||
372 | |||
347 | asmlinkage long sys32_sigreturn(void) | 373 | asmlinkage long sys32_sigreturn(void) |
348 | { | 374 | { |
349 | struct pt_regs *regs = task_pt_regs(current); | 375 | struct pt_regs *regs = task_pt_regs(current); |
@@ -363,6 +389,8 @@ asmlinkage long sys32_sigreturn(void) | |||
363 | 389 | ||
364 | if (restore_sigregs32(regs, &frame->sregs)) | 390 | if (restore_sigregs32(regs, &frame->sregs)) |
365 | goto badframe; | 391 | goto badframe; |
392 | if (restore_sigregs_gprs_high(regs, frame->gprs_high)) | ||
393 | goto badframe; | ||
366 | 394 | ||
367 | return regs->gprs[2]; | 395 | return regs->gprs[2]; |
368 | 396 | ||
@@ -394,6 +422,8 @@ asmlinkage long sys32_rt_sigreturn(void) | |||
394 | 422 | ||
395 | if (restore_sigregs32(regs, &frame->uc.uc_mcontext)) | 423 | if (restore_sigregs32(regs, &frame->uc.uc_mcontext)) |
396 | goto badframe; | 424 | goto badframe; |
425 | if (restore_sigregs_gprs_high(regs, frame->gprs_high)) | ||
426 | goto badframe; | ||
397 | 427 | ||
398 | err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp); | 428 | err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp); |
399 | st.ss_sp = compat_ptr(ss_sp); | 429 | st.ss_sp = compat_ptr(ss_sp); |
@@ -474,6 +504,8 @@ static int setup_frame32(int sig, struct k_sigaction *ka, | |||
474 | 504 | ||
475 | if (save_sigregs32(regs, &frame->sregs)) | 505 | if (save_sigregs32(regs, &frame->sregs)) |
476 | goto give_sigsegv; | 506 | goto give_sigsegv; |
507 | if (save_sigregs_gprs_high(regs, frame->gprs_high)) | ||
508 | goto give_sigsegv; | ||
477 | if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs)) | 509 | if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs)) |
478 | goto give_sigsegv; | 510 | goto give_sigsegv; |
479 | 511 | ||
@@ -529,13 +561,14 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
529 | goto give_sigsegv; | 561 | goto give_sigsegv; |
530 | 562 | ||
531 | /* Create the ucontext. */ | 563 | /* Create the ucontext. */ |
532 | err |= __put_user(0, &frame->uc.uc_flags); | 564 | err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags); |
533 | err |= __put_user(0, &frame->uc.uc_link); | 565 | err |= __put_user(0, &frame->uc.uc_link); |
534 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | 566 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); |
535 | err |= __put_user(sas_ss_flags(regs->gprs[15]), | 567 | err |= __put_user(sas_ss_flags(regs->gprs[15]), |
536 | &frame->uc.uc_stack.ss_flags); | 568 | &frame->uc.uc_stack.ss_flags); |
537 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 569 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
538 | err |= save_sigregs32(regs, &frame->uc.uc_mcontext); | 570 | err |= save_sigregs32(regs, &frame->uc.uc_mcontext); |
571 | err |= save_sigregs_gprs_high(regs, frame->gprs_high); | ||
539 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 572 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
540 | if (err) | 573 | if (err) |
541 | goto give_sigsegv; | 574 | goto give_sigsegv; |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index a8738676b26c..653c6a178740 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -57,6 +57,7 @@ | |||
57 | enum s390_regset { | 57 | enum s390_regset { |
58 | REGSET_GENERAL, | 58 | REGSET_GENERAL, |
59 | REGSET_FP, | 59 | REGSET_FP, |
60 | REGSET_GENERAL_EXTENDED, | ||
60 | }; | 61 | }; |
61 | 62 | ||
62 | static void | 63 | static void |
@@ -879,6 +880,67 @@ static int s390_compat_regs_set(struct task_struct *target, | |||
879 | return rc; | 880 | return rc; |
880 | } | 881 | } |
881 | 882 | ||
883 | static int s390_compat_regs_high_get(struct task_struct *target, | ||
884 | const struct user_regset *regset, | ||
885 | unsigned int pos, unsigned int count, | ||
886 | void *kbuf, void __user *ubuf) | ||
887 | { | ||
888 | compat_ulong_t *gprs_high; | ||
889 | |||
890 | gprs_high = (compat_ulong_t *) | ||
891 | &task_pt_regs(target)->gprs[pos / sizeof(compat_ulong_t)]; | ||
892 | if (kbuf) { | ||
893 | compat_ulong_t *k = kbuf; | ||
894 | while (count > 0) { | ||
895 | *k++ = *gprs_high; | ||
896 | gprs_high += 2; | ||
897 | count -= sizeof(*k); | ||
898 | } | ||
899 | } else { | ||
900 | compat_ulong_t __user *u = ubuf; | ||
901 | while (count > 0) { | ||
902 | if (__put_user(*gprs_high, u++)) | ||
903 | return -EFAULT; | ||
904 | gprs_high += 2; | ||
905 | count -= sizeof(*u); | ||
906 | } | ||
907 | } | ||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static int s390_compat_regs_high_set(struct task_struct *target, | ||
912 | const struct user_regset *regset, | ||
913 | unsigned int pos, unsigned int count, | ||
914 | const void *kbuf, const void __user *ubuf) | ||
915 | { | ||
916 | compat_ulong_t *gprs_high; | ||
917 | int rc = 0; | ||
918 | |||
919 | gprs_high = (compat_ulong_t *) | ||
920 | &task_pt_regs(target)->gprs[pos / sizeof(compat_ulong_t)]; | ||
921 | if (kbuf) { | ||
922 | const compat_ulong_t *k = kbuf; | ||
923 | while (count > 0) { | ||
924 | *gprs_high = *k++; | ||
925 | *gprs_high += 2; | ||
926 | count -= sizeof(*k); | ||
927 | } | ||
928 | } else { | ||
929 | const compat_ulong_t __user *u = ubuf; | ||
930 | while (count > 0 && !rc) { | ||
931 | unsigned long word; | ||
932 | rc = __get_user(word, u++); | ||
933 | if (rc) | ||
934 | break; | ||
935 | *gprs_high = word; | ||
936 | *gprs_high += 2; | ||
937 | count -= sizeof(*u); | ||
938 | } | ||
939 | } | ||
940 | |||
941 | return rc; | ||
942 | } | ||
943 | |||
882 | static const struct user_regset s390_compat_regsets[] = { | 944 | static const struct user_regset s390_compat_regsets[] = { |
883 | [REGSET_GENERAL] = { | 945 | [REGSET_GENERAL] = { |
884 | .core_note_type = NT_PRSTATUS, | 946 | .core_note_type = NT_PRSTATUS, |
@@ -896,6 +958,14 @@ static const struct user_regset s390_compat_regsets[] = { | |||
896 | .get = s390_fpregs_get, | 958 | .get = s390_fpregs_get, |
897 | .set = s390_fpregs_set, | 959 | .set = s390_fpregs_set, |
898 | }, | 960 | }, |
961 | [REGSET_GENERAL_EXTENDED] = { | ||
962 | .core_note_type = NT_PRXSTATUS, | ||
963 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), | ||
964 | .size = sizeof(compat_long_t), | ||
965 | .align = sizeof(compat_long_t), | ||
966 | .get = s390_compat_regs_high_get, | ||
967 | .set = s390_compat_regs_high_set, | ||
968 | }, | ||
899 | }; | 969 | }; |
900 | 970 | ||
901 | static const struct user_regset_view user_s390_compat_view = { | 971 | static const struct user_regset_view user_s390_compat_view = { |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 9ed13a1ed376..061479ff029f 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -729,7 +729,7 @@ static void __init setup_hwcaps(void) | |||
729 | 729 | ||
730 | if ((facility_list & (1UL << (31 - 22))) | 730 | if ((facility_list & (1UL << (31 - 22))) |
731 | && (facility_list & (1UL << (31 - 30)))) | 731 | && (facility_list & (1UL << (31 - 30)))) |
732 | elf_hwcap |= 1UL << 8; | 732 | elf_hwcap |= HWCAP_S390_ETF3EH; |
733 | 733 | ||
734 | /* | 734 | /* |
735 | * Check for additional facilities with store-facility-list-extended. | 735 | * Check for additional facilities with store-facility-list-extended. |
@@ -748,11 +748,20 @@ static void __init setup_hwcaps(void) | |||
748 | __stfle(&facility_list_extended, 1) > 0) { | 748 | __stfle(&facility_list_extended, 1) > 0) { |
749 | if ((facility_list_extended & (1ULL << (63 - 42))) | 749 | if ((facility_list_extended & (1ULL << (63 - 42))) |
750 | && (facility_list_extended & (1ULL << (63 - 44)))) | 750 | && (facility_list_extended & (1ULL << (63 - 44)))) |
751 | elf_hwcap |= 1UL << 6; | 751 | elf_hwcap |= HWCAP_S390_DFP; |
752 | } | 752 | } |
753 | 753 | ||
754 | /* | ||
755 | * Huge page support HWCAP_S390_HPAGE is bit 7. | ||
756 | */ | ||
754 | if (MACHINE_HAS_HPAGE) | 757 | if (MACHINE_HAS_HPAGE) |
755 | elf_hwcap |= 1UL << 7; | 758 | elf_hwcap |= HWCAP_S390_HPAGE; |
759 | |||
760 | /* | ||
761 | * 64-bit register support for 31-bit processes | ||
762 | * HWCAP_S390_HIGH_GPRS is bit 9. | ||
763 | */ | ||
764 | elf_hwcap |= HWCAP_S390_HIGH_GPRS; | ||
756 | 765 | ||
757 | switch (S390_lowcore.cpu_id.machine) { | 766 | switch (S390_lowcore.cpu_id.machine) { |
758 | case 0x9672: | 767 | case 0x9672: |