Skip to content

Commit

Permalink
s390: add support for vector extension
Browse files Browse the repository at this point in the history
The vector extension introduces 32 128-bit vector registers and a set of
instruction to operate on the vector registers.

The kernel can control the use of vector registers for the problem state
program with a bit in control register 0. Once enabled for a process the
kernel needs to retain the content of the vector registers on context
switch. The signal frame is extended to include the vector registers.
Two new register sets NT_S390_VXRS_LOW and NT_S390_VXRS_HIGH are added
to the regset interface for the debugger and core dumps.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
Martin Schwidefsky committed Oct 9, 2014
1 parent 42f4dd6 commit 8070361
Show file tree
Hide file tree
Showing 22 changed files with 804 additions and 187 deletions.
1 change: 1 addition & 0 deletions arch/s390/include/asm/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
#define HWCAP_S390_ETF3EH 256
#define HWCAP_S390_HIGH_GPRS 512
#define HWCAP_S390_TE 1024
#define HWCAP_S390_VXRS 2048

/*
* These are used to set parameters in the core dumps.
Expand Down
10 changes: 7 additions & 3 deletions arch/s390/include/asm/lowcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,10 @@ struct _lowcore {

/* Extended facility list */
__u64 stfle_fac_list[32]; /* 0x0f00 */
__u8 pad_0x1000[0x11b8-0x1000]; /* 0x1000 */
__u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */

/* Pointer to vector register save area */
__u64 vector_save_area_addr; /* 0x11b0 */

/* 64 bit extparam used for pfault/diag 250: defined by architecture */
__u64 ext_params2; /* 0x11B8 */
Expand All @@ -334,9 +337,10 @@ struct _lowcore {

/* Transaction abort diagnostic block */
__u8 pgm_tdb[256]; /* 0x1800 */
__u8 pad_0x1900[0x1c00-0x1900]; /* 0x1900 */

/* align to the top of the prefix area */
__u8 pad_0x1900[0x2000-0x1900]; /* 0x1900 */
/* Software defined save area for vector registers */
__u8 vector_save_area[1024]; /* 0x1c00 */
} __packed;

#endif /* CONFIG_32BIT */
Expand Down
2 changes: 1 addition & 1 deletion arch/s390/include/asm/nmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct mci {
__u32 pm : 1; /* 22 psw program mask and cc validity */
__u32 ia : 1; /* 23 psw instruction address validity */
__u32 fa : 1; /* 24 failing storage address validity */
__u32 : 1; /* 25 */
__u32 vr : 1; /* 25 vector register validity */
__u32 ec : 1; /* 26 external damage code validity */
__u32 fp : 1; /* 27 floating point register validity */
__u32 gr : 1; /* 28 general register validity */
Expand Down
1 change: 1 addition & 0 deletions arch/s390/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ struct thread_struct {
int ri_signum;
#ifdef CONFIG_64BIT
unsigned char trap_tdb[256]; /* Transaction abort diagnose block */
__vector128 *vxrs; /* Vector register save area */
#endif
};

Expand Down
3 changes: 3 additions & 0 deletions arch/s390/include/asm/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ extern void detect_memory_memblock(void);
#define MACHINE_FLAG_TOPOLOGY (1UL << 14)
#define MACHINE_FLAG_TE (1UL << 15)
#define MACHINE_FLAG_TLB_LC (1UL << 17)
#define MACHINE_FLAG_VX (1UL << 18)

#define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM)
#define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
Expand All @@ -78,6 +79,7 @@ extern void detect_memory_memblock(void);
#define MACHINE_HAS_TOPOLOGY (0)
#define MACHINE_HAS_TE (0)
#define MACHINE_HAS_TLB_LC (0)
#define MACHINE_HAS_VX (0)
#else /* CONFIG_64BIT */
#define MACHINE_HAS_IEEE (1)
#define MACHINE_HAS_CSP (1)
Expand All @@ -90,6 +92,7 @@ extern void detect_memory_memblock(void);
#define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
#define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE)
#define MACHINE_HAS_TLB_LC (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC)
#define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX)
#endif /* CONFIG_64BIT */

/*
Expand Down
48 changes: 45 additions & 3 deletions arch/s390/include/asm/switch_to.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,48 @@ static inline void restore_fp_regs(freg_t *fprs)
asm volatile("ld 15,%0" : : "Q" (fprs[15]));
}

static inline void save_vx_regs(__vector128 *vxrs)
{
typedef struct { __vector128 _[__NUM_VXRS]; } addrtype;

asm volatile(
" la 1,%0\n"
" .word 0xe70f,0x1000,0x003e\n" /* vstm 0,15,0(1) */
" .word 0xe70f,0x1100,0x0c3e\n" /* vstm 16,31,256(1) */
: "=Q" (*(addrtype *) vxrs) : : "1");
}

static inline void restore_vx_regs(__vector128 *vxrs)
{
typedef struct { __vector128 _[__NUM_VXRS]; } addrtype;

asm volatile(
" la 1,%0\n"
" .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */
" .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */
: : "Q" (*(addrtype *) vxrs) : "1");
}

static inline void save_fp_vx_regs(struct task_struct *task)
{
#ifdef CONFIG_64BIT
if (task->thread.vxrs)
save_vx_regs(task->thread.vxrs);
else
#endif
save_fp_regs(task->thread.fp_regs.fprs);
}

static inline void restore_fp_vx_regs(struct task_struct *task)
{
#ifdef CONFIG_64BIT
if (task->thread.vxrs)
restore_vx_regs(task->thread.vxrs);
else
#endif
restore_fp_regs(task->thread.fp_regs.fprs);
}

static inline void save_access_regs(unsigned int *acrs)
{
typedef struct { int _[NUM_ACRS]; } acrstype;
Expand All @@ -120,16 +162,16 @@ static inline void restore_access_regs(unsigned int *acrs)
#define switch_to(prev,next,last) do { \
if (prev->mm) { \
save_fp_ctl(&prev->thread.fp_regs.fpc); \
save_fp_regs(prev->thread.fp_regs.fprs); \
save_fp_vx_regs(prev); \
save_access_regs(&prev->thread.acrs[0]); \
save_ri_cb(prev->thread.ri_cb); \
} \
if (next->mm) { \
update_cr_regs(next); \
restore_fp_ctl(&next->thread.fp_regs.fpc); \
restore_fp_regs(next->thread.fp_regs.fprs); \
restore_fp_vx_regs(next); \
restore_access_regs(&next->thread.acrs[0]); \
restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \
update_cr_regs(next); \
} \
prev = __switch_to(prev,next); \
} while (0)
Expand Down
20 changes: 17 additions & 3 deletions arch/s390/include/uapi/asm/sigcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
#define _ASM_S390_SIGCONTEXT_H

#include <linux/compiler.h>
#include <linux/types.h>

#define __NUM_GPRS 16
#define __NUM_FPRS 16
#define __NUM_ACRS 16
#define __NUM_GPRS 16
#define __NUM_FPRS 16
#define __NUM_ACRS 16
#define __NUM_VXRS 32
#define __NUM_VXRS_LOW 16
#define __NUM_VXRS_HIGH 16

#ifndef __s390x__

Expand Down Expand Up @@ -59,6 +63,16 @@ typedef struct
_s390_fp_regs fpregs;
} _sigregs;

typedef struct
{
#ifndef __s390x__
unsigned long gprs_high[__NUM_GPRS];
#endif
unsigned long long vxrs_low[__NUM_VXRS_LOW];
__vector128 vxrs_high[__NUM_VXRS_HIGH];
unsigned char __reserved[128];
} _sigregs_ext;

struct sigcontext
{
unsigned long oldmask[_SIGCONTEXT_NSIG_WORDS];
Expand Down
4 changes: 4 additions & 0 deletions arch/s390/include/uapi/asm/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
typedef unsigned long addr_t;
typedef __signed__ long saddr_t;

typedef struct {
__u32 u[4];
} __vector128;

#endif /* __ASSEMBLY__ */

#endif /* _UAPI_S390_TYPES_H */
15 changes: 9 additions & 6 deletions arch/s390/include/uapi/asm/ucontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
#ifndef _ASM_S390_UCONTEXT_H
#define _ASM_S390_UCONTEXT_H

#define UC_EXTENDED 0x00000001

#ifndef __s390x__
#define UC_GPRS_HIGH 1 /* uc_mcontext_ext has valid high gprs */
#define UC_VXRS 2 /* uc_mcontext_ext has valid vector regs */

/*
* The struct ucontext_extended describes how the registers are stored
* on a rt signal frame. Please note that the structure is not fixed,
* if new CPU registers are added to the user state the size of the
* struct ucontext_extended will increase.
*/
struct ucontext_extended {
unsigned long uc_flags;
struct ucontext *uc_link;
Expand All @@ -19,11 +24,9 @@ struct ucontext_extended {
sigset_t uc_sigmask;
/* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */
unsigned char __unused[128 - sizeof(sigset_t)];
unsigned long uc_gprs_high[16];
_sigregs_ext uc_mcontext_ext;
};

#endif

struct ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
Expand Down
9 changes: 9 additions & 0 deletions arch/s390/kernel/compat_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ typedef struct
_s390_fp_regs32 fpregs;
} _sigregs32;

typedef struct
{
__u32 gprs_high[__NUM_GPRS];
__u64 vxrs_low[__NUM_VXRS_LOW];
__vector128 vxrs_high[__NUM_VXRS_HIGH];
__u8 __reserved[128];
} _sigregs_ext32;

#define _SIGCONTEXT_NSIG32 64
#define _SIGCONTEXT_NSIG_BPW32 32
#define __SIGNAL_FRAMESIZE32 96
Expand All @@ -72,6 +80,7 @@ struct ucontext32 {
compat_sigset_t uc_sigmask;
/* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */
unsigned char __unused[128 - sizeof(compat_sigset_t)];
_sigregs_ext32 uc_mcontext_ext;
};

struct stat64_emu31;
Expand Down
Loading

0 comments on commit 8070361

Please sign in to comment.