Merge tag 'powerpc-4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc updates from Michael Ellerman: "Highlights: - Major rework of Book3S 64-bit exception vectors (Nicholas Piggin) - Use gas sections for arranging exception vectors et. al. - Large set of TM cleanups and selftests (Cyril Bur) - Enable transactional memory (TM) lazily for userspace (Cyril Bur) - Support for XZ compression in the zImage wrapper (Oliver O'Halloran) - Add support for bpf constant blinding (Naveen N. Rao) - Beginnings of upstream support for PA Semi Nemo motherboards (Darren Stevens) Fixes: - Ensure .mem(init|exit).text are within _stext/_etext (Michael Ellerman) - xmon: Don't use ld on 32-bit (Michael Ellerman) - vdso64: Use double word compare on pointers (Anton Blanchard) - powerpc/nvram: Fix an incorrect partition merge (Pan Xinhui) - powerpc: Fix usage of _PAGE_RO in hugepage (Christophe Leroy) - powerpc/mm: Update FORCE_MAX_ZONEORDER range to allow hugetlb w/4K (Aneesh Kumar K.V) - Fix memory leak in queue_hotplug_event() error path (Andrew Donnellan) - Replay hypervisor maintenance interrupt first (Nicholas Piggin) Various performance optimisations (Anton Blanchard): - Align hot loops of memset() and backwards_memcpy() - During context switch, check before setting mm_cpumask - Remove static branch prediction in atomic{, 64}_add_unless - Only disable HAVE_EFFICIENT_UNALIGNED_ACCESS on POWER7 little endian - Set default CPU type to POWER8 for little endian builds Cleanups & features: - Sparse fixes/cleanups (Daniel Axtens) - Preserve CFAR value on SLB miss caused by access to bogus address (Paul Mackerras) - Radix MMU fixups for POWER9 (Aneesh Kumar K.V) - Support for setting used_(vsr|vr|spe) in sigreturn path (for CRIU) (Simon Guo) - Optimise syscall entry for virtual, relocatable case (Nicholas Piggin) - Optimise MSR handling in exception handling (Nicholas Piggin) - Support for kexec with Radix MMU (Benjamin Herrenschmidt) - powernv EEH fixes (Russell Currey) - Suprise PCI hotplug support for powernv (Gavin Shan) - Endian/sparse fixes for powernv PCI (Gavin Shan) - Defconfig updates (Anton Blanchard) - KVM: PPC: Book3S HV: Migrate pinned pages out of CMA (Balbir Singh) - cxl: Flush PSL cache before resetting the adapter (Frederic Barrat) - cxl: replace loop with for_each_child_of_node(), remove unneeded of_node_put() (Andrew Donnellan) - Fix HV facility unavailable to use correct handler (Nicholas Piggin) - Remove unnecessary syscall trampoline (Nicholas Piggin) - fadump: Fix build break when CONFIG_PROC_VMCORE=n (Michael Ellerman) - Quieten EEH message when no adapters are found (Anton Blanchard) - powernv: Add PHB register dump debugfs handle (Russell Currey) - Use kprobe blacklist for exception handlers & asm functions (Nicholas Piggin) - Document the syscall ABI (Nicholas Piggin) - MAINTAINERS: Update cxl maintainers (Michael Neuling) - powerpc: Remove all usages of NO_IRQ (Michael Ellerman) Minor cleanups: - Andrew Donnellan, Christophe Leroy, Colin Ian King, Cyril Bur, Frederic Barrat, Pan Xinhui, PrasannaKumar Muralidharan, Rui Teng, Simon Guo" * tag 'powerpc-4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (156 commits) powerpc/bpf: Add support for bpf constant blinding powerpc/bpf: Implement support for tail calls powerpc/bpf: Introduce accessors for using the tmp local stack space powerpc/fadump: Fix build break when CONFIG_PROC_VMCORE=n powerpc: tm: Enable transactional memory (TM) lazily for userspace powerpc/tm: Add TM Unavailable Exception powerpc: Remove do_load_up_transact_{fpu,altivec} powerpc: tm: Rename transct_(*) to ck(\1)_state powerpc: tm: Always use fp_state and vr_state to store live registers selftests/powerpc: Add checks for transactional VSXs in signal contexts selftests/powerpc: Add checks for transactional VMXs in signal contexts selftests/powerpc: Add checks for transactional FPUs in signal contexts selftests/powerpc: Add checks for transactional GPRs in signal contexts selftests/powerpc: Check that signals always get delivered selftests/powerpc: Add TM tcheck helpers in C selftests/powerpc: Allow tests to extend their kill timeout selftests/powerpc: Introduce GPR asm helper header file selftests/powerpc: Move VMX stack frame macros to header file selftests/powerpc: Rework FPU stack placement macros and move to header file selftests/powerpc: Check for VSX preservation across userspace preemption ...
This commit is contained in:
@@ -19,6 +19,7 @@ SUB_DIRS = alignment \
|
||||
dscr \
|
||||
mm \
|
||||
pmu \
|
||||
signal \
|
||||
primitives \
|
||||
stringloops \
|
||||
switch_endian \
|
||||
|
80
tools/testing/selftests/powerpc/fpu_asm.h
Normal file
80
tools/testing/selftests/powerpc/fpu_asm.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2016, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SELFTESTS_POWERPC_FPU_ASM_H
|
||||
#define _SELFTESTS_POWERPC_FPU_ASM_H
|
||||
#include "basic_asm.h"
|
||||
|
||||
#define PUSH_FPU(stack_size) \
|
||||
stfd f31,(stack_size + STACK_FRAME_MIN_SIZE)(%r1); \
|
||||
stfd f30,(stack_size + STACK_FRAME_MIN_SIZE - 8)(%r1); \
|
||||
stfd f29,(stack_size + STACK_FRAME_MIN_SIZE - 16)(%r1); \
|
||||
stfd f28,(stack_size + STACK_FRAME_MIN_SIZE - 24)(%r1); \
|
||||
stfd f27,(stack_size + STACK_FRAME_MIN_SIZE - 32)(%r1); \
|
||||
stfd f26,(stack_size + STACK_FRAME_MIN_SIZE - 40)(%r1); \
|
||||
stfd f25,(stack_size + STACK_FRAME_MIN_SIZE - 48)(%r1); \
|
||||
stfd f24,(stack_size + STACK_FRAME_MIN_SIZE - 56)(%r1); \
|
||||
stfd f23,(stack_size + STACK_FRAME_MIN_SIZE - 64)(%r1); \
|
||||
stfd f22,(stack_size + STACK_FRAME_MIN_SIZE - 72)(%r1); \
|
||||
stfd f21,(stack_size + STACK_FRAME_MIN_SIZE - 80)(%r1); \
|
||||
stfd f20,(stack_size + STACK_FRAME_MIN_SIZE - 88)(%r1); \
|
||||
stfd f19,(stack_size + STACK_FRAME_MIN_SIZE - 96)(%r1); \
|
||||
stfd f18,(stack_size + STACK_FRAME_MIN_SIZE - 104)(%r1); \
|
||||
stfd f17,(stack_size + STACK_FRAME_MIN_SIZE - 112)(%r1); \
|
||||
stfd f16,(stack_size + STACK_FRAME_MIN_SIZE - 120)(%r1); \
|
||||
stfd f15,(stack_size + STACK_FRAME_MIN_SIZE - 128)(%r1); \
|
||||
stfd f14,(stack_size + STACK_FRAME_MIN_SIZE - 136)(%r1);
|
||||
|
||||
#define POP_FPU(stack_size) \
|
||||
lfd f31,(stack_size + STACK_FRAME_MIN_SIZE)(%r1); \
|
||||
lfd f30,(stack_size + STACK_FRAME_MIN_SIZE - 8)(%r1); \
|
||||
lfd f29,(stack_size + STACK_FRAME_MIN_SIZE - 16)(%r1); \
|
||||
lfd f28,(stack_size + STACK_FRAME_MIN_SIZE - 24)(%r1); \
|
||||
lfd f27,(stack_size + STACK_FRAME_MIN_SIZE - 32)(%r1); \
|
||||
lfd f26,(stack_size + STACK_FRAME_MIN_SIZE - 40)(%r1); \
|
||||
lfd f25,(stack_size + STACK_FRAME_MIN_SIZE - 48)(%r1); \
|
||||
lfd f24,(stack_size + STACK_FRAME_MIN_SIZE - 56)(%r1); \
|
||||
lfd f23,(stack_size + STACK_FRAME_MIN_SIZE - 64)(%r1); \
|
||||
lfd f22,(stack_size + STACK_FRAME_MIN_SIZE - 72)(%r1); \
|
||||
lfd f21,(stack_size + STACK_FRAME_MIN_SIZE - 80)(%r1); \
|
||||
lfd f20,(stack_size + STACK_FRAME_MIN_SIZE - 88)(%r1); \
|
||||
lfd f19,(stack_size + STACK_FRAME_MIN_SIZE - 96)(%r1); \
|
||||
lfd f18,(stack_size + STACK_FRAME_MIN_SIZE - 104)(%r1); \
|
||||
lfd f17,(stack_size + STACK_FRAME_MIN_SIZE - 112)(%r1); \
|
||||
lfd f16,(stack_size + STACK_FRAME_MIN_SIZE - 120)(%r1); \
|
||||
lfd f15,(stack_size + STACK_FRAME_MIN_SIZE - 128)(%r1); \
|
||||
lfd f14,(stack_size + STACK_FRAME_MIN_SIZE - 136)(%r1);
|
||||
|
||||
/*
|
||||
* Careful calling this, it will 'clobber' fpu (by design)
|
||||
* Don't call this from C
|
||||
*/
|
||||
FUNC_START(load_fpu)
|
||||
lfd f14,0(r3)
|
||||
lfd f15,8(r3)
|
||||
lfd f16,16(r3)
|
||||
lfd f17,24(r3)
|
||||
lfd f18,32(r3)
|
||||
lfd f19,40(r3)
|
||||
lfd f20,48(r3)
|
||||
lfd f21,56(r3)
|
||||
lfd f22,64(r3)
|
||||
lfd f23,72(r3)
|
||||
lfd f24,80(r3)
|
||||
lfd f25,88(r3)
|
||||
lfd f26,96(r3)
|
||||
lfd f27,104(r3)
|
||||
lfd f28,112(r3)
|
||||
lfd f29,120(r3)
|
||||
lfd f30,128(r3)
|
||||
lfd f31,136(r3)
|
||||
blr
|
||||
FUNC_END(load_fpu)
|
||||
|
||||
#endif /* _SELFTESTS_POWERPC_FPU_ASM_H */
|
96
tools/testing/selftests/powerpc/gpr_asm.h
Normal file
96
tools/testing/selftests/powerpc/gpr_asm.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2016, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SELFTESTS_POWERPC_GPR_ASM_H
|
||||
#define _SELFTESTS_POWERPC_GPR_ASM_H
|
||||
|
||||
#include "basic_asm.h"
|
||||
|
||||
#define __PUSH_NVREGS(top_pos); \
|
||||
std r31,(top_pos)(%r1); \
|
||||
std r30,(top_pos - 8)(%r1); \
|
||||
std r29,(top_pos - 16)(%r1); \
|
||||
std r28,(top_pos - 24)(%r1); \
|
||||
std r27,(top_pos - 32)(%r1); \
|
||||
std r26,(top_pos - 40)(%r1); \
|
||||
std r25,(top_pos - 48)(%r1); \
|
||||
std r24,(top_pos - 56)(%r1); \
|
||||
std r23,(top_pos - 64)(%r1); \
|
||||
std r22,(top_pos - 72)(%r1); \
|
||||
std r21,(top_pos - 80)(%r1); \
|
||||
std r20,(top_pos - 88)(%r1); \
|
||||
std r19,(top_pos - 96)(%r1); \
|
||||
std r18,(top_pos - 104)(%r1); \
|
||||
std r17,(top_pos - 112)(%r1); \
|
||||
std r16,(top_pos - 120)(%r1); \
|
||||
std r15,(top_pos - 128)(%r1); \
|
||||
std r14,(top_pos - 136)(%r1)
|
||||
|
||||
#define __POP_NVREGS(top_pos); \
|
||||
ld r31,(top_pos)(%r1); \
|
||||
ld r30,(top_pos - 8)(%r1); \
|
||||
ld r29,(top_pos - 16)(%r1); \
|
||||
ld r28,(top_pos - 24)(%r1); \
|
||||
ld r27,(top_pos - 32)(%r1); \
|
||||
ld r26,(top_pos - 40)(%r1); \
|
||||
ld r25,(top_pos - 48)(%r1); \
|
||||
ld r24,(top_pos - 56)(%r1); \
|
||||
ld r23,(top_pos - 64)(%r1); \
|
||||
ld r22,(top_pos - 72)(%r1); \
|
||||
ld r21,(top_pos - 80)(%r1); \
|
||||
ld r20,(top_pos - 88)(%r1); \
|
||||
ld r19,(top_pos - 96)(%r1); \
|
||||
ld r18,(top_pos - 104)(%r1); \
|
||||
ld r17,(top_pos - 112)(%r1); \
|
||||
ld r16,(top_pos - 120)(%r1); \
|
||||
ld r15,(top_pos - 128)(%r1); \
|
||||
ld r14,(top_pos - 136)(%r1)
|
||||
|
||||
#define PUSH_NVREGS(stack_size) \
|
||||
__PUSH_NVREGS(stack_size + STACK_FRAME_MIN_SIZE)
|
||||
|
||||
/* 18 NV FPU REGS */
|
||||
#define PUSH_NVREGS_BELOW_FPU(stack_size) \
|
||||
__PUSH_NVREGS(stack_size + STACK_FRAME_MIN_SIZE - (18 * 8))
|
||||
|
||||
#define POP_NVREGS(stack_size) \
|
||||
__POP_NVREGS(stack_size + STACK_FRAME_MIN_SIZE)
|
||||
|
||||
/* 18 NV FPU REGS */
|
||||
#define POP_NVREGS_BELOW_FPU(stack_size) \
|
||||
__POP_NVREGS(stack_size + STACK_FRAME_MIN_SIZE - (18 * 8))
|
||||
|
||||
/*
|
||||
* Careful calling this, it will 'clobber' NVGPRs (by design)
|
||||
* Don't call this from C
|
||||
*/
|
||||
FUNC_START(load_gpr)
|
||||
ld r14,0(r3)
|
||||
ld r15,8(r3)
|
||||
ld r16,16(r3)
|
||||
ld r17,24(r3)
|
||||
ld r18,32(r3)
|
||||
ld r19,40(r3)
|
||||
ld r20,48(r3)
|
||||
ld r21,56(r3)
|
||||
ld r22,64(r3)
|
||||
ld r23,72(r3)
|
||||
ld r24,80(r3)
|
||||
ld r25,88(r3)
|
||||
ld r26,96(r3)
|
||||
ld r27,104(r3)
|
||||
ld r28,112(r3)
|
||||
ld r29,120(r3)
|
||||
ld r30,128(r3)
|
||||
ld r31,136(r3)
|
||||
blr
|
||||
FUNC_END(load_gpr)
|
||||
|
||||
|
||||
#endif /* _SELFTESTS_POWERPC_GPR_ASM_H */
|
@@ -19,9 +19,9 @@
|
||||
#include "subunit.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define TIMEOUT 120
|
||||
#define KILL_TIMEOUT 5
|
||||
|
||||
static uint64_t timeout = 120;
|
||||
|
||||
int run_test(int (test_function)(void), char *name)
|
||||
{
|
||||
@@ -44,7 +44,7 @@ int run_test(int (test_function)(void), char *name)
|
||||
setpgid(pid, pid);
|
||||
|
||||
/* Wake us up in timeout seconds */
|
||||
alarm(TIMEOUT);
|
||||
alarm(timeout);
|
||||
terminated = false;
|
||||
|
||||
wait:
|
||||
@@ -94,6 +94,11 @@ static struct sigaction alarm_action = {
|
||||
.sa_handler = alarm_handler,
|
||||
};
|
||||
|
||||
void test_harness_set_timeout(uint64_t time)
|
||||
{
|
||||
timeout = time;
|
||||
}
|
||||
|
||||
int test_harness(int (test_function)(void), char *name)
|
||||
{
|
||||
int rc;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal
|
||||
TEST_PROGS := fpu_syscall fpu_preempt fpu_signal vmx_syscall vmx_preempt vmx_signal vsx_preempt
|
||||
|
||||
all: $(TEST_PROGS)
|
||||
|
||||
@@ -13,6 +13,9 @@ vmx_syscall: vmx_asm.S
|
||||
vmx_preempt: vmx_asm.S
|
||||
vmx_signal: vmx_asm.S
|
||||
|
||||
vsx_preempt: CFLAGS += -mvsx
|
||||
vsx_preempt: vsx_asm.S
|
||||
|
||||
include ../../lib.mk
|
||||
|
||||
clean:
|
||||
|
@@ -8,70 +8,7 @@
|
||||
*/
|
||||
|
||||
#include "../basic_asm.h"
|
||||
|
||||
#define PUSH_FPU(pos) \
|
||||
stfd f14,pos(sp); \
|
||||
stfd f15,pos+8(sp); \
|
||||
stfd f16,pos+16(sp); \
|
||||
stfd f17,pos+24(sp); \
|
||||
stfd f18,pos+32(sp); \
|
||||
stfd f19,pos+40(sp); \
|
||||
stfd f20,pos+48(sp); \
|
||||
stfd f21,pos+56(sp); \
|
||||
stfd f22,pos+64(sp); \
|
||||
stfd f23,pos+72(sp); \
|
||||
stfd f24,pos+80(sp); \
|
||||
stfd f25,pos+88(sp); \
|
||||
stfd f26,pos+96(sp); \
|
||||
stfd f27,pos+104(sp); \
|
||||
stfd f28,pos+112(sp); \
|
||||
stfd f29,pos+120(sp); \
|
||||
stfd f30,pos+128(sp); \
|
||||
stfd f31,pos+136(sp);
|
||||
|
||||
#define POP_FPU(pos) \
|
||||
lfd f14,pos(sp); \
|
||||
lfd f15,pos+8(sp); \
|
||||
lfd f16,pos+16(sp); \
|
||||
lfd f17,pos+24(sp); \
|
||||
lfd f18,pos+32(sp); \
|
||||
lfd f19,pos+40(sp); \
|
||||
lfd f20,pos+48(sp); \
|
||||
lfd f21,pos+56(sp); \
|
||||
lfd f22,pos+64(sp); \
|
||||
lfd f23,pos+72(sp); \
|
||||
lfd f24,pos+80(sp); \
|
||||
lfd f25,pos+88(sp); \
|
||||
lfd f26,pos+96(sp); \
|
||||
lfd f27,pos+104(sp); \
|
||||
lfd f28,pos+112(sp); \
|
||||
lfd f29,pos+120(sp); \
|
||||
lfd f30,pos+128(sp); \
|
||||
lfd f31,pos+136(sp);
|
||||
|
||||
# Careful calling this, it will 'clobber' fpu (by design)
|
||||
# Don't call this from C
|
||||
FUNC_START(load_fpu)
|
||||
lfd f14,0(r3)
|
||||
lfd f15,8(r3)
|
||||
lfd f16,16(r3)
|
||||
lfd f17,24(r3)
|
||||
lfd f18,32(r3)
|
||||
lfd f19,40(r3)
|
||||
lfd f20,48(r3)
|
||||
lfd f21,56(r3)
|
||||
lfd f22,64(r3)
|
||||
lfd f23,72(r3)
|
||||
lfd f24,80(r3)
|
||||
lfd f25,88(r3)
|
||||
lfd f26,96(r3)
|
||||
lfd f27,104(r3)
|
||||
lfd f28,112(r3)
|
||||
lfd f29,120(r3)
|
||||
lfd f30,128(r3)
|
||||
lfd f31,136(r3)
|
||||
blr
|
||||
FUNC_END(load_fpu)
|
||||
#include "../fpu_asm.h"
|
||||
|
||||
FUNC_START(check_fpu)
|
||||
mr r4,r3
|
||||
@@ -138,9 +75,9 @@ FUNC_START(test_fpu)
|
||||
# r4 holds pointer to the pid
|
||||
# f14-f31 are non volatiles
|
||||
PUSH_BASIC_STACK(256)
|
||||
PUSH_FPU(256)
|
||||
std r3,STACK_FRAME_PARAM(0)(sp) # Address of darray
|
||||
std r4,STACK_FRAME_PARAM(1)(sp) # Address of pid
|
||||
PUSH_FPU(STACK_FRAME_LOCAL(2,0))
|
||||
|
||||
bl load_fpu
|
||||
nop
|
||||
@@ -155,7 +92,7 @@ FUNC_START(test_fpu)
|
||||
bl check_fpu
|
||||
nop
|
||||
|
||||
POP_FPU(STACK_FRAME_LOCAL(2,0))
|
||||
POP_FPU(256)
|
||||
POP_BASIC_STACK(256)
|
||||
blr
|
||||
FUNC_END(test_fpu)
|
||||
@@ -166,10 +103,10 @@ FUNC_END(test_fpu)
|
||||
# registers while running is not zero.
|
||||
FUNC_START(preempt_fpu)
|
||||
PUSH_BASIC_STACK(256)
|
||||
PUSH_FPU(256)
|
||||
std r3,STACK_FRAME_PARAM(0)(sp) # double *darray
|
||||
std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting
|
||||
std r5,STACK_FRAME_PARAM(2)(sp) # int *running
|
||||
PUSH_FPU(STACK_FRAME_LOCAL(3,0))
|
||||
|
||||
bl load_fpu
|
||||
nop
|
||||
@@ -192,7 +129,7 @@ FUNC_START(preempt_fpu)
|
||||
cmpwi r5,0
|
||||
bne 2b
|
||||
|
||||
3: POP_FPU(STACK_FRAME_LOCAL(3,0))
|
||||
3: POP_FPU(256)
|
||||
POP_BASIC_STACK(256)
|
||||
blr
|
||||
FUNC_END(preempt_fpu)
|
||||
|
@@ -8,90 +8,7 @@
|
||||
*/
|
||||
|
||||
#include "../basic_asm.h"
|
||||
|
||||
# POS MUST BE 16 ALIGNED!
|
||||
#define PUSH_VMX(pos,reg) \
|
||||
li reg,pos; \
|
||||
stvx v20,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v21,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v22,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v23,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v24,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v25,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v26,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v27,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v28,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v29,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v30,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
stvx v31,reg,sp;
|
||||
|
||||
# POS MUST BE 16 ALIGNED!
|
||||
#define POP_VMX(pos,reg) \
|
||||
li reg,pos; \
|
||||
lvx v20,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v21,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v22,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v23,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v24,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v25,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v26,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v27,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v28,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v29,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v30,reg,sp; \
|
||||
addi reg,reg,16; \
|
||||
lvx v31,reg,sp;
|
||||
|
||||
# Carefull this will 'clobber' vmx (by design)
|
||||
# Don't call this from C
|
||||
FUNC_START(load_vmx)
|
||||
li r5,0
|
||||
lvx v20,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v21,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v22,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v23,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v24,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v25,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v26,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v27,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v28,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v29,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v30,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v31,r5,r3
|
||||
blr
|
||||
FUNC_END(load_vmx)
|
||||
#include "../vmx_asm.h"
|
||||
|
||||
# Should be safe from C, only touches r4, r5 and v0,v1,v2
|
||||
FUNC_START(check_vmx)
|
||||
|
61
tools/testing/selftests/powerpc/math/vsx_asm.S
Normal file
61
tools/testing/selftests/powerpc/math/vsx_asm.S
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2015, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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 "../basic_asm.h"
|
||||
#include "../vsx_asm.h"
|
||||
|
||||
#long check_vsx(vector int *r3);
|
||||
#This function wraps storeing VSX regs to the end of an array and a
|
||||
#call to a comparison function in C which boils down to a memcmp()
|
||||
FUNC_START(check_vsx)
|
||||
PUSH_BASIC_STACK(32)
|
||||
std r3,STACK_FRAME_PARAM(0)(sp)
|
||||
addi r3, r3, 16 * 12 #Second half of array
|
||||
bl store_vsx
|
||||
ld r3,STACK_FRAME_PARAM(0)(sp)
|
||||
bl vsx_memcmp
|
||||
POP_BASIC_STACK(32)
|
||||
blr
|
||||
FUNC_END(check_vsx)
|
||||
|
||||
# int preempt_vmx(vector int *varray, int *threads_starting,
|
||||
# int *running);
|
||||
# On starting will (atomically) decrement threads_starting as a signal
|
||||
# that the VMX have been loaded with varray. Will proceed to check the
|
||||
# validity of the VMX registers while running is not zero.
|
||||
FUNC_START(preempt_vsx)
|
||||
PUSH_BASIC_STACK(512)
|
||||
std r3,STACK_FRAME_PARAM(0)(sp) # vector int *varray
|
||||
std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting
|
||||
std r5,STACK_FRAME_PARAM(2)(sp) # int *running
|
||||
|
||||
bl load_vsx
|
||||
nop
|
||||
|
||||
sync
|
||||
# Atomic DEC
|
||||
ld r3,STACK_FRAME_PARAM(1)(sp)
|
||||
1: lwarx r4,0,r3
|
||||
addi r4,r4,-1
|
||||
stwcx. r4,0,r3
|
||||
bne- 1b
|
||||
|
||||
2: ld r3,STACK_FRAME_PARAM(0)(sp)
|
||||
bl check_vsx
|
||||
nop
|
||||
cmpdi r3,0
|
||||
bne 3f
|
||||
ld r4,STACK_FRAME_PARAM(2)(sp)
|
||||
ld r5,0(r4)
|
||||
cmpwi r5,0
|
||||
bne 2b
|
||||
|
||||
3: POP_BASIC_STACK(512)
|
||||
blr
|
||||
FUNC_END(preempt_vsx)
|
147
tools/testing/selftests/powerpc/math/vsx_preempt.c
Normal file
147
tools/testing/selftests/powerpc/math/vsx_preempt.c
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2015, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This test attempts to see if the VSX registers change across preemption.
|
||||
* There is no way to be sure preemption happened so this test just
|
||||
* uses many threads and a long wait. As such, a successful test
|
||||
* doesn't mean much but a failure is bad.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
/* Time to wait for workers to get preempted (seconds) */
|
||||
#define PREEMPT_TIME 20
|
||||
/*
|
||||
* Factor by which to multiply number of online CPUs for total number of
|
||||
* worker threads
|
||||
*/
|
||||
#define THREAD_FACTOR 8
|
||||
|
||||
/*
|
||||
* Ensure there is twice the number of non-volatile VMX regs!
|
||||
* check_vmx() is going to use the other half as space to put the live
|
||||
* registers before calling vsx_memcmp()
|
||||
*/
|
||||
__thread vector int varray[24] = {
|
||||
{1, 2, 3, 4 }, {5, 6, 7, 8 }, {9, 10,11,12},
|
||||
{13,14,15,16}, {17,18,19,20}, {21,22,23,24},
|
||||
{25,26,27,28}, {29,30,31,32}, {33,34,35,36},
|
||||
{37,38,39,40}, {41,42,43,44}, {45,46,47,48}
|
||||
};
|
||||
|
||||
int threads_starting;
|
||||
int running;
|
||||
|
||||
extern long preempt_vsx(vector int *varray, int *threads_starting, int *running);
|
||||
|
||||
long vsx_memcmp(vector int *a) {
|
||||
vector int zero = {0, 0, 0, 0};
|
||||
int i;
|
||||
|
||||
FAIL_IF(a != varray);
|
||||
|
||||
for(i = 0; i < 12; i++) {
|
||||
if (memcmp(&a[i + 12], &zero, sizeof(vector int)) == 0) {
|
||||
fprintf(stderr, "Detected zero from the VSX reg %d\n", i + 12);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(a, &a[12], 12 * sizeof(vector int))) {
|
||||
long *p = (long *)a;
|
||||
fprintf(stderr, "VSX mismatch\n");
|
||||
for (i = 0; i < 24; i=i+2)
|
||||
fprintf(stderr, "%d: 0x%08lx%08lx | 0x%08lx%08lx\n",
|
||||
i/2 + i%2 + 20, p[i], p[i + 1], p[i + 24], p[i + 25]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *preempt_vsx_c(void *p)
|
||||
{
|
||||
int i, j;
|
||||
long rc;
|
||||
srand(pthread_self());
|
||||
for (i = 0; i < 12; i++)
|
||||
for (j = 0; j < 4; j++) {
|
||||
varray[i][j] = rand();
|
||||
/* Don't want zero because it hides kernel problems */
|
||||
if (varray[i][j] == 0)
|
||||
j--;
|
||||
}
|
||||
rc = preempt_vsx(varray, &threads_starting, &running);
|
||||
if (rc == 2)
|
||||
fprintf(stderr, "Caught zeros in VSX compares\n");
|
||||
return (void *)rc;
|
||||
}
|
||||
|
||||
int test_preempt_vsx(void)
|
||||
{
|
||||
int i, rc, threads;
|
||||
pthread_t *tids;
|
||||
|
||||
threads = sysconf(_SC_NPROCESSORS_ONLN) * THREAD_FACTOR;
|
||||
tids = malloc(threads * sizeof(pthread_t));
|
||||
FAIL_IF(!tids);
|
||||
|
||||
running = true;
|
||||
threads_starting = threads;
|
||||
for (i = 0; i < threads; i++) {
|
||||
rc = pthread_create(&tids[i], NULL, preempt_vsx_c, NULL);
|
||||
FAIL_IF(rc);
|
||||
}
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
/* Not really nessesary but nice to wait for every thread to start */
|
||||
printf("\tWaiting for %d workers to start...", threads_starting);
|
||||
while(threads_starting)
|
||||
asm volatile("": : :"memory");
|
||||
printf("done\n");
|
||||
|
||||
printf("\tWaiting for %d seconds to let some workers get preempted...", PREEMPT_TIME);
|
||||
sleep(PREEMPT_TIME);
|
||||
printf("done\n");
|
||||
|
||||
printf("\tStopping workers...");
|
||||
/*
|
||||
* Working are checking this value every loop. In preempt_vsx 'cmpwi r5,0; bne 2b'.
|
||||
* r5 will have loaded the value of running.
|
||||
*/
|
||||
running = 0;
|
||||
for (i = 0; i < threads; i++) {
|
||||
void *rc_p;
|
||||
pthread_join(tids[i], &rc_p);
|
||||
|
||||
/*
|
||||
* Harness will say the fail was here, look at why preempt_vsx
|
||||
* returned
|
||||
*/
|
||||
if ((long) rc_p)
|
||||
printf("oops\n");
|
||||
FAIL_IF((long) rc_p);
|
||||
}
|
||||
printf("done\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return test_harness(test_preempt_vsx, "vsx_preempt");
|
||||
}
|
13
tools/testing/selftests/powerpc/signal/Makefile
Normal file
13
tools/testing/selftests/powerpc/signal/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
TEST_PROGS := signal signal_tm
|
||||
|
||||
all: $(TEST_PROGS)
|
||||
|
||||
$(TEST_PROGS): ../harness.c ../utils.c signal.S
|
||||
|
||||
CFLAGS += -maltivec
|
||||
signal_tm: CFLAGS += -mhtm
|
||||
|
||||
include ../../lib.mk
|
||||
|
||||
clean:
|
||||
rm -f $(TEST_PROGS) *.o
|
50
tools/testing/selftests/powerpc/signal/signal.S
Normal file
50
tools/testing/selftests/powerpc/signal/signal.S
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2015, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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 "../basic_asm.h"
|
||||
|
||||
/* long signal_self(pid_t pid, int sig); */
|
||||
FUNC_START(signal_self)
|
||||
li r0,37 /* sys_kill */
|
||||
/* r3 already has our pid in it */
|
||||
/* r4 already has signal type in it */
|
||||
sc
|
||||
bc 4,3,1f
|
||||
subfze r3,r3
|
||||
1: blr
|
||||
FUNC_END(signal_self)
|
||||
|
||||
/* long tm_signal_self(pid_t pid, int sig, int *ret); */
|
||||
FUNC_START(tm_signal_self)
|
||||
PUSH_BASIC_STACK(8)
|
||||
std r5,STACK_FRAME_PARAM(0)(sp) /* ret */
|
||||
tbegin.
|
||||
beq 1f
|
||||
tsuspend.
|
||||
li r0,37 /* sys_kill */
|
||||
/* r3 already has our pid in it */
|
||||
/* r4 already has signal type in it */
|
||||
sc
|
||||
ld r5,STACK_FRAME_PARAM(0)(sp) /* ret */
|
||||
bc 4,3,2f
|
||||
subfze r3,r3
|
||||
2: std r3,0(r5)
|
||||
tabort. 0
|
||||
tresume. /* Be nice to some cleanup, jumps back to tbegin then to 1: */
|
||||
/*
|
||||
* Transaction should be proper doomed and we should never get
|
||||
* here
|
||||
*/
|
||||
li r3,1
|
||||
POP_BASIC_STACK(8)
|
||||
blr
|
||||
1: li r3,0
|
||||
POP_BASIC_STACK(8)
|
||||
blr
|
||||
FUNC_END(tm_signal_self)
|
111
tools/testing/selftests/powerpc/signal/signal.c
Normal file
111
tools/testing/selftests/powerpc/signal/signal.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2016, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Sending one self a signal should always get delivered.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <altivec.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define MAX_ATTEMPT 500000
|
||||
#define TIMEOUT 5
|
||||
|
||||
extern long signal_self(pid_t pid, int sig);
|
||||
|
||||
static sig_atomic_t signaled;
|
||||
static sig_atomic_t fail;
|
||||
|
||||
static void signal_handler(int sig)
|
||||
{
|
||||
if (sig == SIGUSR1)
|
||||
signaled = 1;
|
||||
else
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
static int test_signal()
|
||||
{
|
||||
int i;
|
||||
struct sigaction act;
|
||||
pid_t ppid = getpid();
|
||||
pid_t pid;
|
||||
|
||||
act.sa_handler = signal_handler;
|
||||
act.sa_flags = 0;
|
||||
sigemptyset(&act.sa_mask);
|
||||
if (sigaction(SIGUSR1, &act, NULL) < 0) {
|
||||
perror("sigaction SIGUSR1");
|
||||
exit(1);
|
||||
}
|
||||
if (sigaction(SIGALRM, &act, NULL) < 0) {
|
||||
perror("sigaction SIGALRM");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Don't do this for MAX_ATTEMPT, its simply too long */
|
||||
for(i = 0; i < 1000; i++) {
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
perror("fork");
|
||||
exit(1);
|
||||
}
|
||||
if (pid == 0) {
|
||||
signal_self(ppid, SIGUSR1);
|
||||
exit(1);
|
||||
} else {
|
||||
alarm(0); /* Disable any pending */
|
||||
alarm(2);
|
||||
while (!signaled && !fail)
|
||||
asm volatile("": : :"memory");
|
||||
if (!signaled) {
|
||||
fprintf(stderr, "Didn't get signal from child\n");
|
||||
FAIL_IF(1); /* For the line number */
|
||||
}
|
||||
/* Otherwise we'll loop too fast and fork() will eventually fail */
|
||||
waitpid(pid, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_ATTEMPT; i++) {
|
||||
long rc;
|
||||
|
||||
alarm(0); /* Disable any pending */
|
||||
signaled = 0;
|
||||
alarm(TIMEOUT);
|
||||
rc = signal_self(ppid, SIGUSR1);
|
||||
if (rc) {
|
||||
fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx",
|
||||
i, fail, rc);
|
||||
FAIL_IF(1); /* For the line number */
|
||||
}
|
||||
while (!signaled && !fail)
|
||||
asm volatile("": : :"memory");
|
||||
if (!signaled) {
|
||||
fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx",
|
||||
i, fail, rc);
|
||||
FAIL_IF(1); /* For the line number */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_harness_set_timeout(300);
|
||||
return test_harness(test_signal, "signal");
|
||||
}
|
110
tools/testing/selftests/powerpc/signal/signal_tm.c
Normal file
110
tools/testing/selftests/powerpc/signal/signal_tm.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2016, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Sending one self a signal should always get delivered.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <altivec.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "../tm/tm.h"
|
||||
|
||||
#define MAX_ATTEMPT 500000
|
||||
#define TIMEOUT 10
|
||||
|
||||
extern long tm_signal_self(pid_t pid, int sig, long *ret);
|
||||
|
||||
static sig_atomic_t signaled;
|
||||
static sig_atomic_t fail;
|
||||
|
||||
static void signal_handler(int sig)
|
||||
{
|
||||
if (tcheck_active()) {
|
||||
fail = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sig == SIGUSR1)
|
||||
signaled = 1;
|
||||
else
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
static int test_signal_tm()
|
||||
{
|
||||
int i;
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_handler = signal_handler;
|
||||
act.sa_flags = 0;
|
||||
sigemptyset(&act.sa_mask);
|
||||
if (sigaction(SIGUSR1, &act, NULL) < 0) {
|
||||
perror("sigaction SIGUSR1");
|
||||
exit(1);
|
||||
}
|
||||
if (sigaction(SIGALRM, &act, NULL) < 0) {
|
||||
perror("sigaction SIGALRM");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
SKIP_IF(!have_htm());
|
||||
|
||||
for (i = 0; i < MAX_ATTEMPT; i++) {
|
||||
/*
|
||||
* If anything bad happens in ASM and we fail to set ret
|
||||
* because *handwave* TM this will cause failure
|
||||
*/
|
||||
long ret = 0xdead;
|
||||
long rc = 0xbeef;
|
||||
|
||||
alarm(0); /* Disable any pending */
|
||||
signaled = 0;
|
||||
alarm(TIMEOUT);
|
||||
FAIL_IF(tcheck_transactional());
|
||||
rc = tm_signal_self(getpid(), SIGUSR1, &ret);
|
||||
if (ret == 0xdead)
|
||||
/*
|
||||
* This basically means the transaction aborted before we
|
||||
* even got to the suspend... this is crazy but it
|
||||
* happens.
|
||||
* Yes this also means we might never make forward
|
||||
* progress... the alarm() will trip eventually...
|
||||
*/
|
||||
continue;
|
||||
|
||||
if (rc || ret) {
|
||||
/* Ret is actually an errno */
|
||||
printf("TEXASR 0x%016lx, TFIAR 0x%016lx\n",
|
||||
__builtin_get_texasr(), __builtin_get_tfiar());
|
||||
fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx ret=0x%lx\n",
|
||||
i, fail, rc, ret);
|
||||
FAIL_IF(ret);
|
||||
}
|
||||
while(!signaled && !fail)
|
||||
asm volatile("": : :"memory");
|
||||
if (!signaled) {
|
||||
fprintf(stderr, "(%d) Fail reason: %d rc=0x%lx ret=0x%lx\n",
|
||||
i, fail, rc, ret);
|
||||
FAIL_IF(fail); /* For the line number */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return test_harness(test_signal_tm, "signal_tm");
|
||||
}
|
@@ -1,5 +1,8 @@
|
||||
SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu \
|
||||
tm-signal-context-chk-vmx tm-signal-context-chk-vsx
|
||||
|
||||
TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \
|
||||
tm-vmxcopy tm-fork tm-tar tm-tmspr tm-exec tm-execed
|
||||
tm-vmxcopy tm-fork tm-tar tm-tmspr $(SIGNAL_CONTEXT_CHK_TESTS)
|
||||
|
||||
all: $(TEST_PROGS)
|
||||
|
||||
@@ -11,6 +14,9 @@ tm-syscall: tm-syscall-asm.S
|
||||
tm-syscall: CFLAGS += -I../../../../../usr/include
|
||||
tm-tmspr: CFLAGS += -pthread
|
||||
|
||||
$(SIGNAL_CONTEXT_CHK_TESTS): tm-signal.S
|
||||
$(SIGNAL_CONTEXT_CHK_TESTS): CFLAGS += -mhtm -m64 -mvsx
|
||||
|
||||
include ../../lib.mk
|
||||
|
||||
clean:
|
||||
|
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2016, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* Test the kernel's signal frame code.
|
||||
*
|
||||
* The kernel sets up two sets of ucontexts if the signal was to be
|
||||
* delivered while the thread was in a transaction.
|
||||
* Expected behaviour is that the checkpointed state is in the user
|
||||
* context passed to the signal handler. The speculated state can be
|
||||
* accessed with the uc_link pointer.
|
||||
*
|
||||
* The rationale for this is that if TM unaware code (which linked
|
||||
* against TM libs) installs a signal handler it will not know of the
|
||||
* speculative nature of the 'live' registers and may infer the wrong
|
||||
* thing.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <altivec.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "tm.h"
|
||||
|
||||
#define MAX_ATTEMPT 500000
|
||||
|
||||
#define NV_FPU_REGS 18
|
||||
|
||||
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
|
||||
|
||||
/* Be sure there are 2x as many as there are NV FPU regs (2x18) */
|
||||
static double fps[] = {
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18
|
||||
};
|
||||
|
||||
static sig_atomic_t fail;
|
||||
|
||||
static void signal_usr1(int signum, siginfo_t *info, void *uc)
|
||||
{
|
||||
int i;
|
||||
ucontext_t *ucp = uc;
|
||||
ucontext_t *tm_ucp = ucp->uc_link;
|
||||
|
||||
for (i = 0; i < NV_FPU_REGS && !fail; i++) {
|
||||
fail = (ucp->uc_mcontext.fp_regs[i + 14] != fps[i]);
|
||||
fail |= (tm_ucp->uc_mcontext.fp_regs[i + 14] != fps[i + NV_FPU_REGS]);
|
||||
if (fail)
|
||||
printf("Failed on %d FP %g or %g\n", i, ucp->uc_mcontext.fp_regs[i + 14], tm_ucp->uc_mcontext.fp_regs[i + 14]);
|
||||
}
|
||||
}
|
||||
|
||||
static int tm_signal_context_chk_fpu()
|
||||
{
|
||||
struct sigaction act;
|
||||
int i;
|
||||
long rc;
|
||||
pid_t pid = getpid();
|
||||
|
||||
SKIP_IF(!have_htm());
|
||||
|
||||
act.sa_sigaction = signal_usr1;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGUSR1, &act, NULL) < 0) {
|
||||
perror("sigaction sigusr1");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < MAX_ATTEMPT && !fail) {
|
||||
rc = tm_signal_self_context_load(pid, NULL, fps, NULL, NULL);
|
||||
FAIL_IF(rc != pid);
|
||||
i++;
|
||||
}
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return test_harness(tm_signal_context_chk_fpu, "tm_signal_context_chk_fpu");
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2016, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* Test the kernel's signal frame code.
|
||||
*
|
||||
* The kernel sets up two sets of ucontexts if the signal was to be
|
||||
* delivered while the thread was in a transaction.
|
||||
* Expected behaviour is that the checkpointed state is in the user
|
||||
* context passed to the signal handler. The speculated state can be
|
||||
* accessed with the uc_link pointer.
|
||||
*
|
||||
* The rationale for this is that if TM unaware code (which linked
|
||||
* against TM libs) installs a signal handler it will not know of the
|
||||
* speculative nature of the 'live' registers and may infer the wrong
|
||||
* thing.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <altivec.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "tm.h"
|
||||
|
||||
#define MAX_ATTEMPT 500000
|
||||
|
||||
#define NV_GPR_REGS 18
|
||||
|
||||
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
|
||||
|
||||
static sig_atomic_t fail;
|
||||
|
||||
static long gps[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
|
||||
-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18};
|
||||
|
||||
static void signal_usr1(int signum, siginfo_t *info, void *uc)
|
||||
{
|
||||
int i;
|
||||
ucontext_t *ucp = uc;
|
||||
ucontext_t *tm_ucp = ucp->uc_link;
|
||||
|
||||
for (i = 0; i < NV_GPR_REGS && !fail; i++) {
|
||||
fail = (ucp->uc_mcontext.gp_regs[i + 14] != gps[i]);
|
||||
fail |= (tm_ucp->uc_mcontext.gp_regs[i + 14] != gps[i + NV_GPR_REGS]);
|
||||
if (fail)
|
||||
printf("Failed on %d GPR %lu or %lu\n", i,
|
||||
ucp->uc_mcontext.gp_regs[i + 14], tm_ucp->uc_mcontext.gp_regs[i + 14]);
|
||||
}
|
||||
}
|
||||
|
||||
static int tm_signal_context_chk_gpr()
|
||||
{
|
||||
struct sigaction act;
|
||||
int i;
|
||||
long rc;
|
||||
pid_t pid = getpid();
|
||||
|
||||
SKIP_IF(!have_htm());
|
||||
|
||||
act.sa_sigaction = signal_usr1;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGUSR1, &act, NULL) < 0) {
|
||||
perror("sigaction sigusr1");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < MAX_ATTEMPT && !fail) {
|
||||
rc = tm_signal_self_context_load(pid, gps, NULL, NULL, NULL);
|
||||
FAIL_IF(rc != pid);
|
||||
i++;
|
||||
}
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return test_harness(tm_signal_context_chk_gpr, "tm_signal_context_chk_gpr");
|
||||
}
|
110
tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c
Normal file
110
tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vmx.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2016, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* Test the kernel's signal frame code.
|
||||
*
|
||||
* The kernel sets up two sets of ucontexts if the signal was to be
|
||||
* delivered while the thread was in a transaction.
|
||||
* Expected behaviour is that the checkpointed state is in the user
|
||||
* context passed to the signal handler. The speculated state can be
|
||||
* accessed with the uc_link pointer.
|
||||
*
|
||||
* The rationale for this is that if TM unaware code (which linked
|
||||
* against TM libs) installs a signal handler it will not know of the
|
||||
* speculative nature of the 'live' registers and may infer the wrong
|
||||
* thing.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <altivec.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "tm.h"
|
||||
|
||||
#define MAX_ATTEMPT 500000
|
||||
|
||||
#define NV_VMX_REGS 12
|
||||
|
||||
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
|
||||
|
||||
static sig_atomic_t fail;
|
||||
|
||||
vector int vms[] = {
|
||||
{1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12},
|
||||
{13,14,15,16},{17,18,19,20},{21,22,23,24},
|
||||
{25,26,27,28},{29,30,31,32},{33,34,35,36},
|
||||
{37,38,39,40},{41,42,43,44},{45,46,47,48},
|
||||
{-1, -2, -3, -4}, {-5, -6, -7, -8}, {-9, -10,-11,-12},
|
||||
{-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
|
||||
{-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
|
||||
{-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48}
|
||||
};
|
||||
|
||||
static void signal_usr1(int signum, siginfo_t *info, void *uc)
|
||||
{
|
||||
int i;
|
||||
ucontext_t *ucp = uc;
|
||||
ucontext_t *tm_ucp = ucp->uc_link;
|
||||
|
||||
for (i = 0; i < NV_VMX_REGS && !fail; i++) {
|
||||
fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[i + 20],
|
||||
&vms[i], sizeof(vector int));
|
||||
fail |= memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[i + 20],
|
||||
&vms[i + NV_VMX_REGS], sizeof (vector int));
|
||||
|
||||
if (fail) {
|
||||
int j;
|
||||
|
||||
fprintf(stderr, "Failed on %d vmx 0x", i);
|
||||
for (j = 0; j < 4; j++)
|
||||
fprintf(stderr, "%04x", ucp->uc_mcontext.v_regs->vrregs[i + 20][j]);
|
||||
fprintf(stderr, " vs 0x");
|
||||
for (j = 0 ; j < 4; j++)
|
||||
fprintf(stderr, "%04x", tm_ucp->uc_mcontext.v_regs->vrregs[i + 20][j]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int tm_signal_context_chk()
|
||||
{
|
||||
struct sigaction act;
|
||||
int i;
|
||||
long rc;
|
||||
pid_t pid = getpid();
|
||||
|
||||
SKIP_IF(!have_htm());
|
||||
|
||||
act.sa_sigaction = signal_usr1;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGUSR1, &act, NULL) < 0) {
|
||||
perror("sigaction sigusr1");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < MAX_ATTEMPT && !fail) {
|
||||
rc = tm_signal_self_context_load(pid, NULL, NULL, vms, NULL);
|
||||
FAIL_IF(rc != pid);
|
||||
i++;
|
||||
}
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vmx");
|
||||
}
|
125
tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c
Normal file
125
tools/testing/selftests/powerpc/tm/tm-signal-context-chk-vsx.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2016, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* Test the kernel's signal frame code.
|
||||
*
|
||||
* The kernel sets up two sets of ucontexts if the signal was to be
|
||||
* delivered while the thread was in a transaction.
|
||||
* Expected behaviour is that the checkpointed state is in the user
|
||||
* context passed to the signal handler. The speculated state can be
|
||||
* accessed with the uc_link pointer.
|
||||
*
|
||||
* The rationale for this is that if TM unaware code (which linked
|
||||
* against TM libs) installs a signal handler it will not know of the
|
||||
* speculative nature of the 'live' registers and may infer the wrong
|
||||
* thing.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <altivec.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "tm.h"
|
||||
|
||||
#define MAX_ATTEMPT 500000
|
||||
|
||||
#define NV_VSX_REGS 12
|
||||
|
||||
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
|
||||
|
||||
static sig_atomic_t fail;
|
||||
|
||||
vector int vss[] = {
|
||||
{1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12},
|
||||
{13,14,15,16},{17,18,19,20},{21,22,23,24},
|
||||
{25,26,27,28},{29,30,31,32},{33,34,35,36},
|
||||
{37,38,39,40},{41,42,43,44},{45,46,47,48},
|
||||
{-1, -2, -3, -4 },{-5, -6, -7, -8 },{-9, -10,-11,-12},
|
||||
{-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
|
||||
{-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
|
||||
{-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48}
|
||||
};
|
||||
|
||||
static void signal_usr1(int signum, siginfo_t *info, void *uc)
|
||||
{
|
||||
int i;
|
||||
uint8_t vsc[sizeof(vector int)];
|
||||
uint8_t vst[sizeof(vector int)];
|
||||
ucontext_t *ucp = uc;
|
||||
ucontext_t *tm_ucp = ucp->uc_link;
|
||||
|
||||
/*
|
||||
* The other half of the VSX regs will be after v_regs.
|
||||
*
|
||||
* In short, vmx_reserve array holds everything. v_regs is a 16
|
||||
* byte aligned pointer at the start of vmx_reserve (vmx_reserve
|
||||
* may or may not be 16 aligned) where the v_regs structure exists.
|
||||
* (half of) The VSX regsters are directly after v_regs so the
|
||||
* easiest way to find them below.
|
||||
*/
|
||||
long *vsx_ptr = (long *)(ucp->uc_mcontext.v_regs + 1);
|
||||
long *tm_vsx_ptr = (long *)(tm_ucp->uc_mcontext.v_regs + 1);
|
||||
for (i = 0; i < NV_VSX_REGS && !fail; i++) {
|
||||
memcpy(vsc, &ucp->uc_mcontext.fp_regs[i + 20], 8);
|
||||
memcpy(vsc + 8, &vsx_ptr[20 + i], 8);
|
||||
fail = memcmp(vsc, &vss[i], sizeof(vector int));
|
||||
memcpy(vst, &tm_ucp->uc_mcontext.fp_regs[i + 20], 8);
|
||||
memcpy(vst + 8, &tm_vsx_ptr[20 + i], 8);
|
||||
fail |= memcmp(vst, &vss[i + NV_VSX_REGS], sizeof(vector int));
|
||||
|
||||
if (fail) {
|
||||
int j;
|
||||
|
||||
fprintf(stderr, "Failed on %d vsx 0x", i);
|
||||
for (j = 0; j < 16; j++)
|
||||
fprintf(stderr, "%02x", vsc[j]);
|
||||
fprintf(stderr, " vs 0x");
|
||||
for (j = 0; j < 16; j++)
|
||||
fprintf(stderr, "%02x", vst[j]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int tm_signal_context_chk()
|
||||
{
|
||||
struct sigaction act;
|
||||
int i;
|
||||
long rc;
|
||||
pid_t pid = getpid();
|
||||
|
||||
SKIP_IF(!have_htm());
|
||||
|
||||
act.sa_sigaction = signal_usr1;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
if (sigaction(SIGUSR1, &act, NULL) < 0) {
|
||||
perror("sigaction sigusr1");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < MAX_ATTEMPT && !fail) {
|
||||
rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vss);
|
||||
FAIL_IF(rc != pid);
|
||||
i++;
|
||||
}
|
||||
|
||||
return fail;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return test_harness(tm_signal_context_chk, "tm_signal_context_chk_vsx");
|
||||
}
|
114
tools/testing/selftests/powerpc/tm/tm-signal.S
Normal file
114
tools/testing/selftests/powerpc/tm/tm-signal.S
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2015, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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 "../basic_asm.h"
|
||||
#include "../gpr_asm.h"
|
||||
#include "../fpu_asm.h"
|
||||
#include "../vmx_asm.h"
|
||||
#include "../vsx_asm.h"
|
||||
|
||||
/*
|
||||
* Large caveat here being that the caller cannot expect the
|
||||
* signal to always be sent! The hardware can (AND WILL!) abort
|
||||
* the transaction between the tbegin and the tsuspend (however
|
||||
* unlikely it seems or infrequently it actually happens).
|
||||
* You have been warned.
|
||||
*/
|
||||
/* long tm_signal_self(pid_t pid, long *gprs, double *fps, vector *vms, vector *vss); */
|
||||
FUNC_START(tm_signal_self_context_load)
|
||||
PUSH_BASIC_STACK(512)
|
||||
/*
|
||||
* Don't strictly need to save and restore as it depends on if
|
||||
* we're going to use them, however this reduces messy logic
|
||||
*/
|
||||
PUSH_VMX(STACK_FRAME_LOCAL(5,0),r8)
|
||||
PUSH_FPU(512)
|
||||
PUSH_NVREGS_BELOW_FPU(512)
|
||||
std r3, STACK_FRAME_PARAM(0)(sp) /* pid */
|
||||
std r4, STACK_FRAME_PARAM(1)(sp) /* gps */
|
||||
std r5, STACK_FRAME_PARAM(2)(sp) /* fps */
|
||||
std r6, STACK_FRAME_PARAM(3)(sp) /* vms */
|
||||
std r7, STACK_FRAME_PARAM(4)(sp) /* vss */
|
||||
|
||||
ld r3, STACK_FRAME_PARAM(1)(sp)
|
||||
cmpdi r3, 0
|
||||
beq skip_gpr_lc
|
||||
bl load_gpr
|
||||
skip_gpr_lc:
|
||||
ld r3, STACK_FRAME_PARAM(2)(sp)
|
||||
cmpdi r3, 0
|
||||
beq skip_fpu_lc
|
||||
bl load_fpu
|
||||
skip_fpu_lc:
|
||||
ld r3, STACK_FRAME_PARAM(3)(sp)
|
||||
cmpdi r3, 0
|
||||
beq skip_vmx_lc
|
||||
bl load_vmx
|
||||
skip_vmx_lc:
|
||||
ld r3, STACK_FRAME_PARAM(4)(sp)
|
||||
cmpdi r3, 0
|
||||
beq skip_vsx_lc
|
||||
bl load_vsx
|
||||
skip_vsx_lc:
|
||||
/*
|
||||
* Set r3 (return value) before tbegin. Use the pid as a known
|
||||
* 'all good' return value, zero is used to indicate a non-doomed
|
||||
* transaction.
|
||||
*/
|
||||
ld r3, STACK_FRAME_PARAM(0)(sp)
|
||||
tbegin.
|
||||
beq 1f
|
||||
tsuspend. /* Can't enter a syscall transactionally */
|
||||
ld r3, STACK_FRAME_PARAM(1)(sp)
|
||||
cmpdi r3, 0
|
||||
beq skip_gpr_lt
|
||||
/* Get the second half of the array */
|
||||
addi r3, r3, 8 * 18
|
||||
bl load_gpr
|
||||
skip_gpr_lt:
|
||||
ld r3, STACK_FRAME_PARAM(2)(sp)
|
||||
cmpdi r3, 0
|
||||
beq skip_fpu_lt
|
||||
/* Get the second half of the array */
|
||||
addi r3, r3, 8 * 18
|
||||
bl load_fpu
|
||||
skip_fpu_lt:
|
||||
ld r3, STACK_FRAME_PARAM(3)(sp)
|
||||
cmpdi r3, 0
|
||||
beq skip_vmx_lt
|
||||
/* Get the second half of the array */
|
||||
addi r3, r3, 16 * 12
|
||||
bl load_vmx
|
||||
skip_vmx_lt:
|
||||
ld r3, STACK_FRAME_PARAM(4)(sp)
|
||||
cmpdi r3, 0
|
||||
beq skip_vsx_lt
|
||||
/* Get the second half of the array */
|
||||
addi r3, r3, 16 * 12
|
||||
bl load_vsx
|
||||
skip_vsx_lt:
|
||||
li r0, 37 /* sys_kill */
|
||||
ld r3, STACK_FRAME_PARAM(0)(sp) /* pid */
|
||||
li r4, 10 /* SIGUSR1 */
|
||||
sc /* Taking the signal will doom the transaction */
|
||||
tabort. 0
|
||||
tresume. /* Be super sure we abort */
|
||||
/*
|
||||
* This will cause us to resume doomed transaction and cause
|
||||
* hardware to cleanup, we'll end up at 1: anything between
|
||||
* tresume. and 1: shouldn't ever run.
|
||||
*/
|
||||
li r3, 0
|
||||
1:
|
||||
POP_VMX(STACK_FRAME_LOCAL(5,0),r4)
|
||||
POP_FPU(512)
|
||||
POP_NVREGS_BELOW_FPU(512)
|
||||
POP_BASIC_STACK(512)
|
||||
blr
|
||||
FUNC_END(tm_signal_self_context_load)
|
@@ -52,4 +52,31 @@ static inline bool failure_is_nesting(void)
|
||||
return (__builtin_get_texasru() & 0x400000);
|
||||
}
|
||||
|
||||
static inline int tcheck(void)
|
||||
{
|
||||
long cr;
|
||||
asm volatile ("tcheck 0" : "=r"(cr) : : "cr0");
|
||||
return (cr >> 28) & 4;
|
||||
}
|
||||
|
||||
static inline bool tcheck_doomed(void)
|
||||
{
|
||||
return tcheck() & 8;
|
||||
}
|
||||
|
||||
static inline bool tcheck_active(void)
|
||||
{
|
||||
return tcheck() & 4;
|
||||
}
|
||||
|
||||
static inline bool tcheck_suspended(void)
|
||||
{
|
||||
return tcheck() & 2;
|
||||
}
|
||||
|
||||
static inline bool tcheck_transactional(void)
|
||||
{
|
||||
return tcheck() & 6;
|
||||
}
|
||||
|
||||
#endif /* _SELFTESTS_POWERPC_TM_TM_H */
|
||||
|
@@ -22,7 +22,7 @@ typedef uint32_t u32;
|
||||
typedef uint16_t u16;
|
||||
typedef uint8_t u8;
|
||||
|
||||
|
||||
void test_harness_set_timeout(uint64_t time);
|
||||
int test_harness(int (test_function)(void), char *name);
|
||||
extern void *get_auxv_entry(int type);
|
||||
int pick_online_cpu(void);
|
||||
@@ -32,10 +32,17 @@ static inline bool have_hwcap(unsigned long ftr)
|
||||
return ((unsigned long)get_auxv_entry(AT_HWCAP) & ftr) == ftr;
|
||||
}
|
||||
|
||||
#ifdef AT_HWCAP2
|
||||
static inline bool have_hwcap2(unsigned long ftr2)
|
||||
{
|
||||
return ((unsigned long)get_auxv_entry(AT_HWCAP2) & ftr2) == ftr2;
|
||||
}
|
||||
#else
|
||||
static inline bool have_hwcap2(unsigned long ftr2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Yes, this is evil */
|
||||
#define FAIL_IF(x) \
|
||||
|
96
tools/testing/selftests/powerpc/vmx_asm.h
Normal file
96
tools/testing/selftests/powerpc/vmx_asm.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2015, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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 "basic_asm.h"
|
||||
|
||||
/* POS MUST BE 16 ALIGNED! */
|
||||
#define PUSH_VMX(pos,reg) \
|
||||
li reg,pos; \
|
||||
stvx v20,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v21,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v22,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v23,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v24,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v25,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v26,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v27,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v28,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v29,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v30,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
stvx v31,reg,%r1;
|
||||
|
||||
/* POS MUST BE 16 ALIGNED! */
|
||||
#define POP_VMX(pos,reg) \
|
||||
li reg,pos; \
|
||||
lvx v20,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v21,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v22,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v23,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v24,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v25,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v26,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v27,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v28,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v29,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v30,reg,%r1; \
|
||||
addi reg,reg,16; \
|
||||
lvx v31,reg,%r1;
|
||||
|
||||
/*
|
||||
* Careful this will 'clobber' vmx (by design)
|
||||
* Don't call this from C
|
||||
*/
|
||||
FUNC_START(load_vmx)
|
||||
li r5,0
|
||||
lvx v20,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v21,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v22,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v23,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v24,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v25,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v26,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v27,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v28,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v29,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v30,r5,r3
|
||||
addi r5,r5,16
|
||||
lvx v31,r5,r3
|
||||
blr
|
||||
FUNC_END(load_vmx)
|
71
tools/testing/selftests/powerpc/vsx_asm.h
Normal file
71
tools/testing/selftests/powerpc/vsx_asm.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2015, Cyril Bur, IBM Corp.
|
||||
*
|
||||
* 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 "basic_asm.h"
|
||||
|
||||
/*
|
||||
* Careful this will 'clobber' vsx (by design), VSX are always
|
||||
* volatile though so unlike vmx this isn't so much of an issue
|
||||
* Still should avoid calling from C
|
||||
*/
|
||||
FUNC_START(load_vsx)
|
||||
li r5,0
|
||||
lxvx vs20,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs21,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs22,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs23,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs24,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs25,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs26,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs27,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs28,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs29,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs30,r5,r3
|
||||
addi r5,r5,16
|
||||
lxvx vs31,r5,r3
|
||||
blr
|
||||
FUNC_END(load_vsx)
|
||||
|
||||
FUNC_START(store_vsx)
|
||||
li r5,0
|
||||
stxvx vs20,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs21,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs22,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs23,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs24,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs25,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs26,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs27,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs28,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs29,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs30,r5,r3
|
||||
addi r5,r5,16
|
||||
stxvx vs31,r5,r3
|
||||
blr
|
||||
FUNC_END(store_vsx)
|
Reference in New Issue
Block a user