1 /* SPDX-License-Identifier: GPL-2.0-only */
3 * Copyright (C) 2020 ARM Ltd.
5 #include <linux/linkage.h>
7 #include <asm/asm-uaccess.h>
8 #include <asm/assembler.h>
11 #include <asm/sysreg.h>
13 .arch armv8.5-a+memtag
16 * multitag_transfer_size - set \reg to the block size that is accessed by the
17 * LDGM/STGM instructions.
19 .macro multitag_transfer_size, reg, tmp
20 mrs_s \reg, SYS_GMID_EL1
21 ubfx \reg, \reg, #GMID_EL1_BS_SHIFT, #GMID_EL1_BS_WIDTH
27 * Clear the tags in a page
28 * x0 - address of the page to be cleared
30 SYM_FUNC_START(mte_clear_page_tags)
31 multitag_transfer_size x1, x2
34 tst x0, #(PAGE_SIZE - 1)
37 SYM_FUNC_END(mte_clear_page_tags)
40 * Zero the page and tags at the same time
43 * x0 - address to the beginning of the page
45 SYM_FUNC_START(mte_zero_clear_page_tags)
46 and x0, x0, #(1 << MTE_TAG_SHIFT) - 1 // clear the tag
48 tbnz x1, #4, 2f // Branch if DC GZVA is prohibited
55 tst x0, #(PAGE_SIZE - 1)
59 2: stz2g x0, [x0], #(MTE_GRANULE_SIZE * 2)
60 tst x0, #(PAGE_SIZE - 1)
63 SYM_FUNC_END(mte_zero_clear_page_tags)
66 * Copy the tags from the source page to the destination one
67 * x0 - address of the destination page
68 * x1 - address of the source page
70 SYM_FUNC_START(mte_copy_page_tags)
73 multitag_transfer_size x5, x6
78 tst x2, #(PAGE_SIZE - 1)
81 SYM_FUNC_END(mte_copy_page_tags)
84 * Read tags from a user buffer (one tag per byte) and set the corresponding
85 * tags at the given kernel address. Used by PTRACE_POKEMTETAGS.
86 * x0 - kernel address (to)
87 * x1 - user buffer (from)
88 * x2 - number of tags/bytes (n)
90 * x0 - number of tags read/set
92 SYM_FUNC_START(mte_copy_tags_from_user)
96 USER(2f, ldtrb w4, [x1])
97 lsl x4, x4, #MTE_TAG_SHIFT
98 stg x4, [x0], #MTE_GRANULE_SIZE
103 // exception handling and function return
104 2: sub x0, x1, x3 // update the number of tags set
106 SYM_FUNC_END(mte_copy_tags_from_user)
109 * Get the tags from a kernel address range and write the tag values to the
110 * given user buffer (one tag per byte). Used by PTRACE_PEEKMTETAGS.
111 * x0 - user buffer (to)
112 * x1 - kernel address (from)
113 * x2 - number of tags/bytes (n)
115 * x0 - number of tags read/set
117 SYM_FUNC_START(mte_copy_tags_to_user)
122 ubfx x4, x4, #MTE_TAG_SHIFT, #MTE_TAG_SIZE
123 USER(2f, sttrb w4, [x0])
125 add x1, x1, #MTE_GRANULE_SIZE
129 // exception handling and function return
130 2: sub x0, x0, x3 // update the number of tags copied
132 SYM_FUNC_END(mte_copy_tags_to_user)
135 * Save the tags in a page
137 * x1 - tag storage, MTE_PAGE_TAG_STORAGE bytes
139 SYM_FUNC_START(mte_save_page_tags)
140 multitag_transfer_size x7, x5
147 tst x0, #0xFF // 16 tag values fit in a register,
148 b.ne 2b // which is 16*16=256 bytes
152 tst x0, #(PAGE_SIZE - 1)
156 SYM_FUNC_END(mte_save_page_tags)
159 * Restore the tags in a page
161 * x1 - tag storage, MTE_PAGE_TAG_STORAGE bytes
163 SYM_FUNC_START(mte_restore_page_tags)
164 multitag_transfer_size x7, x5
173 tst x0, #(PAGE_SIZE - 1)
177 SYM_FUNC_END(mte_restore_page_tags)