/*
* signal32.c: Support 32bit signal syscalls.
*
* Copyright (C) 2001 IBM
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*
* These routines maintain argument size conversion between 32bit and 64bit
* environment.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/syscalls.h>
#include <linux/errno.h>
#include <linux/elf.h>
#include <linux/compat.h>
#include <linux/ptrace.h>
#include <asm/ppc32.h>
#include <asm/uaccess.h>
#include <asm/ppcdebug.h>
#include <asm/unistd.h>
#include <asm/cacheflush.h>
#include <asm/vdso.h>
#define DEBUG_SIG 0
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
#define GP_REGS_SIZE32 min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32))
/*
* When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
* a sigregs32 struct
* a sigcontext32 struct
* a gap of __SIGNAL_FRAMESIZE32 bytes
*
* Each of these things must be a multiple of 16 bytes in size.
*
*/
struct sigregs32 {
struct mcontext32 mctx; /* all the register values */
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
* regs and 18 fp regs below sp before decrementing it.
*/
int abigap[56];
};
/* We use the mc_pad field for the signal return trampoline. */
#define tramp mc_pad
/*
* When we have rt signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
* one rt_sigframe32 struct (siginfo + ucontext + ABI gap)
* a gap of __SIGNAL_FRAMESIZE32+16 bytes
* (the +16 is to get the siginfo and ucontext32 in the same
* positions as in older kernels).
*
* Each of these things must be a multiple of 16 bytes in size.
*
*/
struct rt_sigframe32 {
compat_siginfo_t info;
struct ucontext32 uc;
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
* regs and 18 fp regs below sp before decrementing it.
*/
int abigap[56];
};
/*
* Common utility functions used by signal and context support
*
*/
/*
* Restore the user process's signal mask
* (implemented in signal.c)
*/
extern void restore_sigmask(sigset_t *set);
/*
* Functions for flipping sigsets (thanks to brain dead generic
* implementation that makes things simple for little endian only
*/
static inline void compat_from_sigset(compat_sigset_t *compat, sigset_t *set)
{
switch (_NSIG_WORDS) {
case 4: compat->sig[5] = set->sig[3] & 0xffffffffull ;
compat->sig[7] = set->sig[3] >> 32;
case 3: compat->sig[4] = set->sig[2] & 0xffffffffull ;
compat->sig[5] = set->sig[2] >> 32;
case 2: compat->sig[2] = set->sig[1] & 0xffffffffull ;
compat->sig[3] = set->sig[1] >> 32;
case 1: compat->sig[0] = set->sig[0] & 0xffffffffull ;
compat->sig[1] = set->sig[0] >> 32;
}
}
static inline void sigset_from_compat(sigset_t *set, compat_sigset_t *compat)
{
switch (_NSIG_WORDS) {
case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32);
case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32);
case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32);
case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32);
}
}
/*
* Save the current user registers on the user stack.
* We only save the altivec registers if the process has used
* altivec instructions at some point.
*/
static int save_user_regs(struct pt_regs *regs, struct mcontext32 __user *frame, int sigret)
{
elf_greg_t64 *gregs = (elf_greg_t64 *)regs;
int i, err = 0;
/* Make sure floating point registers are stored in regs */
flush_fp_to_thread(current);
/* save general and floating-point registers */
for (i = 0; i <= PT_RESULT; i ++)
err |= __put_user((unsigned int)gregs[i], &frame->mc_gregs[i]);
err |= __copy_to_user(&frame->mc_fregs, current->thread.fpr,
ELF_NFPREG * sizeof(double));
if (err)
return 1;
current->thread.fpscr = 0; /* turn off all fp exceptions */
#ifdef CONFIG_ALTIVEC
/* save altivec registers */
if (current->thread.used_vr) {
flush_altivec_to_thread(current);
if (__copy_to_user(&frame->mc_vregs, current->thread.vr,
ELF_NVRREG32 * sizeof