Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01127f1e authored by Cyril Bur's avatar Cyril Bur Committed by Michael Ellerman
Browse files

selftests/powerpc: Test the preservation of FPU and VMX regs across syscall



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: default avatarCyril Bur <cyrilbur@gmail.com>
[mpe: Add include guards to basic_asm.h, minor formatting]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent a4cf0a2e
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -22,7 +22,8 @@ SUB_DIRS = benchmarks \
	   switch_endian	\
	   syscalls		\
	   tm			\
	   vphn
	   vphn         \
	   math

endif

+70 −0
Original line number Diff line number Diff line
#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 */
+2 −0
Original line number Diff line number Diff line
fpu_syscall
vmx_syscall
+14 −0
Original line number Diff line number Diff line
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
+161 −0
Original line number Diff line number Diff line
/*
 * 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)
Loading