1*c3513ce5SIlya Leoshkevich /*
2*c3513ce5SIlya Leoshkevich  * Test s390x-linux-user precise self-modifying code handling.
3*c3513ce5SIlya Leoshkevich  *
4*c3513ce5SIlya Leoshkevich  * SPDX-License-Identifier: GPL-2.0-or-later
5*c3513ce5SIlya Leoshkevich  */
6*c3513ce5SIlya Leoshkevich #include <assert.h>
7*c3513ce5SIlya Leoshkevich #include <sys/mman.h>
8*c3513ce5SIlya Leoshkevich #include <stdint.h>
9*c3513ce5SIlya Leoshkevich #include <stdlib.h>
10*c3513ce5SIlya Leoshkevich 
11*c3513ce5SIlya Leoshkevich extern __uint128_t __attribute__((__aligned__(1))) smc;
12*c3513ce5SIlya Leoshkevich extern __uint128_t __attribute__((__aligned__(1))) patch;
13*c3513ce5SIlya Leoshkevich 
main(void)14*c3513ce5SIlya Leoshkevich int main(void)
15*c3513ce5SIlya Leoshkevich {
16*c3513ce5SIlya Leoshkevich     char *aligned_smc = (char *)((uintptr_t)&smc & ~0xFFFULL);
17*c3513ce5SIlya Leoshkevich     char *smc_end = (char *)&smc + sizeof(smc);
18*c3513ce5SIlya Leoshkevich     uint64_t value = 21;
19*c3513ce5SIlya Leoshkevich     int err;
20*c3513ce5SIlya Leoshkevich 
21*c3513ce5SIlya Leoshkevich     err = mprotect(aligned_smc, smc_end - aligned_smc,
22*c3513ce5SIlya Leoshkevich                    PROT_READ | PROT_WRITE | PROT_EXEC);
23*c3513ce5SIlya Leoshkevich     assert(err == 0);
24*c3513ce5SIlya Leoshkevich 
25*c3513ce5SIlya Leoshkevich     asm("jg 0f\n"                           /* start a new TB */
26*c3513ce5SIlya Leoshkevich         "patch: .byte 0,0,0,0,0,0\n"        /* replaces padding */
27*c3513ce5SIlya Leoshkevich         ".byte 0,0,0,0,0,0\n"               /* replaces vstl */
28*c3513ce5SIlya Leoshkevich         "agr %[value],%[value]\n"           /* replaces sgr */
29*c3513ce5SIlya Leoshkevich         "smc: .org . + 6\n"                 /* pad patched code to 16 bytes */
30*c3513ce5SIlya Leoshkevich         "0: vstl %[patch],%[idx],%[smc]\n"  /* start writing before TB */
31*c3513ce5SIlya Leoshkevich         "sgr %[value],%[value]"             /* this becomes `agr %r0,%r0` */
32*c3513ce5SIlya Leoshkevich         : [smc] "=R" (smc)
33*c3513ce5SIlya Leoshkevich         , [value] "+r" (value)
34*c3513ce5SIlya Leoshkevich         : [patch] "v" (patch)
35*c3513ce5SIlya Leoshkevich         , [idx] "r" (sizeof(patch) - 1)
36*c3513ce5SIlya Leoshkevich         : "cc");
37*c3513ce5SIlya Leoshkevich 
38*c3513ce5SIlya Leoshkevich     return value == 42 ? EXIT_SUCCESS : EXIT_FAILURE;
39*c3513ce5SIlya Leoshkevich }
40