qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

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>

+110
+1
tests/tcg/s390x/Makefile.target
··· 7 7 TESTS+=exrl-trtr 8 8 TESTS+=pack 9 9 TESTS+=mvo 10 + TESTS+=mvc
+109
tests/tcg/s390x/mvc.c
··· 1 + #include <stdint.h> 2 + #include <stdlib.h> 3 + #include <stdio.h> 4 + #include <string.h> 5 + #include <sys/mman.h> 6 + #include <signal.h> 7 + #include <setjmp.h> 8 + 9 + jmp_buf jmp_env; 10 + 11 + static void handle_sigsegv(int sig) 12 + { 13 + siglongjmp(jmp_env, 1); 14 + } 15 + 16 + #define ALLOC_SIZE (2 * 4096) 17 + 18 + static inline void mvc_256(const char *dst, const char *src) 19 + { 20 + asm volatile ( 21 + " mvc 0(256,%[dst]),0(%[src])\n" 22 + : 23 + : [dst] "d" (dst), 24 + [src] "d" (src) 25 + : "memory"); 26 + } 27 + 28 + int main(void) 29 + { 30 + char *src, *dst; 31 + int i; 32 + 33 + /* register the SIGSEGV handler */ 34 + if (signal(SIGSEGV, handle_sigsegv) == SIG_ERR) { 35 + fprintf(stderr, "SIGSEGV not registered\n"); 36 + return 1; 37 + } 38 + 39 + /* prepare the buffers - two consecutive pages */ 40 + src = valloc(ALLOC_SIZE); 41 + dst = valloc(ALLOC_SIZE); 42 + memset(src, 0xff, ALLOC_SIZE); 43 + memset(dst, 0x0, ALLOC_SIZE); 44 + 45 + /* protect the second pages */ 46 + if (mprotect(src + 4096, 4096, PROT_NONE) || 47 + mprotect(dst + 4096, 4096, PROT_NONE)) { 48 + fprintf(stderr, "mprotect failed\n"); 49 + return 1; 50 + } 51 + 52 + /* fault on second destination page */ 53 + if (sigsetjmp(jmp_env, 1) == 0) { 54 + mvc_256(dst + 4096 - 128, src); 55 + fprintf(stderr, "fault not triggered\n"); 56 + return 1; 57 + } 58 + 59 + /* fault on second source page */ 60 + if (sigsetjmp(jmp_env, 1) == 0) { 61 + mvc_256(dst, src + 4096 - 128); 62 + fprintf(stderr, "fault not triggered\n"); 63 + return 1; 64 + } 65 + 66 + /* fault on second source and second destination page */ 67 + if (sigsetjmp(jmp_env, 1) == 0) { 68 + mvc_256(dst + 4096 - 128, src + 4096 - 128); 69 + fprintf(stderr, "fault not triggered\n"); 70 + return 1; 71 + } 72 + 73 + /* restore permissions */ 74 + if (mprotect(src + 4096, 4096, PROT_READ | PROT_WRITE) || 75 + mprotect(dst + 4096, 4096, PROT_READ | PROT_WRITE)) { 76 + fprintf(stderr, "mprotect failed\n"); 77 + return 1; 78 + } 79 + 80 + /* no data must be touched during the faults */ 81 + for (i = 0; i < ALLOC_SIZE; i++) { 82 + if (src[i] != 0xff || dst[i]) { 83 + fprintf(stderr, "data modified during a fault\n"); 84 + return 1; 85 + } 86 + } 87 + 88 + /* test if MVC works now correctly accross page boundaries */ 89 + mvc_256(dst + 4096 - 128, src + 4096 - 128); 90 + for (i = 0; i < ALLOC_SIZE; i++) { 91 + if (src[i] != 0xff) { 92 + fprintf(stderr, "src modified\n"); 93 + return 1; 94 + } 95 + if (i < 4096 - 128 || i >= 4096 + 128) { 96 + if (dst[i]) { 97 + fprintf(stderr, "wrong dst modified\n"); 98 + return 1; 99 + } 100 + } else { 101 + if (dst[i] != 0xff) { 102 + fprintf(stderr, "wrong data moved\n"); 103 + return 1; 104 + } 105 + } 106 + } 107 + 108 + return 0; 109 + }