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:
Linus Torvalds
2016-10-07 20:19:31 -07:00
227 changed files with 5471 additions and 2931 deletions

View File

@@ -19,6 +19,7 @@ SUB_DIRS = alignment \
dscr \
mm \
pmu \
signal \
primitives \
stringloops \
switch_endian \

View 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 */

View 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 */

View File

@@ -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;

View File

@@ -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:

View File

@@ -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)

View File

@@ -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)

View 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)

View 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");
}

View 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

View 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)

View 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");
}

View 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");
}

View File

@@ -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:

View File

@@ -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");
}

View File

@@ -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");
}

View 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");
}

View 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");
}

View 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)

View File

@@ -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 */

View File

@@ -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) \

View 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)

View 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)