Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -92,6 +92,18 @@
/* Keep this the last entry.  */
#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.
 */
+4 −0
Original line number Diff line number Diff line
@@ -311,6 +311,10 @@ typedef struct
	__u32		orig_gpr2;
} s390_compat_regs;

typedef struct
{
	__u32		gprs_high[NUM_GPRS];
} s390_compat_regs_high;

#ifdef __KERNEL__

+15 −0
Original line number Diff line number Diff line
@@ -9,6 +9,21 @@
#ifndef _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 {
	unsigned long	  uc_flags;
	struct ucontext  *uc_link;
+34 −1
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ typedef struct
	struct sigcontext32 sc;
	_sigregs32 sregs;
	int signo;
	__u32 gprs_high[NUM_GPRS];
	__u8 retcode[S390_SYSCALL_SIZE];
} sigframe32;

@@ -48,6 +49,7 @@ typedef struct
	__u8 retcode[S390_SYSCALL_SIZE];
	compat_siginfo_t info;
	struct ucontext32 uc;
	__u32 gprs_high[NUM_GPRS];
} rt_sigframe32;

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)
	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)
{
	struct pt_regs *regs = task_pt_regs(current);
@@ -363,6 +389,8 @@ asmlinkage long sys32_sigreturn(void)

	if (restore_sigregs32(regs, &frame->sregs))
		goto badframe;
	if (restore_sigregs_gprs_high(regs, frame->gprs_high))
		goto badframe;

	return regs->gprs[2];

@@ -394,6 +422,8 @@ asmlinkage long sys32_rt_sigreturn(void)

	if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
		goto badframe;
	if (restore_sigregs_gprs_high(regs, frame->gprs_high))
		goto badframe;

	err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
	st.ss_sp = compat_ptr(ss_sp);
@@ -474,6 +504,8 @@ static int setup_frame32(int sig, struct k_sigaction *ka,

	if (save_sigregs32(regs, &frame->sregs))
		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))
		goto give_sigsegv;

@@ -529,13 +561,14 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
		goto give_sigsegv;

	/* 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(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
	err |= __put_user(sas_ss_flags(regs->gprs[15]),
	                  &frame->uc.uc_stack.ss_flags);
	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
	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));
	if (err)
		goto give_sigsegv;
+70 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@
enum s390_regset {
	REGSET_GENERAL,
	REGSET_FP,
	REGSET_GENERAL_EXTENDED,
};

static void
@@ -879,6 +880,67 @@ static int s390_compat_regs_set(struct task_struct *target,
	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[] = {
	[REGSET_GENERAL] = {
		.core_note_type = NT_PRSTATUS,
@@ -896,6 +958,14 @@ static const struct user_regset s390_compat_regsets[] = {
		.get = s390_fpregs_get,
		.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 = {
Loading