xref: /openbmc/qemu/tests/tcg/aarch64/mte-8.c (revision f2cb4026fccfe073f84a4b440e41d3ed0c3134f6)
1*340ca46bSGustavo Romero /*
2*340ca46bSGustavo Romero  * To be compiled with -march=armv8.5-a+memtag
3*340ca46bSGustavo Romero  *
4*340ca46bSGustavo Romero  * This test is adapted from a Linux test. Please see:
5*340ca46bSGustavo Romero  *
6*340ca46bSGustavo Romero  * https://www.kernel.org/doc/html/next/arch/arm64/memory-tagging-extension.html#example-of-correct-usage
7*340ca46bSGustavo Romero  */
8*340ca46bSGustavo Romero #include <errno.h>
9*340ca46bSGustavo Romero #include <stdint.h>
10*340ca46bSGustavo Romero #include <stdio.h>
11*340ca46bSGustavo Romero #include <stdlib.h>
12*340ca46bSGustavo Romero #include <unistd.h>
13*340ca46bSGustavo Romero #include <sys/auxv.h>
14*340ca46bSGustavo Romero #include <sys/mman.h>
15*340ca46bSGustavo Romero #include <sys/prctl.h>
16*340ca46bSGustavo Romero #include <string.h>
17*340ca46bSGustavo Romero /*
18*340ca46bSGustavo Romero  * From arch/arm64/include/uapi/asm/hwcap.h
19*340ca46bSGustavo Romero  */
20*340ca46bSGustavo Romero #define HWCAP2_MTE              (1 << 18)
21*340ca46bSGustavo Romero 
22*340ca46bSGustavo Romero /*
23*340ca46bSGustavo Romero  * From arch/arm64/include/uapi/asm/mman.h
24*340ca46bSGustavo Romero  */
25*340ca46bSGustavo Romero #define PROT_MTE                 0x20
26*340ca46bSGustavo Romero 
27*340ca46bSGustavo Romero /*
28*340ca46bSGustavo Romero  * Insert a random logical tag into the given pointer.
29*340ca46bSGustavo Romero  */
30*340ca46bSGustavo Romero #define insert_random_tag(ptr) ({                   \
31*340ca46bSGustavo Romero     uint64_t __val;                                 \
32*340ca46bSGustavo Romero     asm("irg %0, %1" : "=r" (__val) : "r" (ptr));   \
33*340ca46bSGustavo Romero     __val;                                          \
34*340ca46bSGustavo Romero })
35*340ca46bSGustavo Romero 
36*340ca46bSGustavo Romero /*
37*340ca46bSGustavo Romero  * Set the allocation tag on the destination address.
38*340ca46bSGustavo Romero  */
39*340ca46bSGustavo Romero #define set_tag(tagged_addr) do {                                      \
40*340ca46bSGustavo Romero         asm volatile("stg %0, [%0]" : : "r" (tagged_addr) : "memory"); \
41*340ca46bSGustavo Romero } while (0)
42*340ca46bSGustavo Romero 
43*340ca46bSGustavo Romero 
main(int argc,char * argv[])44*340ca46bSGustavo Romero int main(int argc, char *argv[])
45*340ca46bSGustavo Romero {
46*340ca46bSGustavo Romero     unsigned char *a;
47*340ca46bSGustavo Romero     unsigned long page_sz = sysconf(_SC_PAGESIZE);
48*340ca46bSGustavo Romero     unsigned long hwcap2 = getauxval(AT_HWCAP2);
49*340ca46bSGustavo Romero 
50*340ca46bSGustavo Romero     /* check if MTE is present */
51*340ca46bSGustavo Romero     if (!(hwcap2 & HWCAP2_MTE)) {
52*340ca46bSGustavo Romero         return EXIT_FAILURE;
53*340ca46bSGustavo Romero     }
54*340ca46bSGustavo Romero 
55*340ca46bSGustavo Romero     /*
56*340ca46bSGustavo Romero      * Enable the tagged address ABI, synchronous or asynchronous MTE
57*340ca46bSGustavo Romero      * tag check faults (based on per-CPU preference) and allow all
58*340ca46bSGustavo Romero      * non-zero tags in the randomly generated set.
59*340ca46bSGustavo Romero      */
60*340ca46bSGustavo Romero     if (prctl(PR_SET_TAGGED_ADDR_CTRL,
61*340ca46bSGustavo Romero               PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC |
62*340ca46bSGustavo Romero               (0xfffe << PR_MTE_TAG_SHIFT),
63*340ca46bSGustavo Romero               0, 0, 0)) {
64*340ca46bSGustavo Romero         perror("prctl() failed");
65*340ca46bSGustavo Romero         return EXIT_FAILURE;
66*340ca46bSGustavo Romero     }
67*340ca46bSGustavo Romero 
68*340ca46bSGustavo Romero     a = mmap(0, page_sz, PROT_READ | PROT_WRITE,
69*340ca46bSGustavo Romero              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
70*340ca46bSGustavo Romero     if (a == MAP_FAILED) {
71*340ca46bSGustavo Romero         perror("mmap() failed");
72*340ca46bSGustavo Romero         return EXIT_FAILURE;
73*340ca46bSGustavo Romero     }
74*340ca46bSGustavo Romero 
75*340ca46bSGustavo Romero     printf("a[] address is %p\n", a);
76*340ca46bSGustavo Romero 
77*340ca46bSGustavo Romero     /*
78*340ca46bSGustavo Romero      * Enable MTE on the above anonymous mmap. The flag could be passed
79*340ca46bSGustavo Romero      * directly to mmap() and skip this step.
80*340ca46bSGustavo Romero      */
81*340ca46bSGustavo Romero     if (mprotect(a, page_sz, PROT_READ | PROT_WRITE | PROT_MTE)) {
82*340ca46bSGustavo Romero         perror("mprotect() failed");
83*340ca46bSGustavo Romero         return EXIT_FAILURE;
84*340ca46bSGustavo Romero     }
85*340ca46bSGustavo Romero 
86*340ca46bSGustavo Romero     /* access with the default tag (0) */
87*340ca46bSGustavo Romero     a[0] = 1;
88*340ca46bSGustavo Romero     a[1] = 2;
89*340ca46bSGustavo Romero 
90*340ca46bSGustavo Romero     printf("a[0] = %hhu a[1] = %hhu\n", a[0], a[1]);
91*340ca46bSGustavo Romero 
92*340ca46bSGustavo Romero     /* set the logical and allocation tags */
93*340ca46bSGustavo Romero     a = (unsigned char *)insert_random_tag(a);
94*340ca46bSGustavo Romero     set_tag(a);
95*340ca46bSGustavo Romero 
96*340ca46bSGustavo Romero     printf("%p\n", a);
97*340ca46bSGustavo Romero 
98*340ca46bSGustavo Romero     return 0;
99*340ca46bSGustavo Romero }
100