1/*
2 * Memory tagging testing code.
3 *
4 * Copyright (c) 2020, Arm Limited.
5 * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
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
28int
29mte_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
43static void *
44mte_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
57void *
58alignup_mte (void *p)
59{
60  return (void *) (((uintptr_t) p + MTE_GRANULE_SIZE - 1)
61		   & ~(MTE_GRANULE_SIZE - 1));
62}
63
64void *
65aligndown_mte (void *p)
66{
67  return (void *) ((uintptr_t) p & ~(MTE_GRANULE_SIZE - 1));
68}
69
70void *
71untag_pointer (void *p)
72{
73  return (void *) ((unsigned long long) p & (~0ULL >> 8));
74}
75
76void
77tag_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
88void *
89tag_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
99void *
100untag_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
111int
112mte_enabled ()
113{
114  return 0;
115}
116static void *
117mte_mmap (size_t size)
118{
119  return malloc (size);
120}
121void *
122tag_buffer (void *p, int len, int test_mte)
123{
124  (void) len;
125  (void) test_mte;
126  return p;
127}
128void *
129untag_buffer (void *p, int len, int test_mte)
130{
131  (void) len;
132  (void) test_mte;
133  return p;
134}
135void *
136untag_pointer (void *p)
137{
138  return p;
139}
140#endif // __ARM_FEATURE_MEMORY_TAGGING
141
142#endif
143