tests/tcg: target/s390x: Test MVC
Let's add a test that especially verifies that no data will be touched in case we cross page boundaries and one page access triggers a fault. Before the fault-safe handling fixes, the test failes with: TEST mvc on s390x data modified during a fault make[2]: *** [../Makefile.target:116: run-mvc] Error 1 Acked-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: David Hildenbrand <david@redhat.com>
This commit is contained in:
parent
d9e13c3419
commit
5d69cbdfdd
@ -7,3 +7,4 @@ TESTS+=exrl-trt
|
||||
TESTS+=exrl-trtr
|
||||
TESTS+=pack
|
||||
TESTS+=mvo
|
||||
TESTS+=mvc
|
||||
|
109
tests/tcg/s390x/mvc.c
Normal file
109
tests/tcg/s390x/mvc.c
Normal file
@ -0,0 +1,109 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
jmp_buf jmp_env;
|
||||
|
||||
static void handle_sigsegv(int sig)
|
||||
{
|
||||
siglongjmp(jmp_env, 1);
|
||||
}
|
||||
|
||||
#define ALLOC_SIZE (2 * 4096)
|
||||
|
||||
static inline void mvc_256(const char *dst, const char *src)
|
||||
{
|
||||
asm volatile (
|
||||
" mvc 0(256,%[dst]),0(%[src])\n"
|
||||
:
|
||||
: [dst] "d" (dst),
|
||||
[src] "d" (src)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char *src, *dst;
|
||||
int i;
|
||||
|
||||
/* register the SIGSEGV handler */
|
||||
if (signal(SIGSEGV, handle_sigsegv) == SIG_ERR) {
|
||||
fprintf(stderr, "SIGSEGV not registered\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* prepare the buffers - two consecutive pages */
|
||||
src = valloc(ALLOC_SIZE);
|
||||
dst = valloc(ALLOC_SIZE);
|
||||
memset(src, 0xff, ALLOC_SIZE);
|
||||
memset(dst, 0x0, ALLOC_SIZE);
|
||||
|
||||
/* protect the second pages */
|
||||
if (mprotect(src + 4096, 4096, PROT_NONE) ||
|
||||
mprotect(dst + 4096, 4096, PROT_NONE)) {
|
||||
fprintf(stderr, "mprotect failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* fault on second destination page */
|
||||
if (sigsetjmp(jmp_env, 1) == 0) {
|
||||
mvc_256(dst + 4096 - 128, src);
|
||||
fprintf(stderr, "fault not triggered\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* fault on second source page */
|
||||
if (sigsetjmp(jmp_env, 1) == 0) {
|
||||
mvc_256(dst, src + 4096 - 128);
|
||||
fprintf(stderr, "fault not triggered\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* fault on second source and second destination page */
|
||||
if (sigsetjmp(jmp_env, 1) == 0) {
|
||||
mvc_256(dst + 4096 - 128, src + 4096 - 128);
|
||||
fprintf(stderr, "fault not triggered\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* restore permissions */
|
||||
if (mprotect(src + 4096, 4096, PROT_READ | PROT_WRITE) ||
|
||||
mprotect(dst + 4096, 4096, PROT_READ | PROT_WRITE)) {
|
||||
fprintf(stderr, "mprotect failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* no data must be touched during the faults */
|
||||
for (i = 0; i < ALLOC_SIZE; i++) {
|
||||
if (src[i] != 0xff || dst[i]) {
|
||||
fprintf(stderr, "data modified during a fault\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* test if MVC works now correctly accross page boundaries */
|
||||
mvc_256(dst + 4096 - 128, src + 4096 - 128);
|
||||
for (i = 0; i < ALLOC_SIZE; i++) {
|
||||
if (src[i] != 0xff) {
|
||||
fprintf(stderr, "src modified\n");
|
||||
return 1;
|
||||
}
|
||||
if (i < 4096 - 128 || i >= 4096 + 128) {
|
||||
if (dst[i]) {
|
||||
fprintf(stderr, "wrong dst modified\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (dst[i] != 0xff) {
|
||||
fprintf(stderr, "wrong data moved\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user