From f1d94ca9e16df455f69c28779154b4f5d1088a6f Mon Sep 17 00:00:00 2001 From: wangmingrong1 Date: Fri, 29 Nov 2024 10:33:12 +0800 Subject: [PATCH] arm64/mte: Add support for arm64 mte For details, please refer to the kernel's introduction to this at "https://docs.kernel.org/arch/arm64/memory-tagging-extension.html" and Android's introduction to this at "https://source.android.com/docs/security/test/memory-safety/arm-mte" Of course, there is also the following detailed principle introduction https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/Arm_Memory_Tagging_Extension_Whitepaper.pdf The modification of this patch is only to merge the simplest MTE function support. In the future, the MTE function will be integrated into the kernel to a greater extent, for example, hardware MTE Kasan will be supported in the future. Signed-off-by: wangmingrong1 --- arch/arm64/Kconfig | 17 ++++- arch/arm64/src/Toolchain.defs | 20 ++++- arch/arm64/src/common/CMakeLists.txt | 4 + arch/arm64/src/common/Make.defs | 4 + arch/arm64/src/common/arm64_arch.h | 25 +++++++ arch/arm64/src/common/arm64_boot.c | 5 ++ arch/arm64/src/common/arm64_mmu.c | 6 +- arch/arm64/src/common/arm64_mmu.h | 18 ++++- arch/arm64/src/common/arm64_mte.c | 107 +++++++++++++++++++++++++++ arch/arm64/src/qemu/qemu_boot.c | 2 + 10 files changed, 201 insertions(+), 7 deletions(-) create mode 100644 arch/arm64/src/common/arm64_mte.c diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1807a7d68b5f0..d5eae21baa2ae 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -108,7 +108,7 @@ config ARCH_CHIP_ZYNQ_MPSOC select ARM64_HAVE_PSCI ---help--- XilinX ZYNQ MPSOC - + config ARCH_CHIP_ARM64_CUSTOM bool "Custom ARM64 chip" select ARCH_CHIP_CUSTOM @@ -127,6 +127,21 @@ config ARCH_ARMV8R default n select ARCH_SINGLE_SECURITY_STATE +config ARCH_AS_HAS_ARMV8_5 + bool "Support ARMv8.5 assembly" + depends on ARCH_ARMV8A + ---help--- + Support ARMv8.5 assembly instruction set + +menu "ARMv8.5 architectural features" + depends on ARCH_AS_HAS_ARMV8_5 + +config ARM64_MTE + bool "Memory Tagging Extension support" + default y + +endmenu # "ARMv8.5 architectural features" + config ARCH_SINGLE_SECURITY_STATE bool "ARM Single Security State Support" default n diff --git a/arch/arm64/src/Toolchain.defs b/arch/arm64/src/Toolchain.defs index bf482ffc7edd6..5a40d2613c6f2 100644 --- a/arch/arm64/src/Toolchain.defs +++ b/arch/arm64/src/Toolchain.defs @@ -30,6 +30,22 @@ # reliable code generation. # +ifeq ($(CONFIG_ARCH_ARMV8A),y) + ifeq ($(CONFIG_ARCH_AS_HAS_ARMV8_5),y) + OPTION_MARCH = -march=armv8.5-a + else + OPTION_MARCH = -march=armv8-a + endif + ifeq ($(CONFIG_ARM64_MTE),y) + OPTION_MARCH_FEATURE = +memtag + endif + ARCHCPUFLAGS += $(OPTION_MARCH)$(OPTION_MARCH_FEATURE) +endif + +ifeq ($(CONFIG_ARCH_ARMV8R),y) + ARCHCPUFLAGS += -march=armv8-r +endif + ifeq ($(CONFIG_ARCH_CORTEX_A53),y) ARCHCPUFLAGS += -mcpu=cortex-a53 else ifeq ($(CONFIG_ARCH_CORTEX_A55),y) @@ -40,10 +56,6 @@ else ifeq ($(CONFIG_ARCH_CORTEX_A72),y) ARCHCPUFLAGS += -mcpu=cortex-a72 else ifeq ($(CONFIG_ARCH_CORTEX_R82),y) ARCHCPUFLAGS += -mcpu=cortex-r82 -else ifeq ($(CONFIG_ARCH_ARMV8A),y) - ARCHCPUFLAGS += -march=armv8-a -else ifeq ($(CONFIG_ARCH_ARMV8R),y) - ARCHCPUFLAGS += -march=armv8-r endif ifeq ($(CONFIG_DEBUG_CUSTOMOPT),y) diff --git a/arch/arm64/src/common/CMakeLists.txt b/arch/arm64/src/common/CMakeLists.txt index ad9b1d07259e1..5567166a25ec1 100644 --- a/arch/arm64/src/common/CMakeLists.txt +++ b/arch/arm64/src/common/CMakeLists.txt @@ -61,6 +61,10 @@ if(CONFIG_ARCH_HAVE_MMU) list(APPEND SRCS arm64_mmu.c) endif() +if(CONFIG_ARM64_MTE) + list(APPEND SRCS arm64_mte.c) +endif() + if(CONFIG_ARCH_HAVE_MPU) list(APPEND SRCS arm64_mpu.c) endif() diff --git a/arch/arm64/src/common/Make.defs b/arch/arm64/src/common/Make.defs index c22af8617ea8e..bc5707604df12 100644 --- a/arch/arm64/src/common/Make.defs +++ b/arch/arm64/src/common/Make.defs @@ -74,6 +74,10 @@ ifeq ($(CONFIG_ARCH_HAVE_MMU),y) CMN_CSRCS += arm64_mmu.c endif +ifeq ($(CONFIG_ARM64_MTE),y) +CMN_CSRCS += arm64_mte.c +endif + ifeq ($(CONFIG_ARCH_HAVE_MPU),y) CMN_CSRCS += arm64_mpu.c common/arm64_mpu.c_CFLAGS += -fno-sanitize=kernel-address diff --git a/arch/arm64/src/common/arm64_arch.h b/arch/arm64/src/common/arm64_arch.h index 5bb8eaeb7bc34..610b141b8e1ed 100644 --- a/arch/arm64/src/common/arm64_arch.h +++ b/arch/arm64/src/common/arm64_arch.h @@ -96,6 +96,18 @@ #define SCTLR_SA_BIT BIT(3) #define SCTLR_I_BIT BIT(12) +/* Controls the impact of tag check faults + * due to loads and stores in EL0 EL1. + */ + +#define SCTLR_TCF0_BIT BIT(38) +#define SCTLR_TCF1_BIT BIT(40) + +/* Controlling EL0 EL1 access to assigned tags */ + +#define SCTLR_ATA0_BIT BIT(42) +#define SCTLR_ATA_BIT BIT(43) + #define ACTLR_AUX_BIT BIT(9) #define ACTLR_CLPORTS_BIT BIT(8) #define ACTLR_CLPMU_BIT BIT(7) @@ -135,6 +147,12 @@ #define SPSR_MODE_EL3H (0xd) #define SPSR_MODE_MASK (0xf) +#define RGSR_EL1_TAG_MASK 0xfUL +#define RGSR_EL1_SEED_SHIFT 8 +#define RGSR_EL1_SEED_MASK 0xffffUL + +#define TTBR_CNP_BIT BIT(0) + /* CurrentEL: Current Exception Level */ #define MODE_EL_SHIFT (0x2) @@ -243,6 +261,7 @@ #define HCR_IMO_BIT BIT(4) #define HCR_AMO_BIT BIT(5) #define HCR_RW_BIT BIT(31) +#define HCR_ATA_BIT BIT(56) /* CNTHCTL_EL2 bits definitions */ @@ -485,6 +504,12 @@ uint64_t arm64_get_mpid(int cpu); int arm64_get_cpuid(uint64_t mpid); #endif +#ifdef CONFIG_ARM64_MTE +void arm64_enable_mte(void); +#else +#define arm64_enable_mte +#endif + #endif /* __ASSEMBLY__ */ #endif /* ___ARCH_ARM64_SRC_COMMON_ARM64_ARCH_H */ diff --git a/arch/arm64/src/common/arm64_boot.c b/arch/arm64/src/common/arm64_boot.c index be482650250a5..16053821249b0 100644 --- a/arch/arm64/src/common/arm64_boot.c +++ b/arch/arm64/src/common/arm64_boot.c @@ -137,6 +137,11 @@ void arm64_boot_el2_init(void) reg = read_sysreg(hcr_el2); reg |= HCR_RW_BIT; /* EL1 Execution state is AArch64 */ + +#ifdef CONFIG_ARM64_MTE + reg |= HCR_ATA_BIT; +#endif + write_sysreg(reg, hcr_el2); reg = 0U; /* RES0 */ diff --git a/arch/arm64/src/common/arm64_mmu.c b/arch/arm64/src/common/arm64_mmu.c index 953f139cf4273..a9033337e8406 100644 --- a/arch/arm64/src/common/arm64_mmu.c +++ b/arch/arm64/src/common/arm64_mmu.c @@ -159,6 +159,10 @@ #define TCR_KASAN_SW_FLAGS 0 #endif +#ifdef CONFIG_ARM64_MTE +#define TCR_MTE_FLAGS (TCR_TCMA1 | TCR_TBI0 | TCR_TBI1 | TCR_ASID_8) +#endif + /**************************************************************************** * Private Data ****************************************************************************/ @@ -262,7 +266,7 @@ static uint64_t get_tcr(int el) */ tcr |= TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | - TCR_IRGN_WBWA | TCR_KASAN_SW_FLAGS; + TCR_IRGN_WBWA | TCR_KASAN_SW_FLAGS | TCR_MTE_FLAGS; return tcr; } diff --git a/arch/arm64/src/common/arm64_mmu.h b/arch/arm64/src/common/arm64_mmu.h index ce5f191a86905..57f8e0bf78286 100644 --- a/arch/arm64/src/common/arm64_mmu.h +++ b/arch/arm64/src/common/arm64_mmu.h @@ -49,11 +49,17 @@ #define MT_NORMAL_NC 3U #define MT_NORMAL 4U +#ifdef CONFIG_ARM64_MTE +#define MT_NORMAL_VAL 0xf0UL +#else +#define MT_NORMAL_VAL 0xffUL +#endif + #define MEMORY_ATTRIBUTES ((0x00 << (MT_DEVICE_NGNRNE * 8)) | \ (0x04 << (MT_DEVICE_NGNRE * 8)) | \ (0x0c << (MT_DEVICE_GRE * 8)) | \ (0x44 << (MT_NORMAL_NC * 8)) | \ - (0xffUL << (MT_NORMAL * 8))) + (MT_NORMAL_VAL << (MT_NORMAL * 8))) /* More flags from user's perpective are supported using remaining bits * of "attrs" field, i.e. attrs[31:3], underlying code will take care @@ -155,6 +161,16 @@ #define TCR_TBI0 (1ULL << 37) #define TCR_TBI1 (1ULL << 38) +/* TCMA1 (bit [58]) controls whether memory accesses + * in the address range [59:55] = 0b11111 are unchecked accesses. + * + * TCMA0 (bit [57]) controls whether memory accesses + * in the address range [59:55] = 0b00000 are unchecked accesses. + */ + +#define TCR_TCMA0 (1ULL << 57) +#define TCR_TCMA1 (1ULL << 58) + #define TCR_PS_BITS_4GB 0x0ULL #define TCR_PS_BITS_64GB 0x1ULL #define TCR_PS_BITS_1TB 0x2ULL diff --git a/arch/arm64/src/common/arm64_mte.c b/arch/arm64/src/common/arm64_mte.c new file mode 100644 index 0000000000000..6a2230f90f085 --- /dev/null +++ b/arch/arm64/src/common/arm64_mte.c @@ -0,0 +1,107 @@ +/**************************************************************************** + * arch/arm64/src/common/arm64_mte.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "arm64_arch.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define GCR_EL1_VAL 0x10001 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int arm64_mte_is_support(void) +{ + int supported; + __asm__ volatile ( + "mrs %0, ID_AA64PFR1_EL1\n" + "ubfx %0, %0, #8, #3\n" + : "=r" (supported) + : + : "memory" + ); + return supported != 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void arm64_enable_mte(void) +{ + uint64_t val; + + if (!arm64_mte_is_support()) + { + return; + } + + /* CnP must be enabled only after the MAIR_EL1 register has been set + * up. Inconsistent MAIR_EL1 between CPUs sharing the same TLB may + * lead to the wrong memory type being used for a brief window during + * CPU power-up. + * + * CnP is not a boot feature so MTE gets enabled before CnP, but let's + * make sure that is the case. + */ + + assert(!(read_sysreg(ttbr0_el1) & TTBR_CNP_BIT)); + assert(!(read_sysreg(ttbr1_el1) & TTBR_CNP_BIT)); + + val = read_sysreg(sctlr_el1); + val |= SCTLR_ATA_BIT | SCTLR_TCF1_BIT; + write_sysreg(val, sctlr_el1); + + write_sysreg(GCR_EL1_VAL, gcr_el1); + + /* If GCR_EL1.RRND=1 is implemented the same way as RRND=0, then + * RGSR_EL1.SEED must be non-zero for IRG to produce + * pseudorandom numbers. As RGSR_EL1 is UNKNOWN out of reset, we + * must initialize it. + */ + + val = (read_sysreg(CNTVCT_EL0) & RGSR_EL1_SEED_MASK) << + RGSR_EL1_SEED_SHIFT; + + if (0 == val) + { + val = 1 << RGSR_EL1_SEED_SHIFT; + } + + write_sysreg(val, rgsr_el1); + + /* clear any pending tag check faults in TFSR*_EL1 */ + + write_sysreg(0, tfsr_el1); + write_sysreg(0, tfsre0_el1); +} diff --git a/arch/arm64/src/qemu/qemu_boot.c b/arch/arm64/src/qemu/qemu_boot.c index dd05165dbb667..9c05128aa3190 100644 --- a/arch/arm64/src/qemu/qemu_boot.c +++ b/arch/arm64/src/qemu/qemu_boot.c @@ -159,6 +159,8 @@ void arm64_chip_boot(void) arm64_mmu_init(true); + arm64_enable_mte(); + #ifdef CONFIG_DEVICE_TREE fdt_register((const char *)0x40000000); #endif