selftests/powerpc: Add test to check if VSRs are corrupted

When a transaction is aborted, VSR values should rollback to the
checkpointed values before the transaction began. VSRs used elsewhere in
the kernel during a transaction, or while the transaction is suspended
should not affect the checkpointed values.

Prior to the bug fix in commit d31626f70b ("powerpc: Don't corrupt
transactional state when using FP/VMX in kernel") when VMX was requested
by the kernel the .vr_state (which held the checkpointed state of VSRs
before the transaction) was overwritten with the current state from
outside the transation. Thus if the transaction did not complete, the
VSR values would be "rolled back" to potentially incorrect values.

Signed-off-by: Rashmica Gupta <rashmicy@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
Rashmica Gupta 2015-12-10 20:49:33 +11:00 committed by Michael Ellerman
parent eb925d6460
commit 5f337e3e5b
3 changed files with 105 additions and 1 deletions

View File

@ -2,3 +2,4 @@ tm-resched-dscr
tm-syscall
tm-signal-msr-resv
tm-signal-stack
tm-vmxcopy

View File

@ -1,4 +1,4 @@
TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack
TEST_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack tm-vmxcopy
all: $(TEST_PROGS)

View File

@ -0,0 +1,103 @@
/*
* Copyright 2015, Michael Neuling, IBM Corp.
* Licensed under GPLv2.
*
* Original: Michael Neuling 4/12/2013
* Edited: Rashmica Gupta 4/12/2015
*
* See if the altivec state is leaked out of an aborted transaction due to
* kernel vmx copy loops.
*
* When the transaction aborts, VSR values should rollback to the values
* they held before the transaction commenced. Using VSRs while transaction
* is suspended should not affect the checkpointed values.
*
* (1) write A to a VSR
* (2) start transaction
* (3) suspend transaction
* (4) change the VSR to B
* (5) trigger kernel vmx copy loop
* (6) abort transaction
* (7) check that the VSR value is A
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <assert.h>
#include "tm.h"
#include "utils.h"
int test_vmxcopy()
{
long double vecin = 1.3;
long double vecout;
unsigned long pgsize = getpagesize();
int i;
int fd;
int size = pgsize*16;
char tmpfile[] = "/tmp/page_faultXXXXXX";
char buf[pgsize];
char *a;
uint64_t aborted = 0;
SKIP_IF(!have_htm());
fd = mkstemp(tmpfile);
assert(fd >= 0);
memset(buf, 0, pgsize);
for (i = 0; i < size; i += pgsize)
assert(write(fd, buf, pgsize) == pgsize);
unlink(tmpfile);
a = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
assert(a != MAP_FAILED);
asm __volatile__(
"lxvd2x 40,0,%[vecinptr];" /* set 40 to initial value*/
"tbegin.;"
"beq 3f;"
"tsuspend.;"
"xxlxor 40,40,40;" /* set 40 to 0 */
"std 5, 0(%[map]);" /* cause kernel vmx copy page */
"tabort. 0;"
"tresume.;"
"tend.;"
"li %[res], 0;"
"b 5f;"
/* Abort handler */
"3:;"
"li %[res], 1;"
"5:;"
"stxvd2x 40,0,%[vecoutptr];"
: [res]"=r"(aborted)
: [vecinptr]"r"(&vecin),
[vecoutptr]"r"(&vecout),
[map]"r"(a)
: "memory", "r0", "r3", "r4", "r5", "r6", "r7");
if (aborted && (vecin != vecout)){
printf("FAILED: vector state leaked on abort %f != %f\n",
(double)vecin, (double)vecout);
return 1;
}
munmap(a, size);
close(fd);
return 0;
}
int main(void)
{
return test_harness(test_vmxcopy, "tm_vmxcopy");
}