1238384Sjkim/*
2238384Sjkim * __mtag_tag_region - tag memory
3238384Sjkim *
4238384Sjkim * Copyright (c) 2021-2022, Arm Limited.
5238384Sjkim * SPDX-License-Identifier: MIT OR Apache-2.0 WITH LLVM-exception
6238384Sjkim */
7238384Sjkim
8238384Sjkim/* Assumptions:
9238384Sjkim *
10238384Sjkim * ARMv8-a, AArch64, MTE, LP64 ABI.
11238384Sjkim *
12238384Sjkim * Interface contract:
13238384Sjkim * Address is 16 byte aligned and size is multiple of 16.
14238384Sjkim * Returns the passed pointer.
15238384Sjkim * The memory region may remain untagged if tagging is not enabled.
16238384Sjkim */
17238384Sjkim
18238384Sjkim#include "asmdefs.h"
19238384Sjkim
20238384Sjkim#if __ARM_FEATURE_MEMORY_TAGGING
21238384Sjkim
22238384Sjkim#define dstin	x0
23238384Sjkim#define count	x1
24238384Sjkim#define dst	x2
25238384Sjkim#define dstend	x3
26238384Sjkim#define tmp	x4
27238384Sjkim#define zva_val	x4
28238384Sjkim
29238384SjkimENTRY (__mtag_tag_region)
30238384Sjkim	PTR_ARG (0)
31238384Sjkim	SIZE_ARG (1)
32238384Sjkim
33238384Sjkim	add	dstend, dstin, count
34238384Sjkim
35238384Sjkim	cmp	count, 96
36238384Sjkim	b.hi	L(set_long)
37238384Sjkim
38238384Sjkim	tbnz	count, 6, L(set96)
39238384Sjkim
40238384Sjkim	/* Set 0, 16, 32, or 48 bytes.  */
41238384Sjkim	lsr	tmp, count, 5
42238384Sjkim	add	tmp, dstin, tmp, lsl 4
43238384Sjkim	cbz     count, L(end)
44238384Sjkim	stg	dstin, [dstin]
45238384Sjkim	stg	dstin, [tmp]
46238384Sjkim	stg	dstin, [dstend, -16]
47238384SjkimL(end):
48238384Sjkim	ret
49238384Sjkim
50238384Sjkim	.p2align 4
51238384Sjkim	/* Set 64..96 bytes.  Write 64 bytes from the start and
52238384Sjkim	   32 bytes from the end.  */
53238384SjkimL(set96):
54238384Sjkim	st2g	dstin, [dstin]
55238384Sjkim	st2g	dstin, [dstin, 32]
56238384Sjkim	st2g	dstin, [dstend, -32]
57238384Sjkim	ret
58238384Sjkim
59238384Sjkim	.p2align 4
60238384Sjkim	/* Size is > 96 bytes.  */
61238384SjkimL(set_long):
62238384Sjkim	cmp	count, 160
63238384Sjkim	b.lo	L(no_zva)
64238384Sjkim
65238384Sjkim#ifndef SKIP_ZVA_CHECK
66238384Sjkim	mrs	zva_val, dczid_el0
67238384Sjkim	and	zva_val, zva_val, 31
68238384Sjkim	cmp	zva_val, 4		/* ZVA size is 64 bytes.  */
69238384Sjkim	b.ne	L(no_zva)
70238384Sjkim#endif
71238384Sjkim	st2g	dstin, [dstin]
72238384Sjkim	st2g	dstin, [dstin, 32]
73238384Sjkim	bic	dst, dstin, 63
74238384Sjkim	sub	count, dstend, dst	/* Count is now 64 too large.  */
75238384Sjkim	sub	count, count, 128	/* Adjust count and bias for loop.  */
76238384Sjkim
77238384Sjkim	.p2align 4
78238384SjkimL(zva_loop):
79238384Sjkim	add	dst, dst, 64
80238384Sjkim	dc	gva, dst
81238384Sjkim	subs	count, count, 64
82238384Sjkim	b.hi	L(zva_loop)
83238384Sjkim	st2g	dstin, [dstend, -64]
84238384Sjkim	st2g	dstin, [dstend, -32]
85238384Sjkim	ret
86238384Sjkim
87238384SjkimL(no_zva):
88238384Sjkim	sub	dst, dstin, 32		/* Dst is biased by -32.  */
89238384Sjkim	sub	count, count, 64	/* Adjust count for loop.  */
90238384SjkimL(no_zva_loop):
91238384Sjkim	st2g	dstin, [dst, 32]
92238384Sjkim	st2g	dstin, [dst, 64]!
93238384Sjkim	subs	count, count, 64
94238384Sjkim	b.hi	L(no_zva_loop)
95238384Sjkim	st2g	dstin, [dstend, -64]
96238384Sjkim	st2g	dstin, [dstend, -32]
97238384Sjkim	ret
98238384Sjkim
99238384SjkimEND (__mtag_tag_region)
100238384Sjkim#endif
101238384Sjkim