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