Skip to content

Commit f8d6aec

Browse files
committed
string: add __mtag_tag_region
Add optimized __mtag_tag_region(dst, len) operation to AOR. It tags the given memory region according to the tag of the dst pointer and returns dst. It requires MTE support. The memory remains untagged if tagging is not enabled for it. The dst must be 16 bytes aligned and len must be a multiple of 16.
1 parent b7e368f commit f8d6aec

File tree

4 files changed

+251
-0
lines changed

4 files changed

+251
-0
lines changed

string/Dir.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ string-tests := \
2929
build/bin/test/memchr \
3030
build/bin/test/memrchr \
3131
build/bin/test/memcmp \
32+
build/bin/test/__mtag_tag_region \
3233
build/bin/test/strcpy \
3334
build/bin/test/stpcpy \
3435
build/bin/test/strcmp \

string/aarch64/__mtag_tag_region.S

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* __mtag_tag_region - tag memory
3+
*
4+
* Copyright (c) 2021, Arm Limited.
5+
* SPDX-License-Identifier: MIT
6+
*/
7+
8+
/* Assumptions:
9+
*
10+
* ARMv8-a, AArch64, MTE, LP64 ABI.
11+
*
12+
* Interface contract:
13+
* Address is 16 byte aligned and size is multiple of 16.
14+
* Returns the passed pointer.
15+
* The memory region may remain untagged if tagging is not enabled.
16+
*/
17+
18+
#include "../asmdefs.h"
19+
20+
#if __ARM_FEATURE_MEMORY_TAGGING
21+
22+
#define dstin x0
23+
#define count x1
24+
#define dst x2
25+
#define dstend x3
26+
#define tmp x4
27+
#define zva_val x4
28+
29+
ENTRY (__mtag_tag_region)
30+
PTR_ARG (0)
31+
SIZE_ARG (1)
32+
33+
add dstend, dstin, count
34+
35+
cmp count, 96
36+
b.hi L(set_long)
37+
38+
tbnz count, 6, L(set96)
39+
40+
/* Set 0, 16, 32, or 48 bytes. */
41+
lsr tmp, count, 5
42+
add tmp, dstin, tmp, lsl 4
43+
cbz count, L(end)
44+
stg dstin, [dstin]
45+
stg dstin, [tmp]
46+
stg dstin, [dstend, -16]
47+
L(end):
48+
ret
49+
50+
.p2align 4
51+
/* Set 64..96 bytes. Write 64 bytes from the start and
52+
32 bytes from the end. */
53+
L(set96):
54+
st2g dstin, [dstin]
55+
st2g dstin, [dstin, 32]
56+
st2g dstin, [dstend, -32]
57+
ret
58+
59+
.p2align 4
60+
/* Size is > 96 bytes. */
61+
L(set_long):
62+
cmp count, 160
63+
b.lo L(no_zva)
64+
65+
#ifndef SKIP_ZVA_CHECK
66+
mrs zva_val, dczid_el0
67+
and zva_val, zva_val, 31
68+
cmp zva_val, 4 /* ZVA size is 64 bytes. */
69+
b.ne L(no_zva)
70+
#endif
71+
st2g dstin, [dstin]
72+
st2g dstin, [dstin, 32]
73+
bic dst, dstin, 63
74+
sub count, dstend, dst /* Count is now 64 too large. */
75+
sub count, count, 128 /* Adjust count and bias for loop. */
76+
77+
.p2align 4
78+
L(zva_loop):
79+
add dst, dst, 64
80+
dc gva, dst
81+
subs count, count, 64
82+
b.hi L(zva_loop)
83+
st2g dstin, [dstend, -64]
84+
st2g dstin, [dstend, -32]
85+
ret
86+
87+
L(no_zva):
88+
sub dst, dstin, 32 /* Dst is biased by -32. */
89+
sub count, count, 64 /* Adjust count for loop. */
90+
L(no_zva_loop):
91+
st2g dstin, [dst, 32]
92+
st2g dstin, [dst, 64]!
93+
subs count, count, 64
94+
b.hi L(no_zva_loop)
95+
st2g dstin, [dstend, -64]
96+
st2g dstin, [dstend, -32]
97+
ret
98+
99+
END (__mtag_tag_region)
100+
#endif

string/include/stringlib.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ size_t __strlen_aarch64_sve (const char *);
5454
size_t __strnlen_aarch64_sve (const char *, size_t);
5555
int __strncmp_aarch64_sve (const char *, const char *, size_t);
5656
# endif
57+
# if __ARM_FEATURE_MEMORY_TAGGING
58+
void *__mtag_tag_region (void *, size_t);
59+
# endif
5760
#elif __arm__
5861
void *__memcpy_arm (void *__restrict, const void *__restrict, size_t);
5962
void *__memset_arm (void *, int, size_t);

string/test/__mtag_tag_region.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* __mtag_tag_region test.
3+
*
4+
* Copyright (c) 2021, Arm Limited.
5+
* SPDX-License-Identifier: MIT
6+
*/
7+
8+
#if __ARM_FEATURE_MEMORY_TAGGING && WANT_MTE_TEST
9+
#include <stdint.h>
10+
#include <stdio.h>
11+
#include <stdlib.h>
12+
#include <string.h>
13+
#include "mte.h"
14+
#include "stringlib.h"
15+
#include "stringtest.h"
16+
17+
static void
18+
mtag_quoteat (const char *prefix, void *p, int len, int at)
19+
{
20+
/* Print tag, untag and quote the context. */
21+
printf ("location: %p\n", __arm_mte_get_tag ((char *) p + at));
22+
untag_buffer (p, len, 1);
23+
p = untag_pointer (p);
24+
quoteat (prefix, p, len, at);
25+
}
26+
27+
#define F(x) {#x, x},
28+
29+
static const struct fun
30+
{
31+
const char *name;
32+
void *(*fun) (void *s, size_t n);
33+
} funtab[] = {
34+
// clang-format off
35+
#if __aarch64__
36+
F(__mtag_tag_region)
37+
#endif
38+
{0, 0}
39+
// clang-format on
40+
};
41+
#undef F
42+
43+
#define A 64
44+
#define LEN 250000
45+
static unsigned char *sbuf;
46+
47+
static void *
48+
alignup (void *p)
49+
{
50+
return (void *) (((uintptr_t) p + A - 1) & -A);
51+
}
52+
53+
static void
54+
test (const struct fun *fun, int salign, int len)
55+
{
56+
unsigned char *src = alignup (sbuf);
57+
unsigned char *s = src + salign;
58+
void *p;
59+
int i;
60+
61+
if (err_count >= ERR_LIMIT)
62+
return;
63+
if (len > LEN || salign >= A)
64+
abort ();
65+
for (i = 0; i < len + 2 * A; i++)
66+
src[i] = '?';
67+
for (i = 0; i < len; i++)
68+
s[i] = 'a';
69+
70+
src = tag_buffer (src, len + 2 * A, 1);
71+
s = src + salign;
72+
/* Use different tag. */
73+
s = __arm_mte_increment_tag (s, 1);
74+
p = fun->fun (s, len);
75+
76+
if (p != s)
77+
ERR ("%s(%p,..) returned %p\n", fun->name, s, p);
78+
79+
for (i = 0; i < salign; i++)
80+
{
81+
if (src[i] != '?')
82+
{
83+
ERR ("%s(align %d, %d) failed\n", fun->name, salign, len);
84+
mtag_quoteat ("got head", src, len + 2 * A, i);
85+
return;
86+
}
87+
}
88+
89+
for (; i < salign + len; i++)
90+
{
91+
if (s[i - salign] != 'a')
92+
{
93+
ERR ("%s(align %d, %d) failed\n", fun->name, salign, len);
94+
mtag_quoteat ("got body", src, len + 2 * A, i);
95+
return;
96+
}
97+
}
98+
99+
for (; i < len + 2 * A; i++)
100+
{
101+
if (src[i] != '?')
102+
{
103+
ERR ("%s(align %d, %d) failed\n", fun->name, salign, len);
104+
mtag_quoteat ("got tail", src, len + 2 * A, i);
105+
return;
106+
}
107+
}
108+
109+
untag_buffer (src, len + 2 * A, 1);
110+
}
111+
112+
int
113+
main ()
114+
{
115+
if (!mte_enabled ())
116+
return 0;
117+
118+
sbuf = mte_mmap (LEN + 3 * A);
119+
int r = 0;
120+
for (int i = 0; funtab[i].name; i++)
121+
{
122+
err_count = 0;
123+
for (int s = 0; s < A; s += 16)
124+
{
125+
int n;
126+
for (n = 0; n < 200; n += 16)
127+
{
128+
test (funtab + i, s, n);
129+
}
130+
for (; n < LEN; n *= 2)
131+
{
132+
test (funtab + i, s, n);
133+
}
134+
}
135+
printf ("%s %s\n", err_count ? "FAIL" : "PASS", funtab[i].name);
136+
if (err_count)
137+
r = -1;
138+
}
139+
return r;
140+
}
141+
#else
142+
int
143+
main ()
144+
{
145+
return 0;
146+
}
147+
#endif

0 commit comments

Comments
 (0)