-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/powerpc: Test the preservation of FPU and VMX regs across s…
…yscall Test that the non volatile floating point and Altivec registers get correctly preserved across the fork() syscall. fork() works nicely for this purpose, the registers should be the same for both parent and child Signed-off-by: Cyril Bur <cyrilbur@gmail.com> [mpe: Add include guards to basic_asm.h, minor formatting] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
- Loading branch information
Cyril Bur
authored and
Michael Ellerman
committed
Mar 2, 2016
1 parent
a4cf0a2
commit 01127f1
Showing
8 changed files
with
625 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,7 +22,8 @@ SUB_DIRS = benchmarks \ | |
switch_endian \ | ||
syscalls \ | ||
tm \ | ||
vphn | ||
vphn \ | ||
math | ||
|
||
endif | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
#ifndef _SELFTESTS_POWERPC_BASIC_ASM_H | ||
#define _SELFTESTS_POWERPC_BASIC_ASM_H | ||
|
||
#include <ppc-asm.h> | ||
#include <asm/unistd.h> | ||
|
||
#define LOAD_REG_IMMEDIATE(reg,expr) \ | ||
lis reg,(expr)@highest; \ | ||
ori reg,reg,(expr)@higher; \ | ||
rldicr reg,reg,32,31; \ | ||
oris reg,reg,(expr)@high; \ | ||
ori reg,reg,(expr)@l; | ||
|
||
/* | ||
* Note: These macros assume that variables being stored on the stack are | ||
* doublewords, while this is usually the case it may not always be the | ||
* case for each use case. | ||
*/ | ||
#if defined(_CALL_ELF) && _CALL_ELF == 2 | ||
#define STACK_FRAME_MIN_SIZE 32 | ||
#define STACK_FRAME_TOC_POS 24 | ||
#define __STACK_FRAME_PARAM(_param) (32 + ((_param)*8)) | ||
#define __STACK_FRAME_LOCAL(_num_params,_var_num) ((STACK_FRAME_PARAM(_num_params)) + ((_var_num)*8)) | ||
#else | ||
#define STACK_FRAME_MIN_SIZE 112 | ||
#define STACK_FRAME_TOC_POS 40 | ||
#define __STACK_FRAME_PARAM(i) (48 + ((i)*8)) | ||
|
||
/* | ||
* Caveat: if a function passed more than 8 doublewords, the caller will have | ||
* made more space... which would render the 112 incorrect. | ||
*/ | ||
#define __STACK_FRAME_LOCAL(_num_params,_var_num) (112 + ((_var_num)*8)) | ||
#endif | ||
|
||
/* Parameter x saved to the stack */ | ||
#define STACK_FRAME_PARAM(var) __STACK_FRAME_PARAM(var) | ||
|
||
/* Local variable x saved to the stack after x parameters */ | ||
#define STACK_FRAME_LOCAL(num_params,var) __STACK_FRAME_LOCAL(num_params,var) | ||
#define STACK_FRAME_LR_POS 16 | ||
#define STACK_FRAME_CR_POS 8 | ||
|
||
/* | ||
* It is very important to note here that _extra is the extra amount of | ||
* stack space needed. This space can be accessed using STACK_FRAME_PARAM() | ||
* or STACK_FRAME_LOCAL() macros. | ||
* | ||
* r1 and r2 are not defined in ppc-asm.h (instead they are defined as sp | ||
* and toc). Kernel programmers tend to prefer rX even for r1 and r2, hence | ||
* %1 and %r2. r0 is defined in ppc-asm.h and therefore %r0 gets | ||
* preprocessed incorrectly, hence r0. | ||
*/ | ||
#define PUSH_BASIC_STACK(_extra) \ | ||
mflr r0; \ | ||
std r0,STACK_FRAME_LR_POS(%r1); \ | ||
stdu %r1,-(_extra + STACK_FRAME_MIN_SIZE)(%r1); \ | ||
mfcr r0; \ | ||
stw r0,STACK_FRAME_CR_POS(%r1); \ | ||
std %r2,STACK_FRAME_TOC_POS(%r1); | ||
|
||
#define POP_BASIC_STACK(_extra) \ | ||
ld %r2,STACK_FRAME_TOC_POS(%r1); \ | ||
lwz r0,STACK_FRAME_CR_POS(%r1); \ | ||
mtcr r0; \ | ||
addi %r1,%r1,(_extra + STACK_FRAME_MIN_SIZE); \ | ||
ld r0,STACK_FRAME_LR_POS(%r1); \ | ||
mtlr r0; | ||
|
||
#endif /* _SELFTESTS_POWERPC_BASIC_ASM_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
fpu_syscall | ||
vmx_syscall |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
TEST_PROGS := fpu_syscall vmx_syscall | ||
|
||
all: $(TEST_PROGS) | ||
|
||
$(TEST_PROGS): ../harness.c | ||
$(TEST_PROGS): CFLAGS += -O2 -g -pthread -m64 -maltivec | ||
|
||
fpu_syscall: fpu_asm.S | ||
vmx_syscall: vmx_asm.S | ||
|
||
include ../../lib.mk | ||
|
||
clean: | ||
rm -f $(TEST_PROGS) *.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/* | ||
* 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" | ||
|
||
#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) | ||
|
||
FUNC_START(check_fpu) | ||
mr r4,r3 | ||
li r3,1 # assume a bad result | ||
lfd f0,0(r4) | ||
fcmpu cr1,f0,f14 | ||
bne cr1,1f | ||
lfd f0,8(r4) | ||
fcmpu cr1,f0,f15 | ||
bne cr1,1f | ||
lfd f0,16(r4) | ||
fcmpu cr1,f0,f16 | ||
bne cr1,1f | ||
lfd f0,24(r4) | ||
fcmpu cr1,f0,f17 | ||
bne cr1,1f | ||
lfd f0,32(r4) | ||
fcmpu cr1,f0,f18 | ||
bne cr1,1f | ||
lfd f0,40(r4) | ||
fcmpu cr1,f0,f19 | ||
bne cr1,1f | ||
lfd f0,48(r4) | ||
fcmpu cr1,f0,f20 | ||
bne cr1,1f | ||
lfd f0,56(r4) | ||
fcmpu cr1,f0,f21 | ||
bne cr1,1f | ||
lfd f0,64(r4) | ||
fcmpu cr1,f0,f22 | ||
bne cr1,1f | ||
lfd f0,72(r4) | ||
fcmpu cr1,f0,f23 | ||
bne cr1,1f | ||
lfd f0,80(r4) | ||
fcmpu cr1,f0,f24 | ||
bne cr1,1f | ||
lfd f0,88(r4) | ||
fcmpu cr1,f0,f25 | ||
bne cr1,1f | ||
lfd f0,96(r4) | ||
fcmpu cr1,f0,f26 | ||
bne cr1,1f | ||
lfd f0,104(r4) | ||
fcmpu cr1,f0,f27 | ||
bne cr1,1f | ||
lfd f0,112(r4) | ||
fcmpu cr1,f0,f28 | ||
bne cr1,1f | ||
lfd f0,120(r4) | ||
fcmpu cr1,f0,f29 | ||
bne cr1,1f | ||
lfd f0,128(r4) | ||
fcmpu cr1,f0,f30 | ||
bne cr1,1f | ||
lfd f0,136(r4) | ||
fcmpu cr1,f0,f31 | ||
bne cr1,1f | ||
li r3,0 # Success!!! | ||
1: blr | ||
|
||
FUNC_START(test_fpu) | ||
# r3 holds pointer to where to put the result of fork | ||
# r4 holds pointer to the pid | ||
# f14-f31 are non volatiles | ||
PUSH_BASIC_STACK(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 | ||
li r0,__NR_fork | ||
sc | ||
|
||
# pass the result of the fork to the caller | ||
ld r9,STACK_FRAME_PARAM(1)(sp) | ||
std r3,0(r9) | ||
|
||
ld r3,STACK_FRAME_PARAM(0)(sp) | ||
bl check_fpu | ||
nop | ||
|
||
POP_FPU(STACK_FRAME_LOCAL(2,0)) | ||
POP_BASIC_STACK(256) | ||
blr | ||
FUNC_END(test_fpu) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* 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 FPU registers change across a syscall (fork). | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include <unistd.h> | ||
#include <sys/syscall.h> | ||
#include <sys/time.h> | ||
#include <sys/types.h> | ||
#include <sys/wait.h> | ||
#include <stdlib.h> | ||
|
||
#include "utils.h" | ||
|
||
extern int test_fpu(double *darray, pid_t *pid); | ||
|
||
double darray[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, | ||
1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, | ||
2.1}; | ||
|
||
int syscall_fpu(void) | ||
{ | ||
pid_t fork_pid; | ||
int i; | ||
int ret; | ||
int child_ret; | ||
for (i = 0; i < 1000; i++) { | ||
/* test_fpu will fork() */ | ||
ret = test_fpu(darray, &fork_pid); | ||
if (fork_pid == -1) | ||
return -1; | ||
if (fork_pid == 0) | ||
exit(ret); | ||
waitpid(fork_pid, &child_ret, 0); | ||
if (ret || child_ret) | ||
return 1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
int test_syscall_fpu(void) | ||
{ | ||
/* | ||
* Setup an environment with much context switching | ||
*/ | ||
pid_t pid2; | ||
pid_t pid = fork(); | ||
int ret; | ||
int child_ret; | ||
FAIL_IF(pid == -1); | ||
|
||
pid2 = fork(); | ||
/* Can't FAIL_IF(pid2 == -1); because already forked once */ | ||
if (pid2 == -1) { | ||
/* | ||
* Couldn't fork, ensure test is a fail | ||
*/ | ||
child_ret = ret = 1; | ||
} else { | ||
ret = syscall_fpu(); | ||
if (pid2) | ||
waitpid(pid2, &child_ret, 0); | ||
else | ||
exit(ret); | ||
} | ||
|
||
ret |= child_ret; | ||
|
||
if (pid) | ||
waitpid(pid, &child_ret, 0); | ||
else | ||
exit(ret); | ||
|
||
FAIL_IF(ret || child_ret); | ||
return 0; | ||
} | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
return test_harness(test_syscall_fpu, "syscall_fpu"); | ||
|
||
} |
Oops, something went wrong.