Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: mte: add in-kernel MTE helpers

Provide helper functions to manipulate allocation and pointer tags for
kernel addresses.

Low-level helper functions (mte_assign_*, written in assembly) operate tag
values from the [0x0, 0xF] range. High-level helper functions
(mte_get/set_*) use the [0xF0, 0xFF] range to preserve compatibility with
normal kernel pointers that have 0xFF in their top byte.

MTE_GRANULE_SIZE and related definitions are moved to mte-def.h header
that doesn't have any dependencies and is safe to include into any
low-level header.

Link: https://lkml.kernel.org/r/c31bf759b4411b2d98cdd801eb928e241584fd1f.1606161801.git.andreyknvl@google.com
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Co-developed-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Branislav Rankov <Branislav.Rankov@arm.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Evgenii Stepanov <eugenis@google.com>
Cc: Kevin Brodsky <kevin.brodsky@arm.com>
Cc: Marco Elver <elver@google.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Vincenzo Frascino and committed by
Linus Torvalds
85f49cae f469c032

+150 -6
+1
arch/arm64/include/asm/esr.h
··· 106 106 #define ESR_ELx_FSC_TYPE (0x3C) 107 107 #define ESR_ELx_FSC_LEVEL (0x03) 108 108 #define ESR_ELx_FSC_EXTABT (0x10) 109 + #define ESR_ELx_FSC_MTE (0x11) 109 110 #define ESR_ELx_FSC_SERROR (0x11) 110 111 #define ESR_ELx_FSC_ACCESS (0x08) 111 112 #define ESR_ELx_FSC_FAULT (0x04)
+15
arch/arm64/include/asm/mte-def.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020 ARM Ltd. 4 + */ 5 + #ifndef __ASM_MTE_DEF_H 6 + #define __ASM_MTE_DEF_H 7 + 8 + #define MTE_GRANULE_SIZE UL(16) 9 + #define MTE_GRANULE_MASK (~(MTE_GRANULE_SIZE - 1)) 10 + #define MTE_TAG_SHIFT 56 11 + #define MTE_TAG_SIZE 4 12 + #define MTE_TAG_MASK GENMASK((MTE_TAG_SHIFT + (MTE_TAG_SIZE - 1)), MTE_TAG_SHIFT) 13 + #define MTE_TAG_MAX (MTE_TAG_MASK >> MTE_TAG_SHIFT) 14 + 15 + #endif /* __ASM_MTE_DEF_H */
+56
arch/arm64/include/asm/mte-kasan.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020 ARM Ltd. 4 + */ 5 + #ifndef __ASM_MTE_KASAN_H 6 + #define __ASM_MTE_KASAN_H 7 + 8 + #include <asm/mte-def.h> 9 + 10 + #ifndef __ASSEMBLY__ 11 + 12 + #include <linux/types.h> 13 + 14 + /* 15 + * The functions below are meant to be used only for the 16 + * KASAN_HW_TAGS interface defined in asm/memory.h. 17 + */ 18 + #ifdef CONFIG_ARM64_MTE 19 + 20 + static inline u8 mte_get_ptr_tag(void *ptr) 21 + { 22 + /* Note: The format of KASAN tags is 0xF<x> */ 23 + u8 tag = 0xF0 | (u8)(((u64)(ptr)) >> MTE_TAG_SHIFT); 24 + 25 + return tag; 26 + } 27 + 28 + u8 mte_get_mem_tag(void *addr); 29 + u8 mte_get_random_tag(void); 30 + void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag); 31 + 32 + #else /* CONFIG_ARM64_MTE */ 33 + 34 + static inline u8 mte_get_ptr_tag(void *ptr) 35 + { 36 + return 0xFF; 37 + } 38 + 39 + static inline u8 mte_get_mem_tag(void *addr) 40 + { 41 + return 0xFF; 42 + } 43 + static inline u8 mte_get_random_tag(void) 44 + { 45 + return 0xFF; 46 + } 47 + static inline void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag) 48 + { 49 + return addr; 50 + } 51 + 52 + #endif /* CONFIG_ARM64_MTE */ 53 + 54 + #endif /* __ASSEMBLY__ */ 55 + 56 + #endif /* __ASM_MTE_KASAN_H */
+14 -6
arch/arm64/include/asm/mte.h
··· 5 5 #ifndef __ASM_MTE_H 6 6 #define __ASM_MTE_H 7 7 8 - #define MTE_GRANULE_SIZE UL(16) 9 - #define MTE_GRANULE_MASK (~(MTE_GRANULE_SIZE - 1)) 10 - #define MTE_TAG_SHIFT 56 11 - #define MTE_TAG_SIZE 4 8 + #include <asm/compiler.h> 9 + #include <asm/mte-def.h> 10 + 11 + #define __MTE_PREAMBLE ARM64_ASM_PREAMBLE ".arch_extension memtag\n" 12 12 13 13 #ifndef __ASSEMBLY__ 14 14 15 + #include <linux/bitfield.h> 15 16 #include <linux/page-flags.h> 17 + #include <linux/types.h> 16 18 17 19 #include <asm/pgtable-types.h> 18 20 ··· 47 45 int mte_ptrace_copy_tags(struct task_struct *child, long request, 48 46 unsigned long addr, unsigned long data); 49 47 50 - #else 48 + void mte_assign_mem_tag_range(void *addr, size_t size); 49 + 50 + #else /* CONFIG_ARM64_MTE */ 51 51 52 52 /* unused if !CONFIG_ARM64_MTE, silence the compiler */ 53 53 #define PG_mte_tagged 0 ··· 84 80 return -EIO; 85 81 } 86 82 87 - #endif 83 + static inline void mte_assign_mem_tag_range(void *addr, size_t size) 84 + { 85 + } 86 + 87 + #endif /* CONFIG_ARM64_MTE */ 88 88 89 89 #endif /* __ASSEMBLY__ */ 90 90 #endif /* __ASM_MTE_H */
+48
arch/arm64/kernel/mte.c
··· 13 13 #include <linux/swap.h> 14 14 #include <linux/swapops.h> 15 15 #include <linux/thread_info.h> 16 + #include <linux/types.h> 16 17 #include <linux/uio.h> 17 18 19 + #include <asm/barrier.h> 18 20 #include <asm/cpufeature.h> 19 21 #include <asm/mte.h> 22 + #include <asm/mte-kasan.h> 20 23 #include <asm/ptrace.h> 21 24 #include <asm/sysreg.h> 22 25 ··· 73 70 return addr1 != addr2; 74 71 75 72 return ret; 73 + } 74 + 75 + u8 mte_get_mem_tag(void *addr) 76 + { 77 + if (!system_supports_mte()) 78 + return 0xFF; 79 + 80 + asm(__MTE_PREAMBLE "ldg %0, [%0]" 81 + : "+r" (addr)); 82 + 83 + return mte_get_ptr_tag(addr); 84 + } 85 + 86 + u8 mte_get_random_tag(void) 87 + { 88 + void *addr; 89 + 90 + if (!system_supports_mte()) 91 + return 0xFF; 92 + 93 + asm(__MTE_PREAMBLE "irg %0, %0" 94 + : "+r" (addr)); 95 + 96 + return mte_get_ptr_tag(addr); 97 + } 98 + 99 + void *mte_set_mem_tag_range(void *addr, size_t size, u8 tag) 100 + { 101 + void *ptr = addr; 102 + 103 + if ((!system_supports_mte()) || (size == 0)) 104 + return addr; 105 + 106 + /* Make sure that size is MTE granule aligned. */ 107 + WARN_ON(size & (MTE_GRANULE_SIZE - 1)); 108 + 109 + /* Make sure that the address is MTE granule aligned. */ 110 + WARN_ON((u64)addr & (MTE_GRANULE_SIZE - 1)); 111 + 112 + tag = 0xF0 | tag; 113 + ptr = (void *)__tag_set(ptr, tag); 114 + 115 + mte_assign_mem_tag_range(ptr, size); 116 + 117 + return ptr; 76 118 } 77 119 78 120 static void update_sctlr_el1_tcf0(u64 tcf0)
+16
arch/arm64/lib/mte.S
··· 149 149 150 150 ret 151 151 SYM_FUNC_END(mte_restore_page_tags) 152 + 153 + /* 154 + * Assign allocation tags for a region of memory based on the pointer tag 155 + * x0 - source pointer 156 + * x1 - size 157 + * 158 + * Note: The address must be non-NULL and MTE_GRANULE_SIZE aligned and 159 + * size must be non-zero and MTE_GRANULE_SIZE aligned. 160 + */ 161 + SYM_FUNC_START(mte_assign_mem_tag_range) 162 + 1: stg x0, [x0] 163 + add x0, x0, #MTE_GRANULE_SIZE 164 + subs x1, x1, #MTE_GRANULE_SIZE 165 + b.gt 1b 166 + ret 167 + SYM_FUNC_END(mte_assign_mem_tag_range)