xref: /openbmc/qemu/tests/tcg/s390x/mvc.c (revision beb1a917)
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] "a" (dst),
24           [src] "a" (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 across 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 }
110