xref: /openbmc/linux/arch/arm64/lib/mte.S (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
134bfeea4SCatalin Marinas/* SPDX-License-Identifier: GPL-2.0-only */
234bfeea4SCatalin Marinas/*
334bfeea4SCatalin Marinas * Copyright (C) 2020 ARM Ltd.
434bfeea4SCatalin Marinas */
534bfeea4SCatalin Marinas#include <linux/linkage.h>
634bfeea4SCatalin Marinas
7e2a2190aSMark Rutland#include <asm/asm-uaccess.h>
834bfeea4SCatalin Marinas#include <asm/assembler.h>
918ddbaa0SCatalin Marinas#include <asm/mte.h>
102563776bSVincenzo Frascino#include <asm/page.h>
1134bfeea4SCatalin Marinas#include <asm/sysreg.h>
1234bfeea4SCatalin Marinas
1334bfeea4SCatalin Marinas	.arch	armv8.5-a+memtag
1434bfeea4SCatalin Marinas
1534bfeea4SCatalin Marinas/*
1634bfeea4SCatalin Marinas * multitag_transfer_size - set \reg to the block size that is accessed by the
1734bfeea4SCatalin Marinas * LDGM/STGM instructions.
1834bfeea4SCatalin Marinas */
1934bfeea4SCatalin Marinas	.macro	multitag_transfer_size, reg, tmp
2034bfeea4SCatalin Marinas	mrs_s	\reg, SYS_GMID_EL1
21*acb3f4bcSWill Deacon	ubfx	\reg, \reg, #GMID_EL1_BS_SHIFT, #GMID_EL1_BS_WIDTH
2234bfeea4SCatalin Marinas	mov	\tmp, #4
2334bfeea4SCatalin Marinas	lsl	\reg, \tmp, \reg
2434bfeea4SCatalin Marinas	.endm
2534bfeea4SCatalin Marinas
2634bfeea4SCatalin Marinas/*
2734bfeea4SCatalin Marinas * Clear the tags in a page
2834bfeea4SCatalin Marinas *   x0 - address of the page to be cleared
2934bfeea4SCatalin Marinas */
3034bfeea4SCatalin MarinasSYM_FUNC_START(mte_clear_page_tags)
3134bfeea4SCatalin Marinas	multitag_transfer_size x1, x2
3234bfeea4SCatalin Marinas1:	stgm	xzr, [x0]
3334bfeea4SCatalin Marinas	add	x0, x0, x1
3434bfeea4SCatalin Marinas	tst	x0, #(PAGE_SIZE - 1)
3534bfeea4SCatalin Marinas	b.ne	1b
3634bfeea4SCatalin Marinas	ret
3734bfeea4SCatalin MarinasSYM_FUNC_END(mte_clear_page_tags)
382563776bSVincenzo Frascino
392563776bSVincenzo Frascino/*
40013bb59dSPeter Collingbourne * Zero the page and tags at the same time
41013bb59dSPeter Collingbourne *
42013bb59dSPeter Collingbourne * Parameters:
43013bb59dSPeter Collingbourne *	x0 - address to the beginning of the page
44013bb59dSPeter Collingbourne */
45013bb59dSPeter CollingbourneSYM_FUNC_START(mte_zero_clear_page_tags)
46685e2564SReiji Watanabe	and	x0, x0, #(1 << MTE_TAG_SHIFT) - 1	// clear the tag
47013bb59dSPeter Collingbourne	mrs	x1, dczid_el0
48685e2564SReiji Watanabe	tbnz	x1, #4, 2f	// Branch if DC GZVA is prohibited
49013bb59dSPeter Collingbourne	and	w1, w1, #0xf
50013bb59dSPeter Collingbourne	mov	x2, #4
51013bb59dSPeter Collingbourne	lsl	x1, x2, x1
52013bb59dSPeter Collingbourne
53013bb59dSPeter Collingbourne1:	dc	gzva, x0
54013bb59dSPeter Collingbourne	add	x0, x0, x1
55013bb59dSPeter Collingbourne	tst	x0, #(PAGE_SIZE - 1)
56013bb59dSPeter Collingbourne	b.ne	1b
57013bb59dSPeter Collingbourne	ret
58685e2564SReiji Watanabe
59685e2564SReiji Watanabe2:	stz2g	x0, [x0], #(MTE_GRANULE_SIZE * 2)
60685e2564SReiji Watanabe	tst	x0, #(PAGE_SIZE - 1)
61685e2564SReiji Watanabe	b.ne	2b
62685e2564SReiji Watanabe	ret
63013bb59dSPeter CollingbourneSYM_FUNC_END(mte_zero_clear_page_tags)
64013bb59dSPeter Collingbourne
65013bb59dSPeter Collingbourne/*
662563776bSVincenzo Frascino * Copy the tags from the source page to the destination one
672563776bSVincenzo Frascino *   x0 - address of the destination page
682563776bSVincenzo Frascino *   x1 - address of the source page
692563776bSVincenzo Frascino */
702563776bSVincenzo FrascinoSYM_FUNC_START(mte_copy_page_tags)
712563776bSVincenzo Frascino	mov	x2, x0
722563776bSVincenzo Frascino	mov	x3, x1
732563776bSVincenzo Frascino	multitag_transfer_size x5, x6
742563776bSVincenzo Frascino1:	ldgm	x4, [x3]
752563776bSVincenzo Frascino	stgm	x4, [x2]
762563776bSVincenzo Frascino	add	x2, x2, x5
772563776bSVincenzo Frascino	add	x3, x3, x5
782563776bSVincenzo Frascino	tst	x2, #(PAGE_SIZE - 1)
792563776bSVincenzo Frascino	b.ne	1b
802563776bSVincenzo Frascino	ret
812563776bSVincenzo FrascinoSYM_FUNC_END(mte_copy_page_tags)
8218ddbaa0SCatalin Marinas
8318ddbaa0SCatalin Marinas/*
8418ddbaa0SCatalin Marinas * Read tags from a user buffer (one tag per byte) and set the corresponding
8518ddbaa0SCatalin Marinas * tags at the given kernel address. Used by PTRACE_POKEMTETAGS.
8618ddbaa0SCatalin Marinas *   x0 - kernel address (to)
8718ddbaa0SCatalin Marinas *   x1 - user buffer (from)
8818ddbaa0SCatalin Marinas *   x2 - number of tags/bytes (n)
8918ddbaa0SCatalin Marinas * Returns:
9018ddbaa0SCatalin Marinas *   x0 - number of tags read/set
9118ddbaa0SCatalin Marinas */
9218ddbaa0SCatalin MarinasSYM_FUNC_START(mte_copy_tags_from_user)
9318ddbaa0SCatalin Marinas	mov	x3, x1
9418ddbaa0SCatalin Marinas	cbz	x2, 2f
9518ddbaa0SCatalin Marinas1:
96b4d6bb38SRobin MurphyUSER(2f, ldtrb	w4, [x1])
9718ddbaa0SCatalin Marinas	lsl	x4, x4, #MTE_TAG_SHIFT
9818ddbaa0SCatalin Marinas	stg	x4, [x0], #MTE_GRANULE_SIZE
9918ddbaa0SCatalin Marinas	add	x1, x1, #1
10018ddbaa0SCatalin Marinas	subs	x2, x2, #1
10118ddbaa0SCatalin Marinas	b.ne	1b
10218ddbaa0SCatalin Marinas
10318ddbaa0SCatalin Marinas	// exception handling and function return
10418ddbaa0SCatalin Marinas2:	sub	x0, x1, x3		// update the number of tags set
10518ddbaa0SCatalin Marinas	ret
10618ddbaa0SCatalin MarinasSYM_FUNC_END(mte_copy_tags_from_user)
10718ddbaa0SCatalin Marinas
10818ddbaa0SCatalin Marinas/*
10918ddbaa0SCatalin Marinas * Get the tags from a kernel address range and write the tag values to the
11018ddbaa0SCatalin Marinas * given user buffer (one tag per byte). Used by PTRACE_PEEKMTETAGS.
11118ddbaa0SCatalin Marinas *   x0 - user buffer (to)
11218ddbaa0SCatalin Marinas *   x1 - kernel address (from)
11318ddbaa0SCatalin Marinas *   x2 - number of tags/bytes (n)
11418ddbaa0SCatalin Marinas * Returns:
11518ddbaa0SCatalin Marinas *   x0 - number of tags read/set
11618ddbaa0SCatalin Marinas */
11718ddbaa0SCatalin MarinasSYM_FUNC_START(mte_copy_tags_to_user)
11818ddbaa0SCatalin Marinas	mov	x3, x0
11918ddbaa0SCatalin Marinas	cbz	x2, 2f
12018ddbaa0SCatalin Marinas1:
12118ddbaa0SCatalin Marinas	ldg	x4, [x1]
12218ddbaa0SCatalin Marinas	ubfx	x4, x4, #MTE_TAG_SHIFT, #MTE_TAG_SIZE
123b4d6bb38SRobin MurphyUSER(2f, sttrb	w4, [x0])
12418ddbaa0SCatalin Marinas	add	x0, x0, #1
12518ddbaa0SCatalin Marinas	add	x1, x1, #MTE_GRANULE_SIZE
12618ddbaa0SCatalin Marinas	subs	x2, x2, #1
12718ddbaa0SCatalin Marinas	b.ne	1b
12818ddbaa0SCatalin Marinas
12918ddbaa0SCatalin Marinas	// exception handling and function return
13018ddbaa0SCatalin Marinas2:	sub	x0, x0, x3		// update the number of tags copied
13118ddbaa0SCatalin Marinas	ret
13218ddbaa0SCatalin MarinasSYM_FUNC_END(mte_copy_tags_to_user)
13336943abaSSteven Price
13436943abaSSteven Price/*
13536943abaSSteven Price * Save the tags in a page
13636943abaSSteven Price *   x0 - page address
137ab1e435cSCatalin Marinas *   x1 - tag storage, MTE_PAGE_TAG_STORAGE bytes
13836943abaSSteven Price */
13936943abaSSteven PriceSYM_FUNC_START(mte_save_page_tags)
14036943abaSSteven Price	multitag_transfer_size x7, x5
14136943abaSSteven Price1:
14236943abaSSteven Price	mov	x2, #0
14336943abaSSteven Price2:
14436943abaSSteven Price	ldgm	x5, [x0]
14536943abaSSteven Price	orr	x2, x2, x5
14636943abaSSteven Price	add	x0, x0, x7
14736943abaSSteven Price	tst	x0, #0xFF		// 16 tag values fit in a register,
14836943abaSSteven Price	b.ne	2b			// which is 16*16=256 bytes
14936943abaSSteven Price
15036943abaSSteven Price	str	x2, [x1], #8
15136943abaSSteven Price
15236943abaSSteven Price	tst	x0, #(PAGE_SIZE - 1)
15336943abaSSteven Price	b.ne	1b
15436943abaSSteven Price
15536943abaSSteven Price	ret
15636943abaSSteven PriceSYM_FUNC_END(mte_save_page_tags)
15736943abaSSteven Price
15836943abaSSteven Price/*
15936943abaSSteven Price * Restore the tags in a page
16036943abaSSteven Price *   x0 - page address
161ab1e435cSCatalin Marinas *   x1 - tag storage, MTE_PAGE_TAG_STORAGE bytes
16236943abaSSteven Price */
16336943abaSSteven PriceSYM_FUNC_START(mte_restore_page_tags)
16436943abaSSteven Price	multitag_transfer_size x7, x5
16536943abaSSteven Price1:
16636943abaSSteven Price	ldr	x2, [x1], #8
16736943abaSSteven Price2:
16836943abaSSteven Price	stgm	x2, [x0]
16936943abaSSteven Price	add	x0, x0, x7
17036943abaSSteven Price	tst	x0, #0xFF
17136943abaSSteven Price	b.ne	2b
17236943abaSSteven Price
17336943abaSSteven Price	tst	x0, #(PAGE_SIZE - 1)
17436943abaSSteven Price	b.ne	1b
17536943abaSSteven Price
17636943abaSSteven Price	ret
17736943abaSSteven PriceSYM_FUNC_END(mte_restore_page_tags)
178