/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright ( C ) 2020 ARM Ltd .
*/
#include <linux/linkage.h>
#include <asm/asm-uaccess.h>
#include <asm/assembler.h>
#include <asm/mte.h>
#include <asm/page.h>
#include <asm/sysreg.h>
.arch armv8.5 -a+memtag
/*
* multitag_transfer_size - set \ reg to the block size that is accessed by the
* LDGM / STGM instructions .
*/
.macro multitag_transfer_size, reg, tmp
mrs_s \reg, SYS_GMID_EL1
ubfx \reg, \reg, #GMID_EL1_BS_SHIFT, #GMID_EL1_BS_WIDTH
mov \tmp, #4
lsl \reg, \tmp, \reg
.endm
/*
* Clear the tags in a page
* x0 - address of the page to be cleared
*/
SYM_FUNC_START(mte_clear_page_tags)
multitag_transfer_size x1, x2
1 : stgm xzr, [x0]
add x0, x0, x1
tst x0, #(PAGE_SIZE - 1 )
b.ne 1 b
ret
SYM_FUNC_END(mte_clear_page_tags)
/*
* Zero the page and tags at the same time
*
* Parameters :
* x0 - address to the beginning of the page
*/
SYM_FUNC_START(mte_zero_clear_page_tags)
and x0, x0, #(1 << MTE_TAG_SHIFT) - 1 // clear the tag
mrs x1, dczid_el0
tbnz x1, #4 , 2 f // Branch if DC GZVA is prohibited
and w1, w1, #0 xf
mov x2, #4
lsl x1, x2, x1
1 : dc gzva, x0
add x0, x0, x1
tst x0, #(PAGE_SIZE - 1 )
b.ne 1 b
ret
2 : stz2g x0, [x0], #(MTE_GRANULE_SIZE * 2 )
tst x0, #(PAGE_SIZE - 1 )
b.ne 2 b
ret
SYM_FUNC_END(mte_zero_clear_page_tags)
/*
* Copy the tags from the source page to the destination one
* x0 - address of the destination page
* x1 - address of the source page
*/
SYM_FUNC_START(mte_copy_page_tags)
mov x2, x0
mov x3, x1
multitag_transfer_size x5, x6
1 : ldgm x4, [x3]
stgm x4, [x2]
add x2, x2, x5
add x3, x3, x5
tst x2, #(PAGE_SIZE - 1 )
b.ne 1 b
ret
SYM_FUNC_END(mte_copy_page_tags)
/*
* Read tags from a user buffer ( one tag per byte ) and set the corresponding
* tags at the given kernel address . Used by PTRACE_POKEMTETAGS .
* x0 - kernel address ( to )
* x1 - user buffer ( from )
* x2 - number of tags / bytes ( n )
* Returns :
* x0 - number of tags read / set
*/
SYM_FUNC_START(mte_copy_tags_from_user)
mov x3, x1
cbz x2, 2 f
1 :
USER(2 f, ldtrb w4, [x1])
lsl x4, x4, #MTE_TAG_SHIFT
stg x4, [x0], #MTE_GRANULE_SIZE
add x1, x1, #1
subs x2, x2, #1
b.ne 1 b
// exception handling and function return
2 : sub x0, x1, x3 // update the number of tags set
ret
SYM_FUNC_END(mte_copy_tags_from_user)
/*
* Get the tags from a kernel address range and write the tag values to the
* given user buffer ( one tag per byte ) . Used by PTRACE_PEEKMTETAGS .
* x0 - user buffer ( to )
* x1 - kernel address ( from )
* x2 - number of tags / bytes ( n )
* Returns :
* x0 - number of tags read / set
*/
SYM_FUNC_START(mte_copy_tags_to_user)
mov x3, x0
cbz x2, 2 f
1 :
ldg x4, [x1]
ubfx x4, x4, #MTE_TAG_SHIFT, #MTE_TAG_SIZE
USER(2 f, sttrb w4, [x0])
add x0, x0, #1
add x1, x1, #MTE_GRANULE_SIZE
subs x2, x2, #1
b.ne 1 b
// exception handling and function return
2 : sub x0, x0, x3 // update the number of tags copied
ret
SYM_FUNC_END(mte_copy_tags_to_user)
/*
* Save the tags in a page
* x0 - page address
* x1 - tag storage , MTE_PAGE_TAG_STORAGE bytes
*/
SYM_FUNC_START(mte_save_page_tags)
multitag_transfer_size x7, x5
1 :
mov x2, #0
2 :
ldgm x5, [x0]
orr x2, x2, x5
add x0, x0, x7
tst x0, #0 xFF // 16 tag values fit in a register,
b.ne 2 b // which is 16 *16 =256 bytes
str x2, [x1], #8
tst x0, #(PAGE_SIZE - 1 )
b.ne 1 b
ret
SYM_FUNC_END(mte_save_page_tags)
/*
* Restore the tags in a page
* x0 - page address
* x1 - tag storage , MTE_PAGE_TAG_STORAGE bytes
*/
SYM_FUNC_START(mte_restore_page_tags)
multitag_transfer_size x7, x5
1 :
ldr x2, [x1], #8
2 :
stgm x2, [x0]
add x0, x0, x7
tst x0, #0 xFF
b.ne 2 b
tst x0, #(PAGE_SIZE - 1 )
b.ne 1 b
ret
SYM_FUNC_END(mte_restore_page_tags)
Messung V0.5 in Prozent C=95 H=92 G=93
¤ Dauer der Verarbeitung: 0.5 Sekunden
¤
*© Formatika GbR, Deutschland