Commit ea2a4d3a authored by Heiko Carstens's avatar Heiko Carstens Committed by Martin Schwidefsky

[S390] 64-bit register support for 31-bit processes

From: Heiko Carstens <heiko.carstens@de.ibm.com>
From: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent dd43bfca
...@@ -92,6 +92,18 @@ ...@@ -92,6 +92,18 @@
/* Keep this the last entry. */ /* Keep this the last entry. */
#define R_390_NUM 61 #define R_390_NUM 61
/* Bits present in AT_HWCAP. */
#define HWCAP_S390_ESAN3 1
#define HWCAP_S390_ZARCH 2
#define HWCAP_S390_STFLE 4
#define HWCAP_S390_MSA 8
#define HWCAP_S390_LDISP 16
#define HWCAP_S390_EIMM 32
#define HWCAP_S390_DFP 64
#define HWCAP_S390_HPAGE 128
#define HWCAP_S390_ETF3EH 256
#define HWCAP_S390_HIGH_GPRS 512
/* /*
* These are used to set parameters in the core dumps. * These are used to set parameters in the core dumps.
*/ */
......
...@@ -311,6 +311,10 @@ typedef struct ...@@ -311,6 +311,10 @@ typedef struct
__u32 orig_gpr2; __u32 orig_gpr2;
} s390_compat_regs; } s390_compat_regs;
typedef struct
{
__u32 gprs_high[NUM_GPRS];
} s390_compat_regs_high;
#ifdef __KERNEL__ #ifdef __KERNEL__
......
...@@ -9,6 +9,21 @@ ...@@ -9,6 +9,21 @@
#ifndef _ASM_S390_UCONTEXT_H #ifndef _ASM_S390_UCONTEXT_H
#define _ASM_S390_UCONTEXT_H #define _ASM_S390_UCONTEXT_H
#define UC_EXTENDED 0x00000001
#ifndef __s390x__
struct ucontext_extended {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
_sigregs uc_mcontext;
unsigned long uc_sigmask[2];
unsigned long uc_gprs_high[16];
};
#endif
struct ucontext { struct ucontext {
unsigned long uc_flags; unsigned long uc_flags;
struct ucontext *uc_link; struct ucontext *uc_link;
......
...@@ -39,6 +39,7 @@ typedef struct ...@@ -39,6 +39,7 @@ typedef struct
struct sigcontext32 sc; struct sigcontext32 sc;
_sigregs32 sregs; _sigregs32 sregs;
int signo; int signo;
__u32 gprs_high[NUM_GPRS];
__u8 retcode[S390_SYSCALL_SIZE]; __u8 retcode[S390_SYSCALL_SIZE];
} sigframe32; } sigframe32;
...@@ -48,6 +49,7 @@ typedef struct ...@@ -48,6 +49,7 @@ typedef struct
__u8 retcode[S390_SYSCALL_SIZE]; __u8 retcode[S390_SYSCALL_SIZE];
compat_siginfo_t info; compat_siginfo_t info;
struct ucontext32 uc; struct ucontext32 uc;
__u32 gprs_high[NUM_GPRS];
} rt_sigframe32; } rt_sigframe32;
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) 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,6 +346,30 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
return 0; return 0;
} }
static int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
{
__u32 gprs_high[NUM_GPRS];
int i;
for (i = 0; i < NUM_GPRS; i++)
gprs_high[i] = regs->gprs[i] >> 32;
return __copy_to_user(uregs, &gprs_high, sizeof(gprs_high));
}
static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
{
__u32 gprs_high[NUM_GPRS];
int err, i;
err = __copy_from_user(&gprs_high, uregs, sizeof(gprs_high));
if (err)
return err;
for (i = 0; i < NUM_GPRS; i++)
*(__u32 *)&regs->gprs[i] = gprs_high[i];
return 0;
}
asmlinkage long sys32_sigreturn(void) asmlinkage long sys32_sigreturn(void)
{ {
struct pt_regs *regs = task_pt_regs(current); struct pt_regs *regs = task_pt_regs(current);
...@@ -363,6 +389,8 @@ asmlinkage long sys32_sigreturn(void) ...@@ -363,6 +389,8 @@ asmlinkage long sys32_sigreturn(void)
if (restore_sigregs32(regs, &frame->sregs)) if (restore_sigregs32(regs, &frame->sregs))
goto badframe; goto badframe;
if (restore_sigregs_gprs_high(regs, frame->gprs_high))
goto badframe;
return regs->gprs[2]; return regs->gprs[2];
...@@ -394,6 +422,8 @@ asmlinkage long sys32_rt_sigreturn(void) ...@@ -394,6 +422,8 @@ asmlinkage long sys32_rt_sigreturn(void)
if (restore_sigregs32(regs, &frame->uc.uc_mcontext)) if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
goto badframe; goto badframe;
if (restore_sigregs_gprs_high(regs, frame->gprs_high))
goto badframe;
err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp); err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
st.ss_sp = compat_ptr(ss_sp); st.ss_sp = compat_ptr(ss_sp);
...@@ -474,6 +504,8 @@ static int setup_frame32(int sig, struct k_sigaction *ka, ...@@ -474,6 +504,8 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
if (save_sigregs32(regs, &frame->sregs)) if (save_sigregs32(regs, &frame->sregs))
goto give_sigsegv; goto give_sigsegv;
if (save_sigregs_gprs_high(regs, frame->gprs_high))
goto give_sigsegv;
if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs)) if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
goto give_sigsegv; goto give_sigsegv;
...@@ -529,13 +561,14 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -529,13 +561,14 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv; goto give_sigsegv;
/* Create the ucontext. */ /* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link); err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->gprs[15]), err |= __put_user(sas_ss_flags(regs->gprs[15]),
&frame->uc.uc_stack.ss_flags); &frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= save_sigregs32(regs, &frame->uc.uc_mcontext); err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
err |= save_sigregs_gprs_high(regs, frame->gprs_high);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err) if (err)
goto give_sigsegv; goto give_sigsegv;
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
enum s390_regset { enum s390_regset {
REGSET_GENERAL, REGSET_GENERAL,
REGSET_FP, REGSET_FP,
REGSET_GENERAL_EXTENDED,
}; };
static void static void
...@@ -879,6 +880,67 @@ static int s390_compat_regs_set(struct task_struct *target, ...@@ -879,6 +880,67 @@ static int s390_compat_regs_set(struct task_struct *target,
return rc; return rc;
} }
static int s390_compat_regs_high_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
compat_ulong_t *gprs_high;
gprs_high = (compat_ulong_t *)
&task_pt_regs(target)->gprs[pos / sizeof(compat_ulong_t)];
if (kbuf) {
compat_ulong_t *k = kbuf;
while (count > 0) {
*k++ = *gprs_high;
gprs_high += 2;
count -= sizeof(*k);
}
} else {
compat_ulong_t __user *u = ubuf;
while (count > 0) {
if (__put_user(*gprs_high, u++))
return -EFAULT;
gprs_high += 2;
count -= sizeof(*u);
}
}
return 0;
}
static int s390_compat_regs_high_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
compat_ulong_t *gprs_high;
int rc = 0;
gprs_high = (compat_ulong_t *)
&task_pt_regs(target)->gprs[pos / sizeof(compat_ulong_t)];
if (kbuf) {
const compat_ulong_t *k = kbuf;
while (count > 0) {
*gprs_high = *k++;
*gprs_high += 2;
count -= sizeof(*k);
}
} else {
const compat_ulong_t __user *u = ubuf;
while (count > 0 && !rc) {
unsigned long word;
rc = __get_user(word, u++);
if (rc)
break;
*gprs_high = word;
*gprs_high += 2;
count -= sizeof(*u);
}
}
return rc;
}
static const struct user_regset s390_compat_regsets[] = { static const struct user_regset s390_compat_regsets[] = {
[REGSET_GENERAL] = { [REGSET_GENERAL] = {
.core_note_type = NT_PRSTATUS, .core_note_type = NT_PRSTATUS,
...@@ -896,6 +958,14 @@ static const struct user_regset s390_compat_regsets[] = { ...@@ -896,6 +958,14 @@ static const struct user_regset s390_compat_regsets[] = {
.get = s390_fpregs_get, .get = s390_fpregs_get,
.set = s390_fpregs_set, .set = s390_fpregs_set,
}, },
[REGSET_GENERAL_EXTENDED] = {
.core_note_type = NT_PRXSTATUS,
.n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t),
.size = sizeof(compat_long_t),
.align = sizeof(compat_long_t),
.get = s390_compat_regs_high_get,
.set = s390_compat_regs_high_set,
},
}; };
static const struct user_regset_view user_s390_compat_view = { static const struct user_regset_view user_s390_compat_view = {
......
...@@ -729,7 +729,7 @@ static void __init setup_hwcaps(void) ...@@ -729,7 +729,7 @@ static void __init setup_hwcaps(void)
if ((facility_list & (1UL << (31 - 22))) if ((facility_list & (1UL << (31 - 22)))
&& (facility_list & (1UL << (31 - 30)))) && (facility_list & (1UL << (31 - 30))))
elf_hwcap |= 1UL << 8; elf_hwcap |= HWCAP_S390_ETF3EH;
/* /*
* Check for additional facilities with store-facility-list-extended. * Check for additional facilities with store-facility-list-extended.
...@@ -748,11 +748,20 @@ static void __init setup_hwcaps(void) ...@@ -748,11 +748,20 @@ static void __init setup_hwcaps(void)
__stfle(&facility_list_extended, 1) > 0) { __stfle(&facility_list_extended, 1) > 0) {
if ((facility_list_extended & (1ULL << (63 - 42))) if ((facility_list_extended & (1ULL << (63 - 42)))
&& (facility_list_extended & (1ULL << (63 - 44)))) && (facility_list_extended & (1ULL << (63 - 44))))
elf_hwcap |= 1UL << 6; elf_hwcap |= HWCAP_S390_DFP;
} }
/*
* Huge page support HWCAP_S390_HPAGE is bit 7.
*/
if (MACHINE_HAS_HPAGE) if (MACHINE_HAS_HPAGE)
elf_hwcap |= 1UL << 7; elf_hwcap |= HWCAP_S390_HPAGE;
/*
* 64-bit register support for 31-bit processes
* HWCAP_S390_HIGH_GPRS is bit 9.
*/
elf_hwcap |= HWCAP_S390_HIGH_GPRS;
switch (S390_lowcore.cpu_id.machine) { switch (S390_lowcore.cpu_id.machine) {
case 0x9672: case 0x9672:
......
...@@ -361,6 +361,7 @@ typedef struct elf64_shdr { ...@@ -361,6 +361,7 @@ typedef struct elf64_shdr {
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ #define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ #define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ #define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
#define NT_PRXSTATUS 0x300 /* s390 upper register halves */
/* Note header in a PT_NOTE section */ /* Note header in a PT_NOTE section */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment