1 /*
2  * Memory tagging testing code.
3  *
4  * Copyright (c) 2020, Arm Limited.
5  * SPDX-License-Identifier: MIT
6  */
7 
8 #ifndef __TEST_MTE_H
9 #define __TEST_MTE_H
10 
11 #include <stdlib.h>
12 
13 #if __ARM_FEATURE_MEMORY_TAGGING && WANT_MTE_TEST
14 #include <arm_acle.h>
15 #include <sys/mman.h>
16 #include <sys/prctl.h>
17 
18 // These depend on a not yet merged kernel ABI.
19 #define PR_SET_TAGGED_ADDR_CTRL 55
20 #define PR_TAGGED_ADDR_ENABLE (1UL << 0)
21 #define PR_MTE_TCF_SHIFT 1
22 #define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
23 #define PR_MTE_TAG_SHIFT 3
24 #define PROT_MTE 0x20
25 
26 #define MTE_GRANULE_SIZE 16
27 
28 int
29 mte_enabled ()
30 {
31   static int enabled = -1;
32   if (enabled == -1)
33     {
34       int res = prctl (PR_SET_TAGGED_ADDR_CTRL,
35 		       PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC
36 			 | (0xfffe << PR_MTE_TAG_SHIFT),
37 		       0, 0, 0);
38       enabled = (res == 0);
39     }
40   return enabled;
41 }
42 
43 static void *
44 mte_mmap (size_t size)
45 {
46   if (mte_enabled ())
47     {
48       return mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_MTE,
49 		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
50     }
51   else
52     {
53       return malloc (size);
54     }
55 }
56 
57 void *
58 alignup_mte (void *p)
59 {
60   return (void *) (((uintptr_t) p + MTE_GRANULE_SIZE - 1)
61 		   & ~(MTE_GRANULE_SIZE - 1));
62 }
63 
64 void *
65 aligndown_mte (void *p)
66 {
67   return (void *) ((uintptr_t) p & ~(MTE_GRANULE_SIZE - 1));
68 }
69 
70 void *
71 untag_pointer (void *p)
72 {
73   return (void *) ((unsigned long long) p & (~0ULL >> 8));
74 }
75 
76 void
77 tag_buffer_helper (void *p, int len)
78 {
79   char *ptr = p;
80   char *end = alignup_mte (ptr + len);
81   ptr = aligndown_mte (p);
82   for (; ptr < end; ptr += MTE_GRANULE_SIZE)
83     {
84       __arm_mte_set_tag (ptr);
85     }
86 }
87 
88 void *
89 tag_buffer (void *p, int len, int test_mte)
90 {
91   if (test_mte && mte_enabled ())
92     {
93       p = __arm_mte_increment_tag (p, 1);
94       tag_buffer_helper (p, len);
95     }
96   return p;
97 }
98 
99 void *
100 untag_buffer (void *p, int len, int test_mte)
101 {
102   p = untag_pointer (p);
103   if (test_mte && mte_enabled ())
104     {
105       tag_buffer_helper (p, len);
106     }
107   return p;
108 }
109 
110 #else  // __ARM_FEATURE_MEMORY_TAGGING
111 int
112 mte_enabled ()
113 {
114   return 0;
115 }
116 static void *
117 mte_mmap (size_t size)
118 {
119   return malloc (size);
120 }
121 void *
122 tag_buffer (void *p, int len, int test_mte)
123 {
124   (void) len;
125   (void) test_mte;
126   return p;
127 }
128 void *
129 untag_buffer (void *p, int len, int test_mte)
130 {
131   (void) len;
132   (void) test_mte;
133   return p;
134 }
135 void *
136 untag_pointer (void *p)
137 {
138   return p;
139 }
140 #endif // __ARM_FEATURE_MEMORY_TAGGING
141 
142 #endif
143