Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
1 parent
d9e13c3
commit 5d69cbd
Showing
2 changed files
with
110 additions
and
0 deletions.
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 |
---|---|---|
|
@@ -7,3 +7,4 @@ TESTS+=exrl-trt | |
TESTS+=exrl-trtr | ||
TESTS+=pack | ||
TESTS+=mvo | ||
TESTS+=mvc |
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,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; | ||
} |