* [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature
@ 2025-05-07 15:46 Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature Yeoreum Yun
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Yeoreum Yun @ 2025-05-07 15:46 UTC (permalink / raw)
To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
joey.gouly, maz, oliver.upton, frederic, james.morse,
hardevsinh.palaniya, huangxiaojia2, mark.rutland, samuel.holland,
palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
yang, mbenes, joel.granados
Cc: linux-arm-kernel, linux-kernel, Yeoreum Yun
ARMv8.5 based processors introduce the Memory Tagging Extension (MTE) feature.
MTE is built on top of the ARMv8.0 virtual address tagging TBI
(Top Byte Ignore) feature and allows software to access a 4-bit
allocation tag for each 16-byte granule in the physical address space.
A logical tag is derived from bits 59-56 of the virtual
address used for the memory access. A CPU with MTE enabled will compare
the logical tag against the allocation tag and potentially raise an
tag check fault on mismatch, subject to system registers configuration.
Since ARMv8.9, FEAT_MTE_STORE_ONLY can be used to restrict raise of tag
check fault on store operation only.
For this, application can use PR_MTE_STORE_ONLY flag
when it sets the MTE setting with prctl().
This feature omits tag check for fetch/read operation.
So it might be used not only debugging purpose but also be used
by application requiring strong memory safty in normal env.
Patch Sequences
================
Patch #1 adds cpufeature FEAT_MTE_STORE_ONLY
Patch #2 introduce new flag -- PR_MTE_STORE_ONLY
Patch #3 support MTE_STORE_ONLY feature
Patch #4 add HWCAP for MTE_STORE_ONLY
Patch #5 adds mte store-only hwcap test
Patch #6 preparation for adding mte store-only testcase
Patch #7 adds mte store-only testcases
Patch History
================
v3 to v4:
- separate cpufeature and hwcap commit.
- add mte store-only testcases in check_mmap_options
- https://lore.kernel.org/linux-arm-kernel/aApBk8eGA2Eo57fq@e129823.arm.com/
v2 to v3:
- rebase to 6.15-rc1
- https://lore.kernel.org/linux-arm-kernel/20250403174701.74312-1-yeoreum.yun@arm.com/
v1 to v2:
- add doc to elf_hwcaps.rst
- add MTE_STORE_ONLY hwcap test
- https://lore.kernel.org/linux-arm-kernel/20250403142707.26397-1-yeoreum.yun@arm.com/
Note:
This patch based on
https://lore.kernel.org/linux-arm-kernel/20250507095757.1663684-1-yeoreum.yun@arm.com/
Yeoreum Yun (7):
arm64/cpufeature: add MTE_STORE_ONLY feature
prtcl: introduce PR_MTE_STORE_ONLY
arm64/kernel: support store-only mte tag check
arm64/hwcaps: add MTE_STORE_ONLY hwcaps
tools/kselftest: add MTE_STORE_ONLY feature hwcap test
kselftest/arm64/mte: preparation for mte store only test
kselftest/arm64/mte: add MTE_STORE_ONLY testcases
Documentation/arch/arm64/elf_hwcaps.rst | 3 +
arch/arm64/include/asm/hwcap.h | 1 +
arch/arm64/include/asm/processor.h | 2 +
arch/arm64/include/uapi/asm/hwcap.h | 1 +
arch/arm64/kernel/cpufeature.c | 9 ++
arch/arm64/kernel/cpuinfo.c | 1 +
arch/arm64/kernel/mte.c | 11 +-
arch/arm64/kernel/process.c | 6 +-
arch/arm64/tools/cpucaps | 1 +
include/uapi/linux/prctl.h | 2 +
tools/testing/selftests/arm64/abi/hwcap.c | 6 +
.../selftests/arm64/mte/check_buffer_fill.c | 10 +-
.../selftests/arm64/mte/check_child_memory.c | 4 +-
.../arm64/mte/check_hugetlb_options.c | 6 +-
.../selftests/arm64/mte/check_ksm_options.c | 2 +-
.../selftests/arm64/mte/check_mmap_options.c | 116 ++++++++++++------
.../testing/selftests/arm64/mte/check_prctl.c | 25 ++--
.../arm64/mte/check_tags_inclusion.c | 8 +-
.../selftests/arm64/mte/check_user_mem.c | 2 +-
.../selftests/arm64/mte/mte_common_util.c | 14 ++-
.../selftests/arm64/mte/mte_common_util.h | 3 +-
21 files changed, 167 insertions(+), 66 deletions(-)
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature
2025-05-07 15:46 [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
@ 2025-05-07 15:46 ` Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 2/7] prtcl: introduce PR_MTE_STORE_ONLY Yeoreum Yun
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2025-05-07 15:46 UTC (permalink / raw)
To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
joey.gouly, maz, oliver.upton, frederic, james.morse,
hardevsinh.palaniya, huangxiaojia2, mark.rutland, samuel.holland,
palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
yang, mbenes, joel.granados
Cc: linux-arm-kernel, linux-kernel, Yeoreum Yun
Since ARMv8.9, FEAT_MTE_STORE_ONLY can be used to restrict raise of tag
check fault on store operation only.
add MTE_STORE_ONLY feature.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
arch/arm64/kernel/cpufeature.c | 8 ++++++++
arch/arm64/tools/cpucaps | 1 +
2 files changed, 9 insertions(+)
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 183b4b7e3074..de42f890bcd7 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -313,6 +313,7 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr1[] = {
static const struct arm64_ftr_bits ftr_id_aa64pfr2[] = {
ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR2_EL1_FPMR_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR2_EL1_MTEFAR_SHIFT, 4, ID_AA64PFR2_EL1_MTEFAR_NI),
+ ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR2_EL1_MTESTOREONLY_SHIFT, 4, ID_AA64PFR2_EL1_MTESTOREONLY_NI),
ARM64_FTR_END,
};
@@ -2869,6 +2870,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
.matches = has_cpuid_feature,
ARM64_CPUID_FIELDS(ID_AA64PFR2_EL1, MTEFAR, IMP)
},
+ {
+ .desc = "Store Only MTE Tag Check",
+ .capability = ARM64_MTE_STORE_ONLY,
+ .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+ .matches = has_cpuid_feature,
+ ARM64_CPUID_FIELDS(ID_AA64PFR2_EL1, MTESTOREONLY, IMP)
+ },
#endif /* CONFIG_ARM64_MTE */
{
.desc = "RCpc load-acquire (LDAPR)",
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index ef62ea04ba37..282a1dbb8bc9 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -68,6 +68,7 @@ MPAM_HCR
MTE
MTE_ASYMM
MTE_FAR
+MTE_STORE_ONLY
SME
SME_FA64
SME2
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 2/7] prtcl: introduce PR_MTE_STORE_ONLY
2025-05-07 15:46 [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature Yeoreum Yun
@ 2025-05-07 15:46 ` Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 3/7] arm64/kernel: support store-only mte tag check Yeoreum Yun
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2025-05-07 15:46 UTC (permalink / raw)
To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
joey.gouly, maz, oliver.upton, frederic, james.morse,
hardevsinh.palaniya, huangxiaojia2, mark.rutland, samuel.holland,
palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
yang, mbenes, joel.granados
Cc: linux-arm-kernel, linux-kernel, Yeoreum Yun
PR_MTE_STORE_ONLY is used to restrict the MTE tag check for store
opeartion only.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
include/uapi/linux/prctl.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 15c18ef4eb11..83ac566251d8 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -244,6 +244,8 @@ struct prctl_mm_map {
# define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT)
/* Unused; kept only for source compatibility */
# define PR_MTE_TCF_SHIFT 1
+/* MTE tag check store only */
+# define PR_MTE_STORE_ONLY (1UL << 19)
/* RISC-V pointer masking tag length */
# define PR_PMLEN_SHIFT 24
# define PR_PMLEN_MASK (0x7fUL << PR_PMLEN_SHIFT)
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 3/7] arm64/kernel: support store-only mte tag check
2025-05-07 15:46 [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 2/7] prtcl: introduce PR_MTE_STORE_ONLY Yeoreum Yun
@ 2025-05-07 15:46 ` Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 4/7] arm64/hwcaps: add MTE_STORE_ONLY hwcaps Yeoreum Yun
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2025-05-07 15:46 UTC (permalink / raw)
To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
joey.gouly, maz, oliver.upton, frederic, james.morse,
hardevsinh.palaniya, huangxiaojia2, mark.rutland, samuel.holland,
palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
yang, mbenes, joel.granados
Cc: linux-arm-kernel, linux-kernel, Yeoreum Yun
Introduce new flag -- MTE_CTRL_STORE_ONLY used to set store-only tag check.
This flag isn't overridden by prefered tcf flag setting but set together
with prefered setting of way to report tag check fault.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
arch/arm64/include/asm/processor.h | 2 ++
arch/arm64/kernel/mte.c | 11 ++++++++++-
arch/arm64/kernel/process.c | 6 +++++-
3 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 1bf1a3b16e88..61d62bfd5a7b 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -23,6 +23,8 @@
#define MTE_CTRL_TCF_ASYNC (1UL << 17)
#define MTE_CTRL_TCF_ASYMM (1UL << 18)
+#define MTE_CTRL_STORE_ONLY (1UL << 19)
+
#ifndef __ASSEMBLY__
#include <linux/build_bug.h>
diff --git a/arch/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
index 2fbfd27ff5f2..e5e773844889 100644
--- a/arch/arm64/kernel/mte.c
+++ b/arch/arm64/kernel/mte.c
@@ -200,7 +200,7 @@ static void mte_update_sctlr_user(struct task_struct *task)
* program requested values go with what was requested.
*/
resolved_mte_tcf = (mte_ctrl & pref) ? pref : mte_ctrl;
- sctlr &= ~SCTLR_EL1_TCF0_MASK;
+ sctlr &= ~(SCTLR_EL1_TCF0_MASK | SCTLR_EL1_TCSO0_MASK);
/*
* Pick an actual setting. The order in which we check for
* set bits and map into register values determines our
@@ -212,6 +212,10 @@ static void mte_update_sctlr_user(struct task_struct *task)
sctlr |= SYS_FIELD_PREP_ENUM(SCTLR_EL1, TCF0, ASYNC);
else if (resolved_mte_tcf & MTE_CTRL_TCF_SYNC)
sctlr |= SYS_FIELD_PREP_ENUM(SCTLR_EL1, TCF0, SYNC);
+
+ if (mte_ctrl & MTE_CTRL_STORE_ONLY)
+ sctlr |= SYS_FIELD_PREP(SCTLR_EL1, TCSO0, 1);
+
task->thread.sctlr_user = sctlr;
}
@@ -371,6 +375,9 @@ long set_mte_ctrl(struct task_struct *task, unsigned long arg)
(arg & PR_MTE_TCF_SYNC))
mte_ctrl |= MTE_CTRL_TCF_ASYMM;
+ if (arg & PR_MTE_STORE_ONLY)
+ mte_ctrl |= MTE_CTRL_STORE_ONLY;
+
task->thread.mte_ctrl = mte_ctrl;
if (task == current) {
preempt_disable();
@@ -398,6 +405,8 @@ long get_mte_ctrl(struct task_struct *task)
ret |= PR_MTE_TCF_ASYNC;
if (mte_ctrl & MTE_CTRL_TCF_SYNC)
ret |= PR_MTE_TCF_SYNC;
+ if (mte_ctrl & MTE_CTRL_STORE_ONLY)
+ ret |= PR_MTE_STORE_ONLY;
return ret;
}
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 42faebb7b712..cea4a23a15de 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -815,10 +815,14 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
if (is_compat_thread(ti))
return -EINVAL;
- if (system_supports_mte())
+ if (system_supports_mte()) {
valid_mask |= PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC \
| PR_MTE_TAG_MASK;
+ if (cpus_have_cap(ARM64_MTE_STORE_ONLY))
+ valid_mask |= PR_MTE_STORE_ONLY;
+ }
+
if (arg & ~valid_mask)
return -EINVAL;
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 4/7] arm64/hwcaps: add MTE_STORE_ONLY hwcaps
2025-05-07 15:46 [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
` (2 preceding siblings ...)
2025-05-07 15:46 ` [PATCH v4 3/7] arm64/kernel: support store-only mte tag check Yeoreum Yun
@ 2025-05-07 15:46 ` Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test Yeoreum Yun
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2025-05-07 15:46 UTC (permalink / raw)
To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
joey.gouly, maz, oliver.upton, frederic, james.morse,
hardevsinh.palaniya, huangxiaojia2, mark.rutland, samuel.holland,
palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
yang, mbenes, joel.granados
Cc: linux-arm-kernel, linux-kernel, Yeoreum Yun
Since ARMv8.9, FEAT_MTE_STORE_ONLY can be used to restrict raise of tag
check fault on store operation only.
add MTE_STORE_ONLY hwcaps so that user can use this feature.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
Documentation/arch/arm64/elf_hwcaps.rst | 3 +++
arch/arm64/include/asm/hwcap.h | 1 +
arch/arm64/include/uapi/asm/hwcap.h | 1 +
arch/arm64/kernel/cpufeature.c | 1 +
arch/arm64/kernel/cpuinfo.c | 1 +
5 files changed, 7 insertions(+)
diff --git a/Documentation/arch/arm64/elf_hwcaps.rst b/Documentation/arch/arm64/elf_hwcaps.rst
index 358f5af035ff..f58ada4d6cb2 100644
--- a/Documentation/arch/arm64/elf_hwcaps.rst
+++ b/Documentation/arch/arm64/elf_hwcaps.rst
@@ -438,6 +438,9 @@ HWCAP2_POE
HWCAP3_MTE_FAR
Functionality implied by ID_AA64PFR2_EL1.MTEFAR == 0b0001.
+HWCAP3_MTE_STORE_ONLY
+ Functionality implied by ID_AA64PFR2_EL1.MTESTOREONLY == 0b0001.
+
4. Unused AT_HWCAP bits
-----------------------
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 28dd1ac29ecc..13f94c8ddfc0 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -177,6 +177,7 @@
#define __khwcap3_feature(x) (const_ilog2(HWCAP3_ ## x) + 128)
#define KERNEL_HWCAP_MTE_FAR __khwcap3_feature(MTE_FAR)
+#define KERNEL_HWCAP_MTE_STORE_ONLY __khwcap3_feature(MTE_STORE_ONLY)
/*
* This yields a mask that user programs can use to figure out what
diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h
index 7d22527a7975..72c78468b806 100644
--- a/arch/arm64/include/uapi/asm/hwcap.h
+++ b/arch/arm64/include/uapi/asm/hwcap.h
@@ -144,5 +144,6 @@
* HWCAP3 flags - for AT_HWCAP3
*/
#define HWCAP3_MTE_FAR (1UL << 0)
+#define HWCAP3_MTE_STORE_ONLY (1UL << 1)
#endif /* _UAPI__ASM_HWCAP_H */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index de42f890bcd7..a2f25a8bed96 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -3208,6 +3208,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
HWCAP_CAP(ID_AA64PFR1_EL1, MTE, MTE2, CAP_HWCAP, KERNEL_HWCAP_MTE),
HWCAP_CAP(ID_AA64PFR1_EL1, MTE, MTE3, CAP_HWCAP, KERNEL_HWCAP_MTE3),
HWCAP_CAP(ID_AA64PFR2_EL1, MTEFAR, IMP, CAP_HWCAP, KERNEL_HWCAP_MTE_FAR),
+ HWCAP_CAP(ID_AA64PFR2_EL1, MTESTOREONLY, IMP, CAP_HWCAP , KERNEL_HWCAP_MTE_STORE_ONLY),
#endif /* CONFIG_ARM64_MTE */
HWCAP_CAP(ID_AA64MMFR0_EL1, ECV, IMP, CAP_HWCAP, KERNEL_HWCAP_ECV),
HWCAP_CAP(ID_AA64MMFR1_EL1, AFP, IMP, CAP_HWCAP, KERNEL_HWCAP_AFP),
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 058e21295003..37fd9a56b0ce 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -161,6 +161,7 @@ static const char *const hwcap_str[] = {
[KERNEL_HWCAP_SME_STMOP] = "smestmop",
[KERNEL_HWCAP_SME_SMOP4] = "smesmop4",
[KERNEL_HWCAP_MTE_FAR] = "mtefar",
+ [KERNEL_HWCAP_MTE_STORE_ONLY] = "mtestoreonly",
};
#ifdef CONFIG_COMPAT
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test
2025-05-07 15:46 [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
` (3 preceding siblings ...)
2025-05-07 15:46 ` [PATCH v4 4/7] arm64/hwcaps: add MTE_STORE_ONLY hwcaps Yeoreum Yun
@ 2025-05-07 15:46 ` Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 6/7] kselftest/arm64/mte: preparation for mte store only test Yeoreum Yun
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2025-05-07 15:46 UTC (permalink / raw)
To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
joey.gouly, maz, oliver.upton, frederic, james.morse,
hardevsinh.palaniya, huangxiaojia2, mark.rutland, samuel.holland,
palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
yang, mbenes, joel.granados
Cc: linux-arm-kernel, linux-kernel, Yeoreum Yun
add MTE_STORE_ONLY feature hwcap test.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
tools/testing/selftests/arm64/abi/hwcap.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c
index e60bfb798ba2..42b59a994bd0 100644
--- a/tools/testing/selftests/arm64/abi/hwcap.c
+++ b/tools/testing/selftests/arm64/abi/hwcap.c
@@ -1104,6 +1104,12 @@ static const struct hwcap_data {
.hwcap_bit = HWCAP3_MTE_FAR,
.cpuinfo = "mtefar",
},
+ {
+ .name = "MTE_STOREONLY",
+ .at_hwcap = AT_HWCAP3,
+ .hwcap_bit = HWCAP3_MTE_STORE_ONLY,
+ .cpuinfo = "mtestoreonly",
+ },
};
typedef void (*sighandler_fn)(int, siginfo_t *, void *);
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 6/7] kselftest/arm64/mte: preparation for mte store only test
2025-05-07 15:46 [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
` (4 preceding siblings ...)
2025-05-07 15:46 ` [PATCH v4 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test Yeoreum Yun
@ 2025-05-07 15:46 ` Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases Yeoreum Yun
2025-05-19 8:12 ` [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
7 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2025-05-07 15:46 UTC (permalink / raw)
To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
joey.gouly, maz, oliver.upton, frederic, james.morse,
hardevsinh.palaniya, huangxiaojia2, mark.rutland, samuel.holland,
palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
yang, mbenes, joel.granados
Cc: linux-arm-kernel, linux-kernel, Yeoreum Yun
Since ARMv8.9, FEAT_MTE_STORE_ONLY can be used to restrict raise of tag
check fault on store operation only.
This patch is preparation for testing FEAT_MTE_STORE_ONLY
It shouldn't change test result.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
.../selftests/arm64/mte/check_buffer_fill.c | 10 +++++-----
.../selftests/arm64/mte/check_child_memory.c | 4 ++--
.../selftests/arm64/mte/check_hugetlb_options.c | 6 +++---
.../selftests/arm64/mte/check_ksm_options.c | 2 +-
.../selftests/arm64/mte/check_mmap_options.c | 6 +++---
.../selftests/arm64/mte/check_tags_inclusion.c | 8 ++++----
tools/testing/selftests/arm64/mte/check_user_mem.c | 2 +-
.../testing/selftests/arm64/mte/mte_common_util.c | 14 ++++++++++++--
.../testing/selftests/arm64/mte/mte_common_util.h | 3 ++-
9 files changed, 33 insertions(+), 22 deletions(-)
diff --git a/tools/testing/selftests/arm64/mte/check_buffer_fill.c b/tools/testing/selftests/arm64/mte/check_buffer_fill.c
index 5248b5265aa4..ff4e07503349 100644
--- a/tools/testing/selftests/arm64/mte/check_buffer_fill.c
+++ b/tools/testing/selftests/arm64/mte/check_buffer_fill.c
@@ -31,7 +31,7 @@ static int check_buffer_by_byte(int mem_type, int mode)
int i, j, item;
bool err;
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
item = ARRAY_SIZE(sizes);
for (i = 0; i < item; i++) {
@@ -68,7 +68,7 @@ static int check_buffer_underflow_by_byte(int mem_type, int mode,
bool err;
char *und_ptr = NULL;
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
item = ARRAY_SIZE(sizes);
for (i = 0; i < item; i++) {
ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
@@ -164,7 +164,7 @@ static int check_buffer_overflow_by_byte(int mem_type, int mode,
size_t tagged_size, overflow_size;
char *over_ptr = NULL;
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
item = ARRAY_SIZE(sizes);
for (i = 0; i < item; i++) {
ptr = (char *)mte_allocate_memory_tag_range(sizes[i], mem_type, 0,
@@ -337,7 +337,7 @@ static int check_buffer_by_block(int mem_type, int mode)
{
int i, item, result = KSFT_PASS;
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
item = ARRAY_SIZE(sizes);
cur_mte_cxt.fault_valid = false;
for (i = 0; i < item; i++) {
@@ -368,7 +368,7 @@ static int check_memory_initial_tags(int mem_type, int mode, int mapping)
int run, fd;
int total = ARRAY_SIZE(sizes);
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
for (run = 0; run < total; run++) {
/* check initial tags for anonymous mmap */
ptr = (char *)mte_allocate_memory(sizes[run], mem_type, mapping, false);
diff --git a/tools/testing/selftests/arm64/mte/check_child_memory.c b/tools/testing/selftests/arm64/mte/check_child_memory.c
index b97ea3981c21..5e97ee792e4d 100644
--- a/tools/testing/selftests/arm64/mte/check_child_memory.c
+++ b/tools/testing/selftests/arm64/mte/check_child_memory.c
@@ -88,7 +88,7 @@ static int check_child_memory_mapping(int mem_type, int mode, int mapping)
int item = ARRAY_SIZE(sizes);
item = ARRAY_SIZE(sizes);
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
for (run = 0; run < item; run++) {
ptr = (char *)mte_allocate_memory_tag_range(sizes[run], mem_type, mapping,
UNDERFLOW, OVERFLOW);
@@ -109,7 +109,7 @@ static int check_child_file_mapping(int mem_type, int mode, int mapping)
int run, fd, map_size, result = KSFT_PASS;
int total = ARRAY_SIZE(sizes);
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
for (run = 0; run < total; run++) {
fd = create_temp_file();
if (fd == -1)
diff --git a/tools/testing/selftests/arm64/mte/check_hugetlb_options.c b/tools/testing/selftests/arm64/mte/check_hugetlb_options.c
index 4e644a606394..aad1234c7e0f 100644
--- a/tools/testing/selftests/arm64/mte/check_hugetlb_options.c
+++ b/tools/testing/selftests/arm64/mte/check_hugetlb_options.c
@@ -151,7 +151,7 @@ static int check_hugetlb_memory_mapping(int mem_type, int mode, int mapping, int
map_size = default_huge_page_size();
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
map_ptr = (char *)mte_allocate_memory(map_size, mem_type, mapping, false);
if (check_allocated_memory(map_ptr, map_size, mem_type, false) != KSFT_PASS)
return KSFT_FAIL;
@@ -180,7 +180,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping)
unsigned long map_size;
prot_flag = PROT_READ | PROT_WRITE;
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
map_size = default_huge_page_size();
map_ptr = (char *)mte_allocate_memory_tag_range(map_size, mem_type, mapping,
0, 0);
@@ -210,7 +210,7 @@ static int check_child_hugetlb_memory_mapping(int mem_type, int mode, int mappin
map_size = default_huge_page_size();
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
ptr = (char *)mte_allocate_memory_tag_range(map_size, mem_type, mapping,
0, 0);
if (check_allocated_memory_range(ptr, map_size, mem_type,
diff --git a/tools/testing/selftests/arm64/mte/check_ksm_options.c b/tools/testing/selftests/arm64/mte/check_ksm_options.c
index afea4e381862..0cf5faef1724 100644
--- a/tools/testing/selftests/arm64/mte/check_ksm_options.c
+++ b/tools/testing/selftests/arm64/mte/check_ksm_options.c
@@ -106,7 +106,7 @@ static int check_madvise_options(int mem_type, int mode, int mapping)
return err;
}
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
ptr = mte_allocate_memory(TEST_UNIT * page_sz, mem_type, mapping, true);
if (check_allocated_memory(ptr, TEST_UNIT * page_sz, mem_type, false) != KSFT_PASS)
return KSFT_FAIL;
diff --git a/tools/testing/selftests/arm64/mte/check_mmap_options.c b/tools/testing/selftests/arm64/mte/check_mmap_options.c
index 4f26617c8e69..d4193377b406 100644
--- a/tools/testing/selftests/arm64/mte/check_mmap_options.c
+++ b/tools/testing/selftests/arm64/mte/check_mmap_options.c
@@ -81,7 +81,7 @@ static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping, i
int run, result, map_size;
int item = ARRAY_SIZE(sizes);
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
for (run = 0; run < item; run++) {
map_size = sizes[run] + OVERFLOW + UNDERFLOW;
map_ptr = (char *)mte_allocate_memory(map_size, mem_type, mapping, false);
@@ -113,7 +113,7 @@ static int check_file_memory_mapping(int mem_type, int mode, int mapping, int ta
int total = ARRAY_SIZE(sizes);
int result = KSFT_PASS;
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
for (run = 0; run < total; run++) {
fd = create_temp_file();
if (fd == -1)
@@ -152,7 +152,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping, int at
int total = ARRAY_SIZE(sizes);
prot_flag = PROT_READ | PROT_WRITE;
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
for (run = 0; run < total; run++) {
map_size = sizes[run] + OVERFLOW + UNDERFLOW;
ptr = (char *)mte_allocate_memory_tag_range(sizes[run], mem_type, mapping,
diff --git a/tools/testing/selftests/arm64/mte/check_tags_inclusion.c b/tools/testing/selftests/arm64/mte/check_tags_inclusion.c
index b96296ab9870..4b764f2a8185 100644
--- a/tools/testing/selftests/arm64/mte/check_tags_inclusion.c
+++ b/tools/testing/selftests/arm64/mte/check_tags_inclusion.c
@@ -57,7 +57,7 @@ static int check_single_included_tags(int mem_type, int mode)
return KSFT_FAIL;
for (tag = 0; (tag < MT_TAG_COUNT) && (result == KSFT_PASS); tag++) {
- ret = mte_switch_mode(mode, MT_INCLUDE_VALID_TAG(tag));
+ ret = mte_switch_mode(mode, MT_INCLUDE_VALID_TAG(tag), false);
if (ret != 0)
result = KSFT_FAIL;
/* Try to catch a excluded tag by a number of tries. */
@@ -91,7 +91,7 @@ static int check_multiple_included_tags(int mem_type, int mode)
for (tag = 0; (tag < MT_TAG_COUNT - 1) && (result == KSFT_PASS); tag++) {
excl_mask |= 1 << tag;
- mte_switch_mode(mode, MT_INCLUDE_VALID_TAGS(excl_mask));
+ mte_switch_mode(mode, MT_INCLUDE_VALID_TAGS(excl_mask), false);
/* Try to catch a excluded tag by a number of tries. */
for (run = 0; (run < RUNS) && (result == KSFT_PASS); run++) {
ptr = mte_insert_tags(ptr, BUFFER_SIZE);
@@ -120,7 +120,7 @@ static int check_all_included_tags(int mem_type, int mode)
mem_type, false) != KSFT_PASS)
return KSFT_FAIL;
- ret = mte_switch_mode(mode, MT_INCLUDE_TAG_MASK);
+ ret = mte_switch_mode(mode, MT_INCLUDE_TAG_MASK, false);
if (ret != 0)
return KSFT_FAIL;
/* Try to catch a excluded tag by a number of tries. */
@@ -145,7 +145,7 @@ static int check_none_included_tags(int mem_type, int mode)
if (check_allocated_memory(ptr, BUFFER_SIZE, mem_type, false) != KSFT_PASS)
return KSFT_FAIL;
- ret = mte_switch_mode(mode, MT_EXCLUDE_TAG_MASK);
+ ret = mte_switch_mode(mode, MT_EXCLUDE_TAG_MASK, false);
if (ret != 0)
return KSFT_FAIL;
/* Try to catch a excluded tag by a number of tries. */
diff --git a/tools/testing/selftests/arm64/mte/check_user_mem.c b/tools/testing/selftests/arm64/mte/check_user_mem.c
index d1d14aaaba16..fb7936c4e097 100644
--- a/tools/testing/selftests/arm64/mte/check_user_mem.c
+++ b/tools/testing/selftests/arm64/mte/check_user_mem.c
@@ -44,7 +44,7 @@ static int check_usermem_access_fault(int mem_type, int mode, int mapping,
err = KSFT_PASS;
len = 2 * page_sz;
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
fd = create_temp_file();
if (fd == -1)
return KSFT_FAIL;
diff --git a/tools/testing/selftests/arm64/mte/mte_common_util.c b/tools/testing/selftests/arm64/mte/mte_common_util.c
index 47e5f940b804..d0da7ee82696 100644
--- a/tools/testing/selftests/arm64/mte/mte_common_util.c
+++ b/tools/testing/selftests/arm64/mte/mte_common_util.c
@@ -28,8 +28,10 @@
struct mte_fault_cxt cur_mte_cxt;
bool mtefar_support;
+bool mtestonly_support;
static unsigned int mte_cur_mode;
static unsigned int mte_cur_pstate_tco;
+static bool mte_cur_stonly;
void mte_default_handler(int signum, siginfo_t *si, void *uc)
{
@@ -316,7 +318,7 @@ void mte_initialize_current_context(int mode, uintptr_t ptr, ssize_t range)
cur_mte_cxt.trig_si_code = 0;
}
-int mte_switch_mode(int mte_option, unsigned long incl_mask)
+int mte_switch_mode(int mte_option, unsigned long incl_mask, bool stonly)
{
unsigned long en = 0;
@@ -348,6 +350,9 @@ int mte_switch_mode(int mte_option, unsigned long incl_mask)
break;
}
+ if (mtestonly_support && stonly)
+ en |= PR_MTE_STORE_ONLY;
+
en |= (incl_mask << PR_MTE_TAG_SHIFT);
/* Enable address tagging ABI, mte error reporting mode and tag inclusion mask. */
if (prctl(PR_SET_TAGGED_ADDR_CTRL, en, 0, 0, 0) != 0) {
@@ -370,6 +375,9 @@ int mte_default_setup(void)
if (hwcaps3 & HWCAP3_MTE_FAR)
mtefar_support = true;
+ if (hwcaps3 & HWCAP3_MTE_STORE_ONLY)
+ mtestonly_support = true;
+
/* Get current mte mode */
ret = prctl(PR_GET_TAGGED_ADDR_CTRL, en, 0, 0, 0);
if (ret < 0) {
@@ -383,6 +391,8 @@ int mte_default_setup(void)
else if (ret & PR_MTE_TCF_NONE)
mte_cur_mode = MTE_NONE_ERR;
+ mte_cur_stonly = (ret & PR_MTE_STORE_ONLY) ? true : false;
+
mte_cur_pstate_tco = mte_get_pstate_tco();
/* Disable PSTATE.TCO */
mte_disable_pstate_tco();
@@ -391,7 +401,7 @@ int mte_default_setup(void)
void mte_restore_setup(void)
{
- mte_switch_mode(mte_cur_mode, MTE_ALLOW_NON_ZERO_TAG);
+ mte_switch_mode(mte_cur_mode, MTE_ALLOW_NON_ZERO_TAG, mte_cur_stonly);
if (mte_cur_pstate_tco == MT_PSTATE_TCO_EN)
mte_enable_pstate_tco();
else if (mte_cur_pstate_tco == MT_PSTATE_TCO_DIS)
diff --git a/tools/testing/selftests/arm64/mte/mte_common_util.h b/tools/testing/selftests/arm64/mte/mte_common_util.h
index 7dbb5e1046ae..567d299b393c 100644
--- a/tools/testing/selftests/arm64/mte/mte_common_util.h
+++ b/tools/testing/selftests/arm64/mte/mte_common_util.h
@@ -40,6 +40,7 @@ struct mte_fault_cxt {
extern struct mte_fault_cxt cur_mte_cxt;
extern bool mtefar_support;
+extern bool mtestonly_support;
/* MTE utility functions */
void mte_default_handler(int signum, siginfo_t *si, void *uc);
@@ -62,7 +63,7 @@ void *mte_insert_atag(void *ptr);
void *mte_clear_atag(void *ptr);
int mte_default_setup(void);
void mte_restore_setup(void);
-int mte_switch_mode(int mte_option, unsigned long incl_mask);
+int mte_switch_mode(int mte_option, unsigned long incl_mask, bool stonly);
void mte_initialize_current_context(int mode, uintptr_t ptr, ssize_t range);
/* Common utility functions */
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases
2025-05-07 15:46 [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
` (5 preceding siblings ...)
2025-05-07 15:46 ` [PATCH v4 6/7] kselftest/arm64/mte: preparation for mte store only test Yeoreum Yun
@ 2025-05-07 15:46 ` Yeoreum Yun
2025-05-19 8:12 ` [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
7 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2025-05-07 15:46 UTC (permalink / raw)
To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
joey.gouly, maz, oliver.upton, frederic, james.morse,
hardevsinh.palaniya, huangxiaojia2, mark.rutland, samuel.holland,
palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
yang, mbenes, joel.granados
Cc: linux-arm-kernel, linux-kernel, Yeoreum Yun
Since ARMv8.9, FEAT_MTE_STORE_ONLY can be used to restrict raise of tag
check fault on store operation only.
Adds new test cases using MTE_STORE_ONLY feature.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
.../selftests/arm64/mte/check_mmap_options.c | 114 ++++++++++++------
.../testing/selftests/arm64/mte/check_prctl.c | 25 ++--
2 files changed, 95 insertions(+), 44 deletions(-)
diff --git a/tools/testing/selftests/arm64/mte/check_mmap_options.c b/tools/testing/selftests/arm64/mte/check_mmap_options.c
index d4193377b406..b9db3e05565e 100644
--- a/tools/testing/selftests/arm64/mte/check_mmap_options.c
+++ b/tools/testing/selftests/arm64/mte/check_mmap_options.c
@@ -34,15 +34,19 @@
#define ATAG_TEST_ON 1
#define ATAG_TEST_OFF 0
+#define TAG_OP_ALL 0
+#define TAG_OP_STONLY 1
+
static size_t page_size;
static int sizes[] = {
1, 537, 989, 1269, MT_GRANULE_SIZE - 1, MT_GRANULE_SIZE,
/* page size - 1*/ 0, /* page_size */ 0, /* page size + 1 */ 0
};
-static int check_mte_memory(char *ptr, int size, int mode, int tag_check, int atag_test)
+static int check_mte_memory(char *ptr, int size, int mode,
+ int tag_check,int atag_test, int tag_op)
{
- int err;
+ char buf[MT_GRANULE_SIZE];
if (!mtefar_support && atag_test == ATAG_TEST_ON)
return KSFT_SKIP;
@@ -72,16 +76,34 @@ static int check_mte_memory(char *ptr, int size, int mode, int tag_check, int at
if (cur_mte_cxt.fault_valid == true && tag_check == TAG_CHECK_OFF)
return KSFT_FAIL;
+ if (tag_op == TAG_OP_STONLY) {
+ mte_initialize_current_context(mode, (uintptr_t)ptr, -UNDERFLOW);
+ memcpy(buf, ptr - UNDERFLOW, MT_GRANULE_SIZE);
+ mte_wait_after_trig();
+ if (cur_mte_cxt.fault_valid == true)
+ return KSFT_FAIL;
+
+ mte_initialize_current_context(mode, (uintptr_t)ptr, size + OVERFLOW);
+ memcpy(buf, ptr + size, MT_GRANULE_SIZE);
+ mte_wait_after_trig();
+ if (cur_mte_cxt.fault_valid == true)
+ return KSFT_FAIL;
+ }
+
return KSFT_PASS;
}
-static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping, int tag_check, int atag_test)
+static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping,
+ int tag_check, int atag_test, int tag_op)
{
char *ptr, *map_ptr;
int run, result, map_size;
int item = ARRAY_SIZE(sizes);
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
+ if (tag_op == TAG_OP_STONLY && !mtestonly_support)
+ return KSFT_SKIP;
+
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, tag_op);
for (run = 0; run < item; run++) {
map_size = sizes[run] + OVERFLOW + UNDERFLOW;
map_ptr = (char *)mte_allocate_memory(map_size, mem_type, mapping, false);
@@ -97,7 +119,7 @@ static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping, i
munmap((void *)map_ptr, map_size);
return KSFT_FAIL;
}
- result = check_mte_memory(ptr, sizes[run], mode, tag_check, atag_test);
+ result = check_mte_memory(ptr, sizes[run], mode, tag_check, atag_test, tag_op);
mte_clear_tags((void *)ptr, sizes[run]);
mte_free_memory((void *)map_ptr, map_size, mem_type, false);
if (result != KSFT_SKIP)
@@ -106,14 +128,18 @@ static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping, i
return KSFT_PASS;
}
-static int check_file_memory_mapping(int mem_type, int mode, int mapping, int tag_check, int atag_test)
+static int check_file_memory_mapping(int mem_type, int mode, int mapping,
+ int tag_check, int atag_test, int tag_op)
{
char *ptr, *map_ptr;
int run, fd, map_size;
int total = ARRAY_SIZE(sizes);
int result = KSFT_PASS;
- mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
+ if (tag_op == TAG_OP_STONLY && !mtestonly_support)
+ return KSFT_SKIP;
+
+ mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, tag_op);
for (run = 0; run < total; run++) {
fd = create_temp_file();
if (fd == -1)
@@ -135,7 +161,7 @@ static int check_file_memory_mapping(int mem_type, int mode, int mapping, int ta
close(fd);
return KSFT_FAIL;
}
- result = check_mte_memory(ptr, sizes[run], mode, tag_check, atag_test);
+ result = check_mte_memory(ptr, sizes[run], mode, tag_check, atag_test, tag_op);
mte_clear_tags((void *)ptr, sizes[run]);
munmap((void *)map_ptr, map_size);
close(fd);
@@ -168,7 +194,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping, int at
ksft_print_msg("FAIL: mprotect not ignoring clear PROT_MTE property\n");
return KSFT_FAIL;
}
- result = check_mte_memory(ptr, sizes[run], mode, TAG_CHECK_ON, atag_test);
+ result = check_mte_memory(ptr, sizes[run], mode, TAG_CHECK_ON, atag_test, TAG_OP_ALL);
mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW);
if (result != KSFT_PASS)
return result;
@@ -192,7 +218,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping, int at
close(fd);
return KSFT_FAIL;
}
- result = check_mte_memory(ptr, sizes[run], mode, TAG_CHECK_ON, atag_test);
+ result = check_mte_memory(ptr, sizes[run], mode, TAG_CHECK_ON, atag_test, TAG_OP_ALL);
mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW);
close(fd);
if (result != KSFT_PASS)
@@ -202,7 +228,7 @@ static int check_clear_prot_mte_flag(int mem_type, int mode, int mapping, int at
}
const char *format_test_name(int check_type, int mem_type, int sync,
- int mapping, int tag_check, int atag_test)
+ int mapping, int tag_check, int atag_test, int tag_op)
{
static char test_name[TEST_NAME_MAX];
const char* check_type_str;
@@ -211,6 +237,7 @@ const char *format_test_name(int check_type, int mem_type, int sync,
const char* mapping_str;
const char* tag_check_str;
const char *atag_test_str;
+ const char *tag_op_str;
switch (check_type) {
case CHECK_ANON_MEM:
@@ -290,10 +317,22 @@ const char *format_test_name(int check_type, int mem_type, int sync,
break;
}
+ switch (tag_op) {
+ case TAG_OP_ALL:
+ tag_op_str = "";
+ break;
+ case TAG_OP_STONLY:
+ tag_op_str = " / store-only";
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
snprintf(test_name, TEST_NAME_MAX,
- "Check %s with %s mapping, %s mode, %s memory and %s (%s)\n",
+ "Check %s with %s mapping, %s mode, %s memory and %s (%s%s)\n",
check_type_str, mapping_str, sync_str, mem_type_str,
- tag_check_str, atag_test_str);
+ tag_check_str, atag_test_str, tag_op_str);
return test_name;
}
@@ -307,7 +346,8 @@ int main(int argc, char *argv[])
int mte_sync[] = { MTE_SYNC_ERR, MTE_ASYNC_ERR };
int mapping[] = { MAP_PRIVATE, MAP_SHARED };
int atag_test[] = { ATAG_TEST_OFF, ATAG_TEST_ON };
- int c, mt, s, m, a;
+ int tag_ops[] = { TAG_OP_ALL, TAG_OP_STONLY };
+ int c, mt, s, m, a, o;
err = mte_default_setup();
if (err)
@@ -322,7 +362,7 @@ int main(int argc, char *argv[])
sizes[item - 1] = page_size + 1;
/* Set test plan */
- ksft_set_plan(44);
+ ksft_set_plan(76);
for (a = 0; a < ARRAY_SIZE(atag_test); a++) {
/* Register signal handlers */
@@ -331,38 +371,40 @@ int main(int argc, char *argv[])
mte_enable_pstate_tco();
- evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a]),
- format_test_name(CHECK_ANON_MEM, USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a]));
+ evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a], TAG_OP_ALL),
+ format_test_name(CHECK_ANON_MEM, USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a], TAG_OP_ALL));
- evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a]),
- format_test_name(CHECK_FILE_MEM, USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a]));
+ evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a], TAG_OP_ALL),
+ format_test_name(CHECK_FILE_MEM, USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a], TAG_OP_ALL));
mte_disable_pstate_tco();
- evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a]),
- format_test_name(CHECK_ANON_MEM, USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a]));
- evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a]),
- format_test_name(CHECK_FILE_MEM, USE_MPROTECT, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a]));
-
- for (c = 0 ; c < ARRAY_SIZE(check_type); c++) {
- for (s = 0; s < ARRAY_SIZE(mte_sync); s++) {
- for (m = 0; m < ARRAY_SIZE(mapping); m++) {
- for (mt = 0; mt < ARRAY_SIZE(mem_type); mt++) {
- if (check_type[c] == CHECK_ANON_MEM)
- evaluate_test(check_anonymous_memory_mapping(mem_type[mt], mte_sync[s], mapping[m], TAG_CHECK_ON, atag_test[a]),
- format_test_name(CHECK_ANON_MEM, mem_type[mt], mte_sync[s], mapping[m], TAG_CHECK_ON, atag_test[a]));
- else
- evaluate_test(check_file_memory_mapping(mem_type[mt], mte_sync[s], mapping[m], TAG_CHECK_ON, atag_test[a]),
- format_test_name(CHECK_FILE_MEM, mem_type[mt], mte_sync[s], mapping[m], TAG_CHECK_ON, atag_test[a]));
+ evaluate_test(check_anonymous_memory_mapping(USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a], TAG_OP_ALL),
+ format_test_name(CHECK_ANON_MEM, USE_MMAP, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a], TAG_OP_ALL));
+ evaluate_test(check_file_memory_mapping(USE_MPROTECT, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a], TAG_OP_ALL),
+ format_test_name(CHECK_FILE_MEM, USE_MPROTECT, MTE_NONE_ERR, MAP_PRIVATE, TAG_CHECK_OFF, atag_test[a], TAG_OP_ALL));
+
+ for (o = 0; o < ARRAY_SIZE(tag_ops); o++) {
+ for (c = 0 ; c < ARRAY_SIZE(check_type); c++) {
+ for (s = 0; s < ARRAY_SIZE(mte_sync); s++) {
+ for (m = 0; m < ARRAY_SIZE(mapping); m++) {
+ for (mt = 0; mt < ARRAY_SIZE(mem_type); mt++) {
+ if (check_type[c] == CHECK_ANON_MEM)
+ evaluate_test(check_anonymous_memory_mapping(mem_type[mt], mte_sync[s], mapping[m], TAG_CHECK_ON, atag_test[a], tag_ops[o]),
+ format_test_name(CHECK_ANON_MEM, mem_type[mt], mte_sync[s], mapping[m], TAG_CHECK_ON, atag_test[a], tag_ops[o]));
+ else
+ evaluate_test(check_file_memory_mapping(mem_type[mt], mte_sync[s], mapping[m], TAG_CHECK_ON, atag_test[a], tag_ops[o]),
+ format_test_name(CHECK_FILE_MEM, mem_type[mt], mte_sync[s], mapping[m], TAG_CHECK_ON, atag_test[a], tag_ops[o]));
+ }
}
}
}
}
evaluate_test(check_clear_prot_mte_flag(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, atag_test[a]),
- format_test_name(CHECK_CLEAR_PROT_MTE, USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON, atag_test[a]));
+ format_test_name(CHECK_CLEAR_PROT_MTE, USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON, atag_test[a], TAG_OP_ALL));
evaluate_test(check_clear_prot_mte_flag(USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, atag_test[a]),
- format_test_name(CHECK_CLEAR_PROT_MTE, USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON, atag_test[a]));
+ format_test_name(CHECK_CLEAR_PROT_MTE, USE_MPROTECT, MTE_SYNC_ERR, MAP_PRIVATE, TAG_CHECK_ON, atag_test[a], TAG_OP_ALL));
}
mte_restore_setup();
diff --git a/tools/testing/selftests/arm64/mte/check_prctl.c b/tools/testing/selftests/arm64/mte/check_prctl.c
index 4c89e9538ca0..83fa20cc6072 100644
--- a/tools/testing/selftests/arm64/mte/check_prctl.c
+++ b/tools/testing/selftests/arm64/mte/check_prctl.c
@@ -60,7 +60,7 @@ void check_basic_read(void)
/*
* Attempt to set a specified combination of modes.
*/
-void set_mode_test(const char *name, int hwcap2, int mask)
+void set_mode_test(const char *name, int hwcap2, int hwcap3, int mask)
{
int ret;
@@ -69,6 +69,11 @@ void set_mode_test(const char *name, int hwcap2, int mask)
return;
}
+ if ((getauxval(AT_HWCAP3) & hwcap3) != hwcap3) {
+ ksft_test_result_skip("%s\n", name);
+ return;
+ }
+
ret = set_tagged_addr_ctrl(mask);
if (ret < 0) {
ksft_test_result_fail("%s\n", name);
@@ -81,7 +86,7 @@ void set_mode_test(const char *name, int hwcap2, int mask)
return;
}
- if ((ret & PR_MTE_TCF_MASK) == mask) {
+ if ((ret & (PR_MTE_TCF_MASK | PR_MTE_STORE_ONLY)) == mask) {
ksft_test_result_pass("%s\n", name);
} else {
ksft_print_msg("Got %x, expected %x\n",
@@ -93,12 +98,16 @@ void set_mode_test(const char *name, int hwcap2, int mask)
struct mte_mode {
int mask;
int hwcap2;
+ int hwcap3;
const char *name;
} mte_modes[] = {
- { PR_MTE_TCF_NONE, 0, "NONE" },
- { PR_MTE_TCF_SYNC, HWCAP2_MTE, "SYNC" },
- { PR_MTE_TCF_ASYNC, HWCAP2_MTE, "ASYNC" },
- { PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC, HWCAP2_MTE, "SYNC+ASYNC" },
+ { PR_MTE_TCF_NONE, 0, 0, "NONE" },
+ { PR_MTE_TCF_SYNC, HWCAP2_MTE, 0, "SYNC" },
+ { PR_MTE_TCF_ASYNC, HWCAP2_MTE, 0, "ASYNC" },
+ { PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC, HWCAP2_MTE, 0, "SYNC+ASYNC" },
+ { PR_MTE_TCF_SYNC | PR_MTE_STORE_ONLY, HWCAP2_MTE, HWCAP3_MTE_STORE_ONLY, "SYNC+STONLY" },
+ { PR_MTE_TCF_ASYNC | PR_MTE_STORE_ONLY, HWCAP2_MTE, HWCAP3_MTE_STORE_ONLY, "ASYNC+STONLY" },
+ { PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC | PR_MTE_STORE_ONLY, HWCAP2_MTE, HWCAP3_MTE_STORE_ONLY, "SYNC+ASYNC+STONLY" },
};
int main(void)
@@ -106,11 +115,11 @@ int main(void)
int i;
ksft_print_header();
- ksft_set_plan(5);
+ ksft_set_plan(8);
check_basic_read();
for (i = 0; i < ARRAY_SIZE(mte_modes); i++)
- set_mode_test(mte_modes[i].name, mte_modes[i].hwcap2,
+ set_mode_test(mte_modes[i].name, mte_modes[i].hwcap2, mte_modes[i].hwcap3,
mte_modes[i].mask);
ksft_print_cnts();
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature
2025-05-07 15:46 [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
` (6 preceding siblings ...)
2025-05-07 15:46 ` [PATCH v4 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases Yeoreum Yun
@ 2025-05-19 8:12 ` Yeoreum Yun
7 siblings, 0 replies; 9+ messages in thread
From: Yeoreum Yun @ 2025-05-19 8:12 UTC (permalink / raw)
To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
joey.gouly, maz, oliver.upton, frederic, james.morse,
hardevsinh.palaniya, huangxiaojia2, mark.rutland, samuel.holland,
palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
yang, mbenes, joel.granados
Cc: linux-arm-kernel, linux-kernel
Gentle ping in case of forgoten...
> ARMv8.5 based processors introduce the Memory Tagging Extension (MTE) feature.
> MTE is built on top of the ARMv8.0 virtual address tagging TBI
> (Top Byte Ignore) feature and allows software to access a 4-bit
> allocation tag for each 16-byte granule in the physical address space.
> A logical tag is derived from bits 59-56 of the virtual
> address used for the memory access. A CPU with MTE enabled will compare
> the logical tag against the allocation tag and potentially raise an
> tag check fault on mismatch, subject to system registers configuration.
>
> Since ARMv8.9, FEAT_MTE_STORE_ONLY can be used to restrict raise of tag
> check fault on store operation only.
> For this, application can use PR_MTE_STORE_ONLY flag
> when it sets the MTE setting with prctl().
>
> This feature omits tag check for fetch/read operation.
> So it might be used not only debugging purpose but also be used
> by application requiring strong memory safty in normal env.
>
> Patch Sequences
> ================
>
> Patch #1 adds cpufeature FEAT_MTE_STORE_ONLY
>
> Patch #2 introduce new flag -- PR_MTE_STORE_ONLY
>
> Patch #3 support MTE_STORE_ONLY feature
>
> Patch #4 add HWCAP for MTE_STORE_ONLY
>
> Patch #5 adds mte store-only hwcap test
>
> Patch #6 preparation for adding mte store-only testcase
>
> Patch #7 adds mte store-only testcases
>
> Patch History
> ================
>
> v3 to v4:
> - separate cpufeature and hwcap commit.
> - add mte store-only testcases in check_mmap_options
> - https://lore.kernel.org/linux-arm-kernel/aApBk8eGA2Eo57fq@e129823.arm.com/
>
> v2 to v3:
> - rebase to 6.15-rc1
> - https://lore.kernel.org/linux-arm-kernel/20250403174701.74312-1-yeoreum.yun@arm.com/
>
> v1 to v2:
> - add doc to elf_hwcaps.rst
> - add MTE_STORE_ONLY hwcap test
> - https://lore.kernel.org/linux-arm-kernel/20250403142707.26397-1-yeoreum.yun@arm.com/
>
> Note:
> This patch based on
> https://lore.kernel.org/linux-arm-kernel/20250507095757.1663684-1-yeoreum.yun@arm.com/
>
> Yeoreum Yun (7):
> arm64/cpufeature: add MTE_STORE_ONLY feature
> prtcl: introduce PR_MTE_STORE_ONLY
> arm64/kernel: support store-only mte tag check
> arm64/hwcaps: add MTE_STORE_ONLY hwcaps
> tools/kselftest: add MTE_STORE_ONLY feature hwcap test
> kselftest/arm64/mte: preparation for mte store only test
> kselftest/arm64/mte: add MTE_STORE_ONLY testcases
>
> Documentation/arch/arm64/elf_hwcaps.rst | 3 +
> arch/arm64/include/asm/hwcap.h | 1 +
> arch/arm64/include/asm/processor.h | 2 +
> arch/arm64/include/uapi/asm/hwcap.h | 1 +
> arch/arm64/kernel/cpufeature.c | 9 ++
> arch/arm64/kernel/cpuinfo.c | 1 +
> arch/arm64/kernel/mte.c | 11 +-
> arch/arm64/kernel/process.c | 6 +-
> arch/arm64/tools/cpucaps | 1 +
> include/uapi/linux/prctl.h | 2 +
> tools/testing/selftests/arm64/abi/hwcap.c | 6 +
> .../selftests/arm64/mte/check_buffer_fill.c | 10 +-
> .../selftests/arm64/mte/check_child_memory.c | 4 +-
> .../arm64/mte/check_hugetlb_options.c | 6 +-
> .../selftests/arm64/mte/check_ksm_options.c | 2 +-
> .../selftests/arm64/mte/check_mmap_options.c | 116 ++++++++++++------
> .../testing/selftests/arm64/mte/check_prctl.c | 25 ++--
> .../arm64/mte/check_tags_inclusion.c | 8 +-
> .../selftests/arm64/mte/check_user_mem.c | 2 +-
> .../selftests/arm64/mte/mte_common_util.c | 14 ++-
> .../selftests/arm64/mte/mte_common_util.h | 3 +-
> 21 files changed, 167 insertions(+), 66 deletions(-)
>
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>
--
Sincerely,
Yeoreum Yun
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-05-19 8:16 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-07 15:46 [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 2/7] prtcl: introduce PR_MTE_STORE_ONLY Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 3/7] arm64/kernel: support store-only mte tag check Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 4/7] arm64/hwcaps: add MTE_STORE_ONLY hwcaps Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 6/7] kselftest/arm64/mte: preparation for mte store only test Yeoreum Yun
2025-05-07 15:46 ` [PATCH v4 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases Yeoreum Yun
2025-05-19 8:12 ` [PATCH v4 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.