[S390] Introduce user_regset accessors for s390
Add the user_regset definitions for normal and compat processes, replace the dump_regs core dump cruft with the generic CORE_DUMP_USER_REGSET and replace binfmt_elf32.c with the generic compat_binfmt_elf.c implementation. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
This commit is contained in:
parent
ae437a452e
commit
63506c4198
|
@ -146,6 +146,7 @@ config MATHEMU
|
||||||
config COMPAT
|
config COMPAT
|
||||||
bool "Kernel support for 31 bit emulation"
|
bool "Kernel support for 31 bit emulation"
|
||||||
depends on 64BIT
|
depends on 64BIT
|
||||||
|
select COMPAT_BINFMT_ELF
|
||||||
help
|
help
|
||||||
Select this option if you want to enable your system kernel to
|
Select this option if you want to enable your system kernel to
|
||||||
handle system-calls from ELF binaries for 31 bit ESA. This option
|
handle system-calls from ELF binaries for 31 bit ESA. This option
|
||||||
|
|
|
@ -7,6 +7,11 @@
|
||||||
#
|
#
|
||||||
CFLAGS_smp.o := -Wno-nonnull
|
CFLAGS_smp.o := -Wno-nonnull
|
||||||
|
|
||||||
|
#
|
||||||
|
# Pass UTS_MACHINE for user_regset definition
|
||||||
|
#
|
||||||
|
CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
|
||||||
|
|
||||||
obj-y := bitmap.o traps.o time.o process.o base.o early.o \
|
obj-y := bitmap.o traps.o time.o process.o base.o early.o \
|
||||||
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
|
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
|
||||||
s390_ext.o debug.o irq.o ipl.o dis.o diag.o
|
s390_ext.o debug.o irq.o ipl.o dis.o diag.o
|
||||||
|
@ -23,7 +28,7 @@ obj-$(CONFIG_AUDIT) += audit.o
|
||||||
compat-obj-$(CONFIG_AUDIT) += compat_audit.o
|
compat-obj-$(CONFIG_AUDIT) += compat_audit.o
|
||||||
obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \
|
obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \
|
||||||
compat_wrapper.o compat_exec_domain.o \
|
compat_wrapper.o compat_exec_domain.o \
|
||||||
binfmt_elf32.o $(compat-obj-y)
|
$(compat-obj-y)
|
||||||
|
|
||||||
obj-$(CONFIG_VIRT_TIMER) += vtime.o
|
obj-$(CONFIG_VIRT_TIMER) += vtime.o
|
||||||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||||
|
|
|
@ -1,214 +0,0 @@
|
||||||
/*
|
|
||||||
* Support for 32-bit Linux for S390 ELF binaries.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
|
||||||
* Author(s): Gerhard Tonn (ton@de.ibm.com)
|
|
||||||
*
|
|
||||||
* Heavily inspired by the 32-bit Sparc compat code which is
|
|
||||||
* Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
|
|
||||||
* Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define __ASMS390_ELF_H
|
|
||||||
|
|
||||||
#include <linux/time.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* These are used to set parameters in the core dumps.
|
|
||||||
*/
|
|
||||||
#define ELF_CLASS ELFCLASS32
|
|
||||||
#define ELF_DATA ELFDATA2MSB
|
|
||||||
#define ELF_ARCH EM_S390
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is used to ensure we don't load something for the wrong architecture.
|
|
||||||
*/
|
|
||||||
#define elf_check_arch(x) \
|
|
||||||
(((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
|
|
||||||
&& (x)->e_ident[EI_CLASS] == ELF_CLASS)
|
|
||||||
|
|
||||||
/* ELF register definitions */
|
|
||||||
#define NUM_GPRS 16
|
|
||||||
#define NUM_FPRS 16
|
|
||||||
#define NUM_ACRS 16
|
|
||||||
|
|
||||||
/* For SVR4/S390 the function pointer to be registered with `atexit` is
|
|
||||||
passed in R14. */
|
|
||||||
#define ELF_PLAT_INIT(_r, load_addr) \
|
|
||||||
do { \
|
|
||||||
_r->gprs[14] = 0; \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define USE_ELF_CORE_DUMP
|
|
||||||
#define ELF_EXEC_PAGESIZE 4096
|
|
||||||
|
|
||||||
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
|
|
||||||
use of this is to invoke "./ld.so someprog" to test out a new version of
|
|
||||||
the loader. We need to make sure that it is out of the way of the program
|
|
||||||
that it will "exec", and that there is sufficient room for the brk. */
|
|
||||||
|
|
||||||
#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
|
|
||||||
|
|
||||||
/* Wow, the "main" arch needs arch dependent functions too.. :) */
|
|
||||||
|
|
||||||
/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
|
|
||||||
now struct_user_regs, they are different) */
|
|
||||||
|
|
||||||
#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs32(regs, &pr_reg);
|
|
||||||
|
|
||||||
#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs32(tsk, regs)
|
|
||||||
|
|
||||||
#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs)
|
|
||||||
|
|
||||||
/* This yields a mask that user programs can use to figure out what
|
|
||||||
instruction set this CPU supports. */
|
|
||||||
|
|
||||||
#define ELF_HWCAP (0)
|
|
||||||
|
|
||||||
/* This yields a string that ld.so will use to load implementation
|
|
||||||
specific libraries for optimization. This is more specific in
|
|
||||||
intent than poking at uname or /proc/cpuinfo.
|
|
||||||
|
|
||||||
For the moment, we have only optimizations for the Intel generations,
|
|
||||||
but that could change... */
|
|
||||||
|
|
||||||
#define ELF_PLATFORM (NULL)
|
|
||||||
|
|
||||||
#define SET_PERSONALITY(ex, ibcs2) \
|
|
||||||
do { \
|
|
||||||
if (ibcs2) \
|
|
||||||
set_personality(PER_SVR4); \
|
|
||||||
else if (current->personality != PER_LINUX32) \
|
|
||||||
set_personality(PER_LINUX); \
|
|
||||||
set_thread_flag(TIF_31BIT); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#include "compat_linux.h"
|
|
||||||
|
|
||||||
typedef _s390_fp_regs32 elf_fpregset_t;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
|
|
||||||
_psw_t32 psw;
|
|
||||||
__u32 gprs[__NUM_GPRS];
|
|
||||||
__u32 acrs[__NUM_ACRS];
|
|
||||||
__u32 orig_gpr2;
|
|
||||||
} s390_regs32;
|
|
||||||
typedef s390_regs32 elf_gregset_t;
|
|
||||||
|
|
||||||
static inline int dump_regs32(struct pt_regs *ptregs, elf_gregset_t *regs)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
memcpy(®s->psw.mask, &ptregs->psw.mask, 4);
|
|
||||||
memcpy(®s->psw.addr, (char *)&ptregs->psw.addr + 4, 4);
|
|
||||||
for (i = 0; i < NUM_GPRS; i++)
|
|
||||||
regs->gprs[i] = ptregs->gprs[i];
|
|
||||||
save_access_regs(regs->acrs);
|
|
||||||
regs->orig_gpr2 = ptregs->orig_gpr2;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int dump_task_regs32(struct task_struct *tsk, elf_gregset_t *regs)
|
|
||||||
{
|
|
||||||
struct pt_regs *ptregs = task_pt_regs(tsk);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
memcpy(®s->psw.mask, &ptregs->psw.mask, 4);
|
|
||||||
memcpy(®s->psw.addr, (char *)&ptregs->psw.addr + 4, 4);
|
|
||||||
for (i = 0; i < NUM_GPRS; i++)
|
|
||||||
regs->gprs[i] = ptregs->gprs[i];
|
|
||||||
memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs));
|
|
||||||
regs->orig_gpr2 = ptregs->orig_gpr2;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
|
|
||||||
{
|
|
||||||
if (tsk == current)
|
|
||||||
save_fp_regs((s390_fp_regs *) fpregs);
|
|
||||||
else
|
|
||||||
memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <asm/processor.h>
|
|
||||||
#include <asm/pgalloc.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/elfcore.h>
|
|
||||||
#include <linux/binfmts.h>
|
|
||||||
#include <linux/compat.h>
|
|
||||||
|
|
||||||
#define elf_prstatus elf_prstatus32
|
|
||||||
struct elf_prstatus32
|
|
||||||
{
|
|
||||||
struct elf_siginfo pr_info; /* Info associated with signal */
|
|
||||||
short pr_cursig; /* Current signal */
|
|
||||||
u32 pr_sigpend; /* Set of pending signals */
|
|
||||||
u32 pr_sighold; /* Set of held signals */
|
|
||||||
pid_t pr_pid;
|
|
||||||
pid_t pr_ppid;
|
|
||||||
pid_t pr_pgrp;
|
|
||||||
pid_t pr_sid;
|
|
||||||
struct compat_timeval pr_utime; /* User time */
|
|
||||||
struct compat_timeval pr_stime; /* System time */
|
|
||||||
struct compat_timeval pr_cutime; /* Cumulative user time */
|
|
||||||
struct compat_timeval pr_cstime; /* Cumulative system time */
|
|
||||||
elf_gregset_t pr_reg; /* GP registers */
|
|
||||||
int pr_fpvalid; /* True if math co-processor being used. */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define elf_prpsinfo elf_prpsinfo32
|
|
||||||
struct elf_prpsinfo32
|
|
||||||
{
|
|
||||||
char pr_state; /* numeric process state */
|
|
||||||
char pr_sname; /* char for pr_state */
|
|
||||||
char pr_zomb; /* zombie */
|
|
||||||
char pr_nice; /* nice val */
|
|
||||||
u32 pr_flag; /* flags */
|
|
||||||
u16 pr_uid;
|
|
||||||
u16 pr_gid;
|
|
||||||
pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
|
|
||||||
/* Lots missing */
|
|
||||||
char pr_fname[16]; /* filename of executable */
|
|
||||||
char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
|
|
||||||
};
|
|
||||||
|
|
||||||
#include <linux/highuid.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
#define init_elf_binfmt init_elf32_binfmt
|
|
||||||
*/
|
|
||||||
|
|
||||||
#undef start_thread
|
|
||||||
#define start_thread start_thread31
|
|
||||||
|
|
||||||
static inline void start_thread31(struct pt_regs *regs, unsigned long new_psw,
|
|
||||||
unsigned long new_stackp)
|
|
||||||
{
|
|
||||||
set_fs(USER_DS);
|
|
||||||
regs->psw.mask = psw_user32_bits;
|
|
||||||
regs->psw.addr = new_psw;
|
|
||||||
regs->gprs[15] = new_stackp;
|
|
||||||
crst_table_downgrade(current->mm, 1UL << 31);
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux for S390 binaries,"
|
|
||||||
" Copyright 2000 IBM Corporation");
|
|
||||||
MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
|
|
||||||
|
|
||||||
#undef MODULE_DESCRIPTION
|
|
||||||
#undef MODULE_AUTHOR
|
|
||||||
|
|
||||||
#undef cputime_to_timeval
|
|
||||||
#define cputime_to_timeval cputime_to_compat_timeval
|
|
||||||
static inline void
|
|
||||||
cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
|
|
||||||
{
|
|
||||||
value->tv_usec = cputime % 1000000;
|
|
||||||
value->tv_sec = cputime / 1000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "../../../fs/binfmt_elf.c"
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef _PTRACE32_H
|
#ifndef _PTRACE32_H
|
||||||
#define _PTRACE32_H
|
#define _PTRACE32_H
|
||||||
|
|
||||||
#include "compat_linux.h" /* needed for _psw_t32 */
|
#include "compat_linux.h" /* needed for psw_compat_t */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
__u32 cr[3];
|
__u32 cr[3];
|
||||||
|
@ -38,7 +38,7 @@ typedef struct {
|
||||||
|
|
||||||
struct user_regs_struct32
|
struct user_regs_struct32
|
||||||
{
|
{
|
||||||
_psw_t32 psw;
|
psw_compat_t psw;
|
||||||
u32 gprs[NUM_GPRS];
|
u32 gprs[NUM_GPRS];
|
||||||
u32 acrs[NUM_ACRS];
|
u32 acrs[NUM_ACRS];
|
||||||
u32 orig_gpr2;
|
u32 orig_gpr2;
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/audit.h>
|
#include <linux/audit.h>
|
||||||
#include <linux/signal.h>
|
#include <linux/signal.h>
|
||||||
|
#include <linux/elf.h>
|
||||||
|
#include <linux/regset.h>
|
||||||
|
|
||||||
#include <asm/segment.h>
|
#include <asm/segment.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
|
@ -47,6 +49,11 @@
|
||||||
#include "compat_ptrace.h"
|
#include "compat_ptrace.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum s390_regset {
|
||||||
|
REGSET_GENERAL,
|
||||||
|
REGSET_FP,
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FixPerRegisters(struct task_struct *task)
|
FixPerRegisters(struct task_struct *task)
|
||||||
{
|
{
|
||||||
|
@ -126,24 +133,10 @@ ptrace_disable(struct task_struct *child)
|
||||||
* struct user contain pad bytes that should be read as zeroes.
|
* struct user contain pad bytes that should be read as zeroes.
|
||||||
* Lovely...
|
* Lovely...
|
||||||
*/
|
*/
|
||||||
static int
|
static unsigned long __peek_user(struct task_struct *child, addr_t addr)
|
||||||
peek_user(struct task_struct *child, addr_t addr, addr_t data)
|
|
||||||
{
|
{
|
||||||
struct user *dummy = NULL;
|
struct user *dummy = NULL;
|
||||||
addr_t offset, tmp, mask;
|
addr_t offset, tmp;
|
||||||
|
|
||||||
/*
|
|
||||||
* Stupid gdb peeks/pokes the access registers in 64 bit with
|
|
||||||
* an alignment of 4. Programmers from hell...
|
|
||||||
*/
|
|
||||||
mask = __ADDR_MASK;
|
|
||||||
#ifdef CONFIG_64BIT
|
|
||||||
if (addr >= (addr_t) &dummy->regs.acrs &&
|
|
||||||
addr < (addr_t) &dummy->regs.orig_gpr2)
|
|
||||||
mask = 3;
|
|
||||||
#endif
|
|
||||||
if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
if (addr < (addr_t) &dummy->regs.acrs) {
|
if (addr < (addr_t) &dummy->regs.acrs) {
|
||||||
/*
|
/*
|
||||||
|
@ -197,24 +190,18 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
} else
|
} else
|
||||||
tmp = 0;
|
tmp = 0;
|
||||||
|
|
||||||
return put_user(tmp, (addr_t __user *) data);
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Write a word to the user area of a process at location addr. This
|
|
||||||
* operation does have an additional problem compared to peek_user.
|
|
||||||
* Stores to the program status word and on the floating point
|
|
||||||
* control register needs to get checked for validity.
|
|
||||||
*/
|
|
||||||
static int
|
static int
|
||||||
poke_user(struct task_struct *child, addr_t addr, addr_t data)
|
peek_user(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
{
|
{
|
||||||
struct user *dummy = NULL;
|
struct user *dummy = NULL;
|
||||||
addr_t offset, mask;
|
addr_t tmp, mask;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stupid gdb peeks/pokes the access registers in 64 bit with
|
* Stupid gdb peeks/pokes the access registers in 64 bit with
|
||||||
* an alignment of 4. Programmers from hell indeed...
|
* an alignment of 4. Programmers from hell...
|
||||||
*/
|
*/
|
||||||
mask = __ADDR_MASK;
|
mask = __ADDR_MASK;
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
|
@ -225,6 +212,21 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
|
if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
tmp = __peek_user(child, addr);
|
||||||
|
return put_user(tmp, (addr_t __user *) data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a word to the user area of a process at location addr. This
|
||||||
|
* operation does have an additional problem compared to peek_user.
|
||||||
|
* Stores to the program status word and on the floating point
|
||||||
|
* control register needs to get checked for validity.
|
||||||
|
*/
|
||||||
|
static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
|
{
|
||||||
|
struct user *dummy = NULL;
|
||||||
|
addr_t offset;
|
||||||
|
|
||||||
if (addr < (addr_t) &dummy->regs.acrs) {
|
if (addr < (addr_t) &dummy->regs.acrs) {
|
||||||
/*
|
/*
|
||||||
* psw and gprs are stored on the stack
|
* psw and gprs are stored on the stack
|
||||||
|
@ -292,6 +294,28 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
poke_user(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
|
{
|
||||||
|
struct user *dummy = NULL;
|
||||||
|
addr_t mask;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stupid gdb peeks/pokes the access registers in 64 bit with
|
||||||
|
* an alignment of 4. Programmers from hell indeed...
|
||||||
|
*/
|
||||||
|
mask = __ADDR_MASK;
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
|
if (addr >= (addr_t) &dummy->regs.acrs &&
|
||||||
|
addr < (addr_t) &dummy->regs.orig_gpr2)
|
||||||
|
mask = 3;
|
||||||
|
#endif
|
||||||
|
if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
return __poke_user(child, addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||||
{
|
{
|
||||||
ptrace_area parea;
|
ptrace_area parea;
|
||||||
|
@ -367,18 +391,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||||
/*
|
/*
|
||||||
* Same as peek_user but for a 31 bit program.
|
* Same as peek_user but for a 31 bit program.
|
||||||
*/
|
*/
|
||||||
static int
|
static u32 __peek_user_compat(struct task_struct *child, addr_t addr)
|
||||||
peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
|
|
||||||
{
|
{
|
||||||
struct user32 *dummy32 = NULL;
|
struct user32 *dummy32 = NULL;
|
||||||
per_struct32 *dummy_per32 = NULL;
|
per_struct32 *dummy_per32 = NULL;
|
||||||
addr_t offset;
|
addr_t offset;
|
||||||
__u32 tmp;
|
__u32 tmp;
|
||||||
|
|
||||||
if (!test_thread_flag(TIF_31BIT) ||
|
|
||||||
(addr & 3) || addr > sizeof(struct user) - 3)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
if (addr < (addr_t) &dummy32->regs.acrs) {
|
if (addr < (addr_t) &dummy32->regs.acrs) {
|
||||||
/*
|
/*
|
||||||
* psw and gprs are stored on the stack
|
* psw and gprs are stored on the stack
|
||||||
|
@ -435,25 +454,32 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
} else
|
} else
|
||||||
tmp = 0;
|
tmp = 0;
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int peek_user_compat(struct task_struct *child,
|
||||||
|
addr_t addr, addr_t data)
|
||||||
|
{
|
||||||
|
__u32 tmp;
|
||||||
|
|
||||||
|
if (!test_thread_flag(TIF_31BIT) ||
|
||||||
|
(addr & 3) || addr > sizeof(struct user) - 3)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
tmp = __peek_user_compat(child, addr);
|
||||||
return put_user(tmp, (__u32 __user *) data);
|
return put_user(tmp, (__u32 __user *) data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Same as poke_user but for a 31 bit program.
|
* Same as poke_user but for a 31 bit program.
|
||||||
*/
|
*/
|
||||||
static int
|
static int __poke_user_compat(struct task_struct *child,
|
||||||
poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
|
addr_t addr, addr_t data)
|
||||||
{
|
{
|
||||||
struct user32 *dummy32 = NULL;
|
struct user32 *dummy32 = NULL;
|
||||||
per_struct32 *dummy_per32 = NULL;
|
per_struct32 *dummy_per32 = NULL;
|
||||||
|
__u32 tmp = (__u32) data;
|
||||||
addr_t offset;
|
addr_t offset;
|
||||||
__u32 tmp;
|
|
||||||
|
|
||||||
if (!test_thread_flag(TIF_31BIT) ||
|
|
||||||
(addr & 3) || addr > sizeof(struct user32) - 3)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
tmp = (__u32) data;
|
|
||||||
|
|
||||||
if (addr < (addr_t) &dummy32->regs.acrs) {
|
if (addr < (addr_t) &dummy32->regs.acrs) {
|
||||||
/*
|
/*
|
||||||
|
@ -528,6 +554,16 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int poke_user_compat(struct task_struct *child,
|
||||||
|
addr_t addr, addr_t data)
|
||||||
|
{
|
||||||
|
if (!test_thread_flag(TIF_31BIT) ||
|
||||||
|
(addr & 3) || addr > sizeof(struct user32) - 3)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
return __poke_user_compat(child, addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||||
compat_ulong_t caddr, compat_ulong_t cdata)
|
compat_ulong_t caddr, compat_ulong_t cdata)
|
||||||
{
|
{
|
||||||
|
@ -539,11 +575,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||||
switch (request) {
|
switch (request) {
|
||||||
case PTRACE_PEEKUSR:
|
case PTRACE_PEEKUSR:
|
||||||
/* read the word at location addr in the USER area. */
|
/* read the word at location addr in the USER area. */
|
||||||
return peek_user_emu31(child, addr, data);
|
return peek_user_compat(child, addr, data);
|
||||||
|
|
||||||
case PTRACE_POKEUSR:
|
case PTRACE_POKEUSR:
|
||||||
/* write the word at location addr in the USER area */
|
/* write the word at location addr in the USER area */
|
||||||
return poke_user_emu31(child, addr, data);
|
return poke_user_compat(child, addr, data);
|
||||||
|
|
||||||
case PTRACE_PEEKUSR_AREA:
|
case PTRACE_PEEKUSR_AREA:
|
||||||
case PTRACE_POKEUSR_AREA:
|
case PTRACE_POKEUSR_AREA:
|
||||||
|
@ -555,13 +591,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||||
copied = 0;
|
copied = 0;
|
||||||
while (copied < parea.len) {
|
while (copied < parea.len) {
|
||||||
if (request == PTRACE_PEEKUSR_AREA)
|
if (request == PTRACE_PEEKUSR_AREA)
|
||||||
ret = peek_user_emu31(child, addr, data);
|
ret = peek_user_compat(child, addr, data);
|
||||||
else {
|
else {
|
||||||
__u32 utmp;
|
__u32 utmp;
|
||||||
if (get_user(utmp,
|
if (get_user(utmp,
|
||||||
(__u32 __force __user *) data))
|
(__u32 __force __user *) data))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
ret = poke_user_emu31(child, addr, utmp);
|
ret = poke_user_compat(child, addr, utmp);
|
||||||
}
|
}
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -610,3 +646,240 @@ syscall_trace(struct pt_regs *regs, int entryexit)
|
||||||
regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
|
regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
|
||||||
regs->gprs[4], regs->gprs[5]);
|
regs->gprs[4], regs->gprs[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* user_regset definitions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int s390_regs_get(struct task_struct *target,
|
||||||
|
const struct user_regset *regset,
|
||||||
|
unsigned int pos, unsigned int count,
|
||||||
|
void *kbuf, void __user *ubuf)
|
||||||
|
{
|
||||||
|
if (target == current)
|
||||||
|
save_access_regs(target->thread.acrs);
|
||||||
|
|
||||||
|
if (kbuf) {
|
||||||
|
unsigned long *k = kbuf;
|
||||||
|
while (count > 0) {
|
||||||
|
*k++ = __peek_user(target, pos);
|
||||||
|
count -= sizeof(*k);
|
||||||
|
pos += sizeof(*k);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsigned long __user *u = ubuf;
|
||||||
|
while (count > 0) {
|
||||||
|
if (__put_user(__peek_user(target, pos), u++))
|
||||||
|
return -EFAULT;
|
||||||
|
count -= sizeof(*u);
|
||||||
|
pos += sizeof(*u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s390_regs_set(struct task_struct *target,
|
||||||
|
const struct user_regset *regset,
|
||||||
|
unsigned int pos, unsigned int count,
|
||||||
|
const void *kbuf, const void __user *ubuf)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (target == current)
|
||||||
|
save_access_regs(target->thread.acrs);
|
||||||
|
|
||||||
|
if (kbuf) {
|
||||||
|
const unsigned long *k = kbuf;
|
||||||
|
while (count > 0 && !rc) {
|
||||||
|
rc = __poke_user(target, pos, *k++);
|
||||||
|
count -= sizeof(*k);
|
||||||
|
pos += sizeof(*k);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const unsigned long __user *u = ubuf;
|
||||||
|
while (count > 0 && !rc) {
|
||||||
|
unsigned long word;
|
||||||
|
rc = __get_user(word, u++);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
rc = __poke_user(target, pos, word);
|
||||||
|
count -= sizeof(*u);
|
||||||
|
pos += sizeof(*u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == 0 && target == current)
|
||||||
|
restore_access_regs(target->thread.acrs);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s390_fpregs_get(struct task_struct *target,
|
||||||
|
const struct user_regset *regset, unsigned int pos,
|
||||||
|
unsigned int count, void *kbuf, void __user *ubuf)
|
||||||
|
{
|
||||||
|
if (target == current)
|
||||||
|
save_fp_regs(&target->thread.fp_regs);
|
||||||
|
|
||||||
|
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||||
|
&target->thread.fp_regs, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s390_fpregs_set(struct task_struct *target,
|
||||||
|
const struct user_regset *regset, unsigned int pos,
|
||||||
|
unsigned int count, const void *kbuf,
|
||||||
|
const void __user *ubuf)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (target == current)
|
||||||
|
save_fp_regs(&target->thread.fp_regs);
|
||||||
|
|
||||||
|
/* If setting FPC, must validate it first. */
|
||||||
|
if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) {
|
||||||
|
u32 fpc[2] = { target->thread.fp_regs.fpc, 0 };
|
||||||
|
rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fpc,
|
||||||
|
0, offsetof(s390_fp_regs, fprs));
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
if ((fpc[0] & ~FPC_VALID_MASK) != 0 || fpc[1] != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
target->thread.fp_regs.fpc = fpc[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == 0 && count > 0)
|
||||||
|
rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||||
|
target->thread.fp_regs.fprs,
|
||||||
|
offsetof(s390_fp_regs, fprs), -1);
|
||||||
|
|
||||||
|
if (rc == 0 && target == current)
|
||||||
|
restore_fp_regs(&target->thread.fp_regs);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct user_regset s390_regsets[] = {
|
||||||
|
[REGSET_GENERAL] = {
|
||||||
|
.core_note_type = NT_PRSTATUS,
|
||||||
|
.n = sizeof(s390_regs) / sizeof(long),
|
||||||
|
.size = sizeof(long),
|
||||||
|
.align = sizeof(long),
|
||||||
|
.get = s390_regs_get,
|
||||||
|
.set = s390_regs_set,
|
||||||
|
},
|
||||||
|
[REGSET_FP] = {
|
||||||
|
.core_note_type = NT_PRFPREG,
|
||||||
|
.n = sizeof(s390_fp_regs) / sizeof(long),
|
||||||
|
.size = sizeof(long),
|
||||||
|
.align = sizeof(long),
|
||||||
|
.get = s390_fpregs_get,
|
||||||
|
.set = s390_fpregs_set,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct user_regset_view user_s390_view = {
|
||||||
|
.name = UTS_MACHINE,
|
||||||
|
.e_machine = EM_S390,
|
||||||
|
.regsets = s390_regsets,
|
||||||
|
.n = ARRAY_SIZE(s390_regsets)
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
static int s390_compat_regs_get(struct task_struct *target,
|
||||||
|
const struct user_regset *regset,
|
||||||
|
unsigned int pos, unsigned int count,
|
||||||
|
void *kbuf, void __user *ubuf)
|
||||||
|
{
|
||||||
|
if (target == current)
|
||||||
|
save_access_regs(target->thread.acrs);
|
||||||
|
|
||||||
|
if (kbuf) {
|
||||||
|
compat_ulong_t *k = kbuf;
|
||||||
|
while (count > 0) {
|
||||||
|
*k++ = __peek_user_compat(target, pos);
|
||||||
|
count -= sizeof(*k);
|
||||||
|
pos += sizeof(*k);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
compat_ulong_t __user *u = ubuf;
|
||||||
|
while (count > 0) {
|
||||||
|
if (__put_user(__peek_user_compat(target, pos), u++))
|
||||||
|
return -EFAULT;
|
||||||
|
count -= sizeof(*u);
|
||||||
|
pos += sizeof(*u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int s390_compat_regs_set(struct task_struct *target,
|
||||||
|
const struct user_regset *regset,
|
||||||
|
unsigned int pos, unsigned int count,
|
||||||
|
const void *kbuf, const void __user *ubuf)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (target == current)
|
||||||
|
save_access_regs(target->thread.acrs);
|
||||||
|
|
||||||
|
if (kbuf) {
|
||||||
|
const compat_ulong_t *k = kbuf;
|
||||||
|
while (count > 0 && !rc) {
|
||||||
|
rc = __poke_user_compat(target, pos, *k++);
|
||||||
|
count -= sizeof(*k);
|
||||||
|
pos += sizeof(*k);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const compat_ulong_t __user *u = ubuf;
|
||||||
|
while (count > 0 && !rc) {
|
||||||
|
compat_ulong_t word;
|
||||||
|
rc = __get_user(word, u++);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
rc = __poke_user_compat(target, pos, word);
|
||||||
|
count -= sizeof(*u);
|
||||||
|
pos += sizeof(*u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == 0 && target == current)
|
||||||
|
restore_access_regs(target->thread.acrs);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct user_regset s390_compat_regsets[] = {
|
||||||
|
[REGSET_GENERAL] = {
|
||||||
|
.core_note_type = NT_PRSTATUS,
|
||||||
|
.n = sizeof(s390_compat_regs) / sizeof(compat_long_t),
|
||||||
|
.size = sizeof(compat_long_t),
|
||||||
|
.align = sizeof(compat_long_t),
|
||||||
|
.get = s390_compat_regs_get,
|
||||||
|
.set = s390_compat_regs_set,
|
||||||
|
},
|
||||||
|
[REGSET_FP] = {
|
||||||
|
.core_note_type = NT_PRFPREG,
|
||||||
|
.n = sizeof(s390_fp_regs) / sizeof(compat_long_t),
|
||||||
|
.size = sizeof(compat_long_t),
|
||||||
|
.align = sizeof(compat_long_t),
|
||||||
|
.get = s390_fpregs_get,
|
||||||
|
.set = s390_fpregs_set,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct user_regset_view user_s390_compat_view = {
|
||||||
|
.name = "s390",
|
||||||
|
.e_machine = EM_S390,
|
||||||
|
.regsets = s390_compat_regsets,
|
||||||
|
.n = ARRAY_SIZE(s390_compat_regsets)
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
if (test_tsk_thread_flag(task, TIF_31BIT))
|
||||||
|
return &user_s390_compat_view;
|
||||||
|
#endif
|
||||||
|
return &user_s390_view;
|
||||||
|
}
|
||||||
|
|
|
@ -113,6 +113,9 @@
|
||||||
typedef s390_fp_regs elf_fpregset_t;
|
typedef s390_fp_regs elf_fpregset_t;
|
||||||
typedef s390_regs elf_gregset_t;
|
typedef s390_regs elf_gregset_t;
|
||||||
|
|
||||||
|
typedef s390_fp_regs compat_elf_fpregset_t;
|
||||||
|
typedef s390_compat_regs compat_elf_gregset_t;
|
||||||
|
|
||||||
#include <linux/sched.h> /* for task_struct */
|
#include <linux/sched.h> /* for task_struct */
|
||||||
#include <asm/system.h> /* for save_access_regs */
|
#include <asm/system.h> /* for save_access_regs */
|
||||||
#include <asm/mmu_context.h>
|
#include <asm/mmu_context.h>
|
||||||
|
@ -123,6 +126,10 @@ typedef s390_regs elf_gregset_t;
|
||||||
#define elf_check_arch(x) \
|
#define elf_check_arch(x) \
|
||||||
(((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
|
(((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
|
||||||
&& (x)->e_ident[EI_CLASS] == ELF_CLASS)
|
&& (x)->e_ident[EI_CLASS] == ELF_CLASS)
|
||||||
|
#define compat_elf_check_arch(x) \
|
||||||
|
(((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
|
||||||
|
&& (x)->e_ident[EI_CLASS] == ELF_CLASS)
|
||||||
|
#define compat_start_thread start_thread31
|
||||||
|
|
||||||
/* For SVR4/S390 the function pointer to be registered with `atexit` is
|
/* For SVR4/S390 the function pointer to be registered with `atexit` is
|
||||||
passed in R14. */
|
passed in R14. */
|
||||||
|
@ -131,6 +138,7 @@ typedef s390_regs elf_gregset_t;
|
||||||
_r->gprs[14] = 0; \
|
_r->gprs[14] = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define CORE_DUMP_USE_REGSET
|
||||||
#define USE_ELF_CORE_DUMP
|
#define USE_ELF_CORE_DUMP
|
||||||
#define ELF_EXEC_PAGESIZE 4096
|
#define ELF_EXEC_PAGESIZE 4096
|
||||||
|
|
||||||
|
@ -140,44 +148,6 @@ typedef s390_regs elf_gregset_t;
|
||||||
that it will "exec", and that there is sufficient room for the brk. */
|
that it will "exec", and that there is sufficient room for the brk. */
|
||||||
#define ELF_ET_DYN_BASE (STACK_TOP / 3 * 2)
|
#define ELF_ET_DYN_BASE (STACK_TOP / 3 * 2)
|
||||||
|
|
||||||
/* Wow, the "main" arch needs arch dependent functions too.. :) */
|
|
||||||
|
|
||||||
/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
|
|
||||||
now struct_user_regs, they are different) */
|
|
||||||
|
|
||||||
static inline int dump_regs(struct pt_regs *ptregs, elf_gregset_t *regs)
|
|
||||||
{
|
|
||||||
memcpy(®s->psw, &ptregs->psw, sizeof(regs->psw)+sizeof(regs->gprs));
|
|
||||||
save_access_regs(regs->acrs);
|
|
||||||
regs->orig_gpr2 = ptregs->orig_gpr2;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs(regs, &pr_reg);
|
|
||||||
|
|
||||||
static inline int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
|
|
||||||
{
|
|
||||||
struct pt_regs *ptregs = task_pt_regs(tsk);
|
|
||||||
memcpy(®s->psw, &ptregs->psw, sizeof(regs->psw)+sizeof(regs->gprs));
|
|
||||||
memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs));
|
|
||||||
regs->orig_gpr2 = ptregs->orig_gpr2;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs(tsk, regs)
|
|
||||||
|
|
||||||
static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
|
|
||||||
{
|
|
||||||
if (tsk == current)
|
|
||||||
save_fp_regs(fpregs);
|
|
||||||
else
|
|
||||||
memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs)
|
|
||||||
|
|
||||||
|
|
||||||
/* This yields a mask that user programs can use to figure out what
|
/* This yields a mask that user programs can use to figure out what
|
||||||
instruction set this CPU supports. */
|
instruction set this CPU supports. */
|
||||||
|
|
||||||
|
@ -204,6 +174,9 @@ do { \
|
||||||
set_personality(PER_SVR4); \
|
set_personality(PER_SVR4); \
|
||||||
else if (current->personality != PER_LINUX32) \
|
else if (current->personality != PER_LINUX32) \
|
||||||
set_personality(PER_LINUX); \
|
set_personality(PER_LINUX); \
|
||||||
|
if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \
|
||||||
|
set_thread_flag(TIF_31BIT); \
|
||||||
|
else \
|
||||||
clear_thread_flag(TIF_31BIT); \
|
clear_thread_flag(TIF_31BIT); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif /* __s390x__ */
|
#endif /* __s390x__ */
|
||||||
|
|
|
@ -147,7 +147,15 @@ struct stack_frame {
|
||||||
set_fs(USER_DS); \
|
set_fs(USER_DS); \
|
||||||
regs->psw.mask = psw_user_bits; \
|
regs->psw.mask = psw_user_bits; \
|
||||||
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
|
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
|
||||||
regs->gprs[15] = new_stackp ; \
|
regs->gprs[15] = new_stackp; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define start_thread31(regs, new_psw, new_stackp) do { \
|
||||||
|
set_fs(USER_DS); \
|
||||||
|
regs->psw.mask = psw_user32_bits; \
|
||||||
|
regs->psw.addr = new_psw | PSW_ADDR_AMODE; \
|
||||||
|
regs->gprs[15] = new_stackp; \
|
||||||
|
crst_table_downgrade(current->mm, 1UL << 31); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Forward declaration, a strange C thing */
|
/* Forward declaration, a strange C thing */
|
||||||
|
|
|
@ -215,6 +215,12 @@ typedef struct
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
} __attribute__ ((aligned(8))) psw_t;
|
} __attribute__ ((aligned(8))) psw_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
__u32 mask;
|
||||||
|
__u32 addr;
|
||||||
|
} __attribute__ ((aligned(8))) psw_compat_t;
|
||||||
|
|
||||||
#ifndef __s390x__
|
#ifndef __s390x__
|
||||||
|
|
||||||
#define PSW_MASK_PER 0x40000000UL
|
#define PSW_MASK_PER 0x40000000UL
|
||||||
|
@ -292,6 +298,15 @@ typedef struct
|
||||||
unsigned long orig_gpr2;
|
unsigned long orig_gpr2;
|
||||||
} s390_regs;
|
} s390_regs;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
psw_compat_t psw;
|
||||||
|
__u32 gprs[NUM_GPRS];
|
||||||
|
__u32 acrs[NUM_ACRS];
|
||||||
|
__u32 orig_gpr2;
|
||||||
|
} s390_compat_regs;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
|
|
Loading…
Reference in New Issue