qemu/tests/tcg/s390x/mvc.c
Thomas Huth f530ba8f8d tests/tcg/s390x: Fix mvc, mvo and pack tests with Clang
These instructions use addressing with a "base address", meaning
that if register r0 is used, it is always treated as zero, no matter
what value is stored in the register. So we have to make sure not
to use register r0 for these instructions in our tests. There was
no problem with GCC so far since it seems to always pick other
registers by default, but Clang likes to chose register r0, too,
so we have to use the "a" constraint to make sure that it does
not pick r0 here.

Message-Id: <20220301093911.1450719-1-thuth@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Thomas Huth <thuth@redhat.com>
2022-03-07 09:04:42 +01:00

110 lines
2.7 KiB
C

#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] "a" (dst),
[src] "a" (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;
}