18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020 ARM Ltd. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#include <linux/linkage.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <asm/alternative.h> 88c2ecf20Sopenharmony_ci#include <asm/assembler.h> 98c2ecf20Sopenharmony_ci#include <asm/mte.h> 108c2ecf20Sopenharmony_ci#include <asm/page.h> 118c2ecf20Sopenharmony_ci#include <asm/sysreg.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci .arch armv8.5-a+memtag 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * multitag_transfer_size - set \reg to the block size that is accessed by the 178c2ecf20Sopenharmony_ci * LDGM/STGM instructions. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci .macro multitag_transfer_size, reg, tmp 208c2ecf20Sopenharmony_ci mrs_s \reg, SYS_GMID_EL1 218c2ecf20Sopenharmony_ci ubfx \reg, \reg, #SYS_GMID_EL1_BS_SHIFT, #SYS_GMID_EL1_BS_SIZE 228c2ecf20Sopenharmony_ci mov \tmp, #4 238c2ecf20Sopenharmony_ci lsl \reg, \tmp, \reg 248c2ecf20Sopenharmony_ci .endm 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * Clear the tags in a page 288c2ecf20Sopenharmony_ci * x0 - address of the page to be cleared 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ciSYM_FUNC_START(mte_clear_page_tags) 318c2ecf20Sopenharmony_ci multitag_transfer_size x1, x2 328c2ecf20Sopenharmony_ci1: stgm xzr, [x0] 338c2ecf20Sopenharmony_ci add x0, x0, x1 348c2ecf20Sopenharmony_ci tst x0, #(PAGE_SIZE - 1) 358c2ecf20Sopenharmony_ci b.ne 1b 368c2ecf20Sopenharmony_ci ret 378c2ecf20Sopenharmony_ciSYM_FUNC_END(mte_clear_page_tags) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Copy the tags from the source page to the destination one 418c2ecf20Sopenharmony_ci * x0 - address of the destination page 428c2ecf20Sopenharmony_ci * x1 - address of the source page 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ciSYM_FUNC_START(mte_copy_page_tags) 458c2ecf20Sopenharmony_ci mov x2, x0 468c2ecf20Sopenharmony_ci mov x3, x1 478c2ecf20Sopenharmony_ci multitag_transfer_size x5, x6 488c2ecf20Sopenharmony_ci1: ldgm x4, [x3] 498c2ecf20Sopenharmony_ci stgm x4, [x2] 508c2ecf20Sopenharmony_ci add x2, x2, x5 518c2ecf20Sopenharmony_ci add x3, x3, x5 528c2ecf20Sopenharmony_ci tst x2, #(PAGE_SIZE - 1) 538c2ecf20Sopenharmony_ci b.ne 1b 548c2ecf20Sopenharmony_ci ret 558c2ecf20Sopenharmony_ciSYM_FUNC_END(mte_copy_page_tags) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * Read tags from a user buffer (one tag per byte) and set the corresponding 598c2ecf20Sopenharmony_ci * tags at the given kernel address. Used by PTRACE_POKEMTETAGS. 608c2ecf20Sopenharmony_ci * x0 - kernel address (to) 618c2ecf20Sopenharmony_ci * x1 - user buffer (from) 628c2ecf20Sopenharmony_ci * x2 - number of tags/bytes (n) 638c2ecf20Sopenharmony_ci * Returns: 648c2ecf20Sopenharmony_ci * x0 - number of tags read/set 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ciSYM_FUNC_START(mte_copy_tags_from_user) 678c2ecf20Sopenharmony_ci mov x3, x1 688c2ecf20Sopenharmony_ci cbz x2, 2f 698c2ecf20Sopenharmony_ci1: 708c2ecf20Sopenharmony_ci uao_user_alternative 2f, ldrb, ldtrb, w4, x1, 0 718c2ecf20Sopenharmony_ci lsl x4, x4, #MTE_TAG_SHIFT 728c2ecf20Sopenharmony_ci stg x4, [x0], #MTE_GRANULE_SIZE 738c2ecf20Sopenharmony_ci add x1, x1, #1 748c2ecf20Sopenharmony_ci subs x2, x2, #1 758c2ecf20Sopenharmony_ci b.ne 1b 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci // exception handling and function return 788c2ecf20Sopenharmony_ci2: sub x0, x1, x3 // update the number of tags set 798c2ecf20Sopenharmony_ci ret 808c2ecf20Sopenharmony_ciSYM_FUNC_END(mte_copy_tags_from_user) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * Get the tags from a kernel address range and write the tag values to the 848c2ecf20Sopenharmony_ci * given user buffer (one tag per byte). Used by PTRACE_PEEKMTETAGS. 858c2ecf20Sopenharmony_ci * x0 - user buffer (to) 868c2ecf20Sopenharmony_ci * x1 - kernel address (from) 878c2ecf20Sopenharmony_ci * x2 - number of tags/bytes (n) 888c2ecf20Sopenharmony_ci * Returns: 898c2ecf20Sopenharmony_ci * x0 - number of tags read/set 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ciSYM_FUNC_START(mte_copy_tags_to_user) 928c2ecf20Sopenharmony_ci mov x3, x0 938c2ecf20Sopenharmony_ci cbz x2, 2f 948c2ecf20Sopenharmony_ci1: 958c2ecf20Sopenharmony_ci ldg x4, [x1] 968c2ecf20Sopenharmony_ci ubfx x4, x4, #MTE_TAG_SHIFT, #MTE_TAG_SIZE 978c2ecf20Sopenharmony_ci uao_user_alternative 2f, strb, sttrb, w4, x0, 0 988c2ecf20Sopenharmony_ci add x0, x0, #1 998c2ecf20Sopenharmony_ci add x1, x1, #MTE_GRANULE_SIZE 1008c2ecf20Sopenharmony_ci subs x2, x2, #1 1018c2ecf20Sopenharmony_ci b.ne 1b 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci // exception handling and function return 1048c2ecf20Sopenharmony_ci2: sub x0, x0, x3 // update the number of tags copied 1058c2ecf20Sopenharmony_ci ret 1068c2ecf20Sopenharmony_ciSYM_FUNC_END(mte_copy_tags_to_user) 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* 1098c2ecf20Sopenharmony_ci * Save the tags in a page 1108c2ecf20Sopenharmony_ci * x0 - page address 1118c2ecf20Sopenharmony_ci * x1 - tag storage 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ciSYM_FUNC_START(mte_save_page_tags) 1148c2ecf20Sopenharmony_ci multitag_transfer_size x7, x5 1158c2ecf20Sopenharmony_ci1: 1168c2ecf20Sopenharmony_ci mov x2, #0 1178c2ecf20Sopenharmony_ci2: 1188c2ecf20Sopenharmony_ci ldgm x5, [x0] 1198c2ecf20Sopenharmony_ci orr x2, x2, x5 1208c2ecf20Sopenharmony_ci add x0, x0, x7 1218c2ecf20Sopenharmony_ci tst x0, #0xFF // 16 tag values fit in a register, 1228c2ecf20Sopenharmony_ci b.ne 2b // which is 16*16=256 bytes 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci str x2, [x1], #8 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci tst x0, #(PAGE_SIZE - 1) 1278c2ecf20Sopenharmony_ci b.ne 1b 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci ret 1308c2ecf20Sopenharmony_ciSYM_FUNC_END(mte_save_page_tags) 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* 1338c2ecf20Sopenharmony_ci * Restore the tags in a page 1348c2ecf20Sopenharmony_ci * x0 - page address 1358c2ecf20Sopenharmony_ci * x1 - tag storage 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ciSYM_FUNC_START(mte_restore_page_tags) 1388c2ecf20Sopenharmony_ci multitag_transfer_size x7, x5 1398c2ecf20Sopenharmony_ci1: 1408c2ecf20Sopenharmony_ci ldr x2, [x1], #8 1418c2ecf20Sopenharmony_ci2: 1428c2ecf20Sopenharmony_ci stgm x2, [x0] 1438c2ecf20Sopenharmony_ci add x0, x0, x7 1448c2ecf20Sopenharmony_ci tst x0, #0xFF 1458c2ecf20Sopenharmony_ci b.ne 2b 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci tst x0, #(PAGE_SIZE - 1) 1488c2ecf20Sopenharmony_ci b.ne 1b 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci ret 1518c2ecf20Sopenharmony_ciSYM_FUNC_END(mte_restore_page_tags) 152