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
mte_enabled()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 *
mte_mmap(size_t size)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 *
alignup_mte(void * p)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 *
aligndown_mte(void * p)65 aligndown_mte (void *p)
66 {
67 return (void *) ((uintptr_t) p & ~(MTE_GRANULE_SIZE - 1));
68 }
69
70 void *
untag_pointer(void * p)71 untag_pointer (void *p)
72 {
73 return (void *) ((unsigned long long) p & (~0ULL >> 8));
74 }
75
76 void
tag_buffer_helper(void * p,int len)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 *
tag_buffer(void * p,int len,int test_mte)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 *
untag_buffer(void * p,int len,int test_mte)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
mte_enabled()112 mte_enabled ()
113 {
114 return 0;
115 }
116 static void *
mte_mmap(size_t size)117 mte_mmap (size_t size)
118 {
119 return malloc (size);
120 }
121 void *
tag_buffer(void * p,int len,int test_mte)122 tag_buffer (void *p, int len, int test_mte)
123 {
124 (void) len;
125 (void) test_mte;
126 return p;
127 }
128 void *
untag_buffer(void * p,int len,int test_mte)129 untag_buffer (void *p, int len, int test_mte)
130 {
131 (void) len;
132 (void) test_mte;
133 return p;
134 }
135 void *
untag_pointer(void * p)136 untag_pointer (void *p)
137 {
138 return p;
139 }
140 #endif // __ARM_FEATURE_MEMORY_TAGGING
141
142 #endif
143