linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/7] support FEAT_MTE_STORE_ONLY feature
@ 2025-06-11  9:47 Yeoreum Yun
  2025-06-11  9:47 ` [PATCH v5 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature Yeoreum Yun
                   ` (6 more replies)
  0 siblings, 7 replies; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11  9:47 UTC (permalink / raw)
  To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
	joey.gouly, maz, oliver.upton, frederic, hardevsinh.palaniya,
	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
in runtime 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
================
v4 to v5:
  - rebase to v6.16-rc1
  - refactor the check_mmap_options for STORE_ONLY testcases.
  - https://lore.kernel.org/linux-arm-kernel/20250507154654.1937588-1-yeoreum.yun@arm.com/

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/all/20250611094107.928457-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  | 361 +++++++++++++++++-
 .../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, 437 insertions(+), 41 deletions(-)

--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v5 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature
  2025-06-11  9:47 [PATCH v5 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
@ 2025-06-11  9:47 ` Yeoreum Yun
  2025-06-11 14:14   ` Mark Brown
  2025-06-11  9:47 ` [PATCH v5 2/7] prtcl: introduce PR_MTE_STORE_ONLY Yeoreum Yun
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11  9:47 UTC (permalink / raw)
  To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
	joey.gouly, maz, oliver.upton, frederic, hardevsinh.palaniya,
	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 8a5284c733b7..fdc48aa1f0e2 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -321,6 +321,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,
 };
 
@@ -2882,6 +2883,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 fe8f4f8ce95c..b96cb6d6bcaa 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -69,6 +69,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] 17+ messages in thread

* [PATCH v5 2/7] prtcl: introduce PR_MTE_STORE_ONLY
  2025-06-11  9:47 [PATCH v5 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
  2025-06-11  9:47 ` [PATCH v5 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature Yeoreum Yun
@ 2025-06-11  9:47 ` Yeoreum Yun
  2025-06-11 14:14   ` Mark Brown
  2025-06-11  9:47 ` [PATCH v5 3/7] arm64/kernel: support store-only mte tag check Yeoreum Yun
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11  9:47 UTC (permalink / raw)
  To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
	joey.gouly, maz, oliver.upton, frederic, hardevsinh.palaniya,
	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 43dec6eed559..f6fb137c407f 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] 17+ messages in thread

* [PATCH v5 3/7] arm64/kernel: support store-only mte tag check
  2025-06-11  9:47 [PATCH v5 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
  2025-06-11  9:47 ` [PATCH v5 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature Yeoreum Yun
  2025-06-11  9:47 ` [PATCH v5 2/7] prtcl: introduce PR_MTE_STORE_ONLY Yeoreum Yun
@ 2025-06-11  9:47 ` Yeoreum Yun
  2025-06-11 13:19   ` Mark Brown
  2025-06-11  9:47 ` [PATCH v5 4/7] arm64/hwcaps: add MTE_STORE_ONLY hwcaps Yeoreum Yun
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11  9:47 UTC (permalink / raw)
  To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
	joey.gouly, maz, oliver.upton, frederic, hardevsinh.palaniya,
	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 a5ca15daeb8a..fc49f2b3ded1 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -849,10 +849,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] 17+ messages in thread

* [PATCH v5 4/7] arm64/hwcaps: add MTE_STORE_ONLY hwcaps
  2025-06-11  9:47 [PATCH v5 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
                   ` (2 preceding siblings ...)
  2025-06-11  9:47 ` [PATCH v5 3/7] arm64/kernel: support store-only mte tag check Yeoreum Yun
@ 2025-06-11  9:47 ` Yeoreum Yun
  2025-06-11  9:48 ` [PATCH v5 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test Yeoreum Yun
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11  9:47 UTC (permalink / raw)
  To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
	joey.gouly, maz, oliver.upton, frederic, hardevsinh.palaniya,
	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 fdc48aa1f0e2..b4204fa743f0 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -3228,6 +3228,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 e552cb305641..ba834909a28b 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] 17+ messages in thread

* [PATCH v5 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test
  2025-06-11  9:47 [PATCH v5 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
                   ` (3 preceding siblings ...)
  2025-06-11  9:47 ` [PATCH v5 4/7] arm64/hwcaps: add MTE_STORE_ONLY hwcaps Yeoreum Yun
@ 2025-06-11  9:48 ` Yeoreum Yun
  2025-06-11 12:46   ` Mark Brown
  2025-06-11  9:48 ` [PATCH v5 6/7] kselftest/arm64/mte: preparation for mte store only test Yeoreum Yun
  2025-06-11  9:48 ` [PATCH v5 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases Yeoreum Yun
  6 siblings, 1 reply; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11  9:48 UTC (permalink / raw)
  To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
	joey.gouly, maz, oliver.upton, frederic, hardevsinh.palaniya,
	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>
---
 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] 17+ messages in thread

* [PATCH v5 6/7] kselftest/arm64/mte: preparation for mte store only test
  2025-06-11  9:47 [PATCH v5 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
                   ` (4 preceding siblings ...)
  2025-06-11  9:48 ` [PATCH v5 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test Yeoreum Yun
@ 2025-06-11  9:48 ` Yeoreum Yun
  2025-06-11 13:10   ` Mark Brown
  2025-06-11  9:48 ` [PATCH v5 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases Yeoreum Yun
  6 siblings, 1 reply; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11  9:48 UTC (permalink / raw)
  To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
	joey.gouly, maz, oliver.upton, frederic, hardevsinh.palaniya,
	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 046fa909de86..1a77dd8f59c0 100644
--- a/tools/testing/selftests/arm64/mte/check_mmap_options.c
+++ b/tools/testing/selftests/arm64/mte/check_mmap_options.c
@@ -90,7 +90,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);
@@ -122,7 +122,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)
@@ -161,7 +161,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 ca5bb9e6472b..a0cc81b76a80 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 045e4ad2f018..250d671329a5 100644
--- a/tools/testing/selftests/arm64/mte/mte_common_util.h
+++ b/tools/testing/selftests/arm64/mte/mte_common_util.h
@@ -38,6 +38,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);
@@ -60,7 +61,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] 17+ messages in thread

* [PATCH v5 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases
  2025-06-11  9:47 [PATCH v5 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
                   ` (5 preceding siblings ...)
  2025-06-11  9:48 ` [PATCH v5 6/7] kselftest/arm64/mte: preparation for mte store only test Yeoreum Yun
@ 2025-06-11  9:48 ` Yeoreum Yun
  2025-06-11 13:02   ` Mark Brown
  6 siblings, 1 reply; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11  9:48 UTC (permalink / raw)
  To: catalin.marinas, pcc, will, broonie, anshuman.khandual,
	joey.gouly, maz, oliver.upton, frederic, hardevsinh.palaniya,
	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  | 359 +++++++++++++++++-
 .../testing/selftests/arm64/mte/check_prctl.c |  25 +-
 2 files changed, 365 insertions(+), 19 deletions(-)

diff --git a/tools/testing/selftests/arm64/mte/check_mmap_options.c b/tools/testing/selftests/arm64/mte/check_mmap_options.c
index 1a77dd8f59c0..b8e96cccc605 100644
--- a/tools/testing/selftests/arm64/mte/check_mmap_options.c
+++ b/tools/testing/selftests/arm64/mte/check_mmap_options.c
@@ -35,6 +35,11 @@ enum mte_mem_check_type {
 	CHECK_CLEAR_PROT_MTE = 2,
 };
 
+enum mte_tag_op_type {
+	TAG_OP_ALL = 0,
+	TAG_OP_STONLY = 1,
+};
+
 struct check_mmap_testcase {
 	int check_type;
 	int mem_type;
@@ -42,17 +47,24 @@ struct check_mmap_testcase {
 	int mapping;
 	int tag_check;
 	int atag_check;
+	int tag_op;
 	bool enable_tco;
 };
 
+#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_check)
+static int check_mte_memory(char *ptr, int size, int mode,
+		int tag_check,int atag_check, int tag_op)
 {
+	char buf[MT_GRANULE_SIZE];
+
 	if (!mtefar_support && atag_check == ATAG_CHECK_ON)
 		return KSFT_SKIP;
 
@@ -81,16 +93,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_check)
+static int check_anonymous_memory_mapping(int mem_type, int mode, int mapping,
+		int tag_check, int atag_check, 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);
@@ -106,7 +136,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_check);
+		result = check_mte_memory(ptr, sizes[run], mode, tag_check, atag_check, tag_op);
 		mte_clear_tags((void *)ptr, sizes[run]);
 		mte_free_memory((void *)map_ptr, map_size, mem_type, false);
 		if (result != KSFT_SKIP)
@@ -115,14 +145,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_check)
+static int check_file_memory_mapping(int mem_type, int mode, int mapping,
+		int tag_check, int atag_check, 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)
@@ -144,7 +178,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_check);
+		result = check_mte_memory(ptr, sizes[run], mode, tag_check, atag_check, tag_op);
 		mte_clear_tags((void *)ptr, sizes[run]);
 		munmap((void *)map_ptr, map_size);
 		close(fd);
@@ -177,7 +211,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_check);
+		result = check_mte_memory(ptr, sizes[run], mode, TAG_CHECK_ON, atag_check, TAG_OP_ALL);
 		mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW);
 		if (result != KSFT_PASS)
 			return KSFT_FAIL;
@@ -201,7 +235,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_check);
+		result = check_mte_memory(ptr, sizes[run], mode, TAG_CHECK_ON, atag_check, TAG_OP_ALL);
 		mte_free_memory_tag_range((void *)ptr, sizes[run], mem_type, UNDERFLOW, OVERFLOW);
 		close(fd);
 		if (result != KSFT_PASS)
@@ -219,6 +253,7 @@ const char *format_test_name(struct check_mmap_testcase *tc)
 	const char *mapping_str;
 	const char *tag_check_str;
 	const char *atag_check_str;
+	const char *tag_op_str;
 
 	switch (tc->check_type) {
 	case CHECK_ANON_MEM:
@@ -303,6 +338,23 @@ const char *format_test_name(struct check_mmap_testcase *tc)
 	         check_type_str, mapping_str, sync_str, mem_type_str,
 	         tag_check_str, atag_check_str);
 
+	switch (tc->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%s)\n",
+	         check_type_str, mapping_str, sync_str, mem_type_str,
+	         tag_check_str, atag_check_str, tag_op_str);
+
 	return test_name;
 }
 
@@ -318,6 +370,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_OFF,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = true,
 		},
 		{
@@ -327,6 +380,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_OFF,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = true,
 		},
 		{
@@ -336,6 +390,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_OFF,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -345,6 +400,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_OFF,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -354,6 +410,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -363,6 +420,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -372,6 +430,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -381,6 +440,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -390,6 +450,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -399,6 +460,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -408,6 +470,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -417,6 +480,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -426,6 +490,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -435,6 +500,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -444,6 +510,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -453,6 +520,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -462,6 +530,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -471,6 +540,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -480,6 +550,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -489,6 +560,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -498,6 +570,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -507,6 +580,257 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_ALL,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_ASYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_ASYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_ASYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_ASYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_ANON_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_ASYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_SYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_ASYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_ASYNC_ERR,
+			.mapping = MAP_PRIVATE,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MMAP,
+			.mte_sync = MTE_ASYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
+			.enable_tco = false,
+		},
+		{
+			.check_type = CHECK_FILE_MEM,
+			.mem_type = USE_MPROTECT,
+			.mte_sync = MTE_ASYNC_ERR,
+			.mapping = MAP_SHARED,
+			.tag_check = TAG_CHECK_ON,
+			.atag_check = ATAG_CHECK_OFF,
+			.tag_op = TAG_OP_STONLY,
 			.enable_tco = false,
 		},
 		{
@@ -516,6 +840,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_STONLY,
 			.enable_tco = false,
 		},
 		{
@@ -525,6 +850,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_STONLY,
 			.enable_tco = false,
 		},
 		{
@@ -534,6 +860,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_STONLY,
 			.enable_tco = false,
 		},
 		{
@@ -543,6 +870,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_STONLY,
 			.enable_tco = false,
 		},
 		{
@@ -552,6 +880,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_STONLY,
 			.enable_tco = false,
 		},
 		{
@@ -561,6 +890,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_STONLY,
 			.enable_tco = false,
 		},
 		{
@@ -570,6 +900,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_STONLY,
 			.enable_tco = false,
 		},
 		{
@@ -579,6 +910,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_SHARED,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_STONLY,
 			.enable_tco = false,
 		},
 		{
@@ -588,6 +920,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_STONLY,
 			.enable_tco = false,
 		},
 		{
@@ -597,6 +930,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 		{
@@ -606,6 +940,7 @@ int main(int argc, char *argv[])
 			.mapping = MAP_PRIVATE,
 			.tag_check = TAG_CHECK_ON,
 			.atag_check = ATAG_CHECK_ON,
+			.tag_op = TAG_OP_ALL,
 			.enable_tco = false,
 		},
 	};
@@ -643,7 +978,8 @@ int main(int argc, char *argv[])
 								     test_cases[i].mte_sync,
 								     test_cases[i].mapping,
 								     test_cases[i].tag_check,
-								     test_cases[i].atag_check),
+								     test_cases[i].atag_check,
+								     test_cases[i].tag_op),
 				      format_test_name(&test_cases[i]));
 			break;
 		case CHECK_FILE_MEM:
@@ -651,7 +987,8 @@ int main(int argc, char *argv[])
 							        test_cases[i].mte_sync,
 							        test_cases[i].mapping,
 							        test_cases[i].tag_check,
-							        test_cases[i].atag_check),
+							        test_cases[i].atag_check,
+								test_cases[i].tag_op),
 				      format_test_name(&test_cases[i]));
 			break;
 		case CHECK_CLEAR_PROT_MTE:
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] 17+ messages in thread

* Re: [PATCH v5 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test
  2025-06-11  9:48 ` [PATCH v5 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test Yeoreum Yun
@ 2025-06-11 12:46   ` Mark Brown
  2025-06-11 14:09     ` Yeoreum Yun
  0 siblings, 1 reply; 17+ messages in thread
From: Mark Brown @ 2025-06-11 12:46 UTC (permalink / raw)
  To: Yeoreum Yun
  Cc: catalin.marinas, pcc, will, anshuman.khandual, joey.gouly, maz,
	oliver.upton, frederic, hardevsinh.palaniya, samuel.holland,
	palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
	yang, mbenes, joel.granados, linux-arm-kernel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 203 bytes --]

On Wed, Jun 11, 2025 at 10:48:00AM +0100, Yeoreum Yun wrote:
> add MTE_STORE_ONLY feature hwcap test.

Subject line doesn't match the usual style, otherwise

Reviewed-by: Mark Brown <broonie@kernel.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v5 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases
  2025-06-11  9:48 ` [PATCH v5 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases Yeoreum Yun
@ 2025-06-11 13:02   ` Mark Brown
  2025-06-11 14:11     ` Yeoreum Yun
  0 siblings, 1 reply; 17+ messages in thread
From: Mark Brown @ 2025-06-11 13:02 UTC (permalink / raw)
  To: Yeoreum Yun
  Cc: catalin.marinas, pcc, will, anshuman.khandual, joey.gouly, maz,
	oliver.upton, frederic, hardevsinh.palaniya, samuel.holland,
	palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
	yang, mbenes, joel.granados, linux-arm-kernel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 858 bytes --]

On Wed, Jun 11, 2025 at 10:48:02AM +0100, Yeoreum Yun wrote:

> @@ -144,7 +178,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_check);
> +		result = check_mte_memory(ptr, sizes[run], mode, tag_check, atag_check, tag_op);
>  		mte_clear_tags((void *)ptr, sizes[run]);
>  		munmap((void *)map_ptr, map_size);
>  		close(fd);

check_file_memory_mapping() looks like it also has the issue from the
other series with skips being upgraded to fails, looks like there's more
instances.

> @@ -106,11 +115,11 @@ int main(void)
>  	int i;
>  
>  	ksft_print_header();
> -	ksft_set_plan(5);
> +	ksft_set_plan(8);
>  

This should probably have been ARRAY_SIZE() to start off with, sorry.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v5 6/7] kselftest/arm64/mte: preparation for mte store only test
  2025-06-11  9:48 ` [PATCH v5 6/7] kselftest/arm64/mte: preparation for mte store only test Yeoreum Yun
@ 2025-06-11 13:10   ` Mark Brown
  2025-06-11 14:12     ` Yeoreum Yun
  0 siblings, 1 reply; 17+ messages in thread
From: Mark Brown @ 2025-06-11 13:10 UTC (permalink / raw)
  To: Yeoreum Yun
  Cc: catalin.marinas, pcc, will, anshuman.khandual, joey.gouly, maz,
	oliver.upton, frederic, hardevsinh.palaniya, samuel.holland,
	palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
	yang, mbenes, joel.granados, linux-arm-kernel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 767 bytes --]

On Wed, Jun 11, 2025 at 10:48:01AM +0100, Yeoreum Yun wrote:
> 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.

Not verified that that's the case but from inspection:

Reviewed-by: Mark Brown <broonie@kernel.org>

> -	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
> +	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
>  	item = ARRAY_SIZE(sizes);

I was going to say on the other series that the boolean flags are kind
of awkward from a readability point of view, but equally it doesn't feel
worth it to make these arguments enums so I'll just mention it but it's
fine either way.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v5 3/7] arm64/kernel: support store-only mte tag check
  2025-06-11  9:47 ` [PATCH v5 3/7] arm64/kernel: support store-only mte tag check Yeoreum Yun
@ 2025-06-11 13:19   ` Mark Brown
  0 siblings, 0 replies; 17+ messages in thread
From: Mark Brown @ 2025-06-11 13:19 UTC (permalink / raw)
  To: Yeoreum Yun
  Cc: catalin.marinas, pcc, will, anshuman.khandual, joey.gouly, maz,
	oliver.upton, frederic, hardevsinh.palaniya, samuel.holland,
	palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
	yang, mbenes, joel.granados, linux-arm-kernel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 821 bytes --]

On Wed, Jun 11, 2025 at 10:47:58AM +0100, Yeoreum Yun wrote:

> 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.

There was a concern when adding asymmetric support that when adding new
prctl() bits might cause issues when libraries linked into a program
don't know about the new bits and miss enabling/disabling them.  That
doesn't seem such an issue here since unlike with asymmetric mode store
only mode doesn't turn MTE on or off entirely, it's more an
optimisation.  There's some possibility that something could rely on
only stores faulting but I'm struggling to think of a real use case.
Assuming that's OK:

Reviewed-by: Mark Brown <broonie@kernel.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v5 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test
  2025-06-11 12:46   ` Mark Brown
@ 2025-06-11 14:09     ` Yeoreum Yun
  0 siblings, 0 replies; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11 14:09 UTC (permalink / raw)
  To: Mark Brown
  Cc: catalin.marinas, pcc, will, anshuman.khandual, joey.gouly, maz,
	oliver.upton, frederic, hardevsinh.palaniya, samuel.holland,
	palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
	yang, mbenes, joel.granados, linux-arm-kernel, linux-kernel

Hi Mark,
>
> Subject line doesn't match the usual style, otherwise
> Reviewed-by: Mark Brown <broonie@kernel.org>

Thank. I'll change the subject format.


--
Sincerely,
Yeoreum Yun

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v5 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases
  2025-06-11 13:02   ` Mark Brown
@ 2025-06-11 14:11     ` Yeoreum Yun
  0 siblings, 0 replies; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11 14:11 UTC (permalink / raw)
  To: Mark Brown
  Cc: catalin.marinas, pcc, will, anshuman.khandual, joey.gouly, maz,
	oliver.upton, frederic, hardevsinh.palaniya, samuel.holland,
	palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
	yang, mbenes, joel.granados, linux-arm-kernel, linux-kernel

Hi Mark,

> On Wed, Jun 11, 2025 at 10:48:02AM +0100, Yeoreum Yun wrote:
>
> > @@ -144,7 +178,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_check);
> > +		result = check_mte_memory(ptr, sizes[run], mode, tag_check, atag_check, tag_op);
> >  		mte_clear_tags((void *)ptr, sizes[run]);
> >  		munmap((void *)map_ptr, map_size);
> >  		close(fd);
>
> check_file_memory_mapping() looks like it also has the issue from the
> other series with skips being upgraded to fails, looks like there's more
> instances.

Thanks. I've fixed this in
  - https://lore.kernel.org/all/20250611135818.31070-10-yeoreum.yun@arm.com/

> > @@ -106,11 +115,11 @@ int main(void)
> >  	int i;
> >
> >  	ksft_print_header();
> > -	ksft_set_plan(5);
> > +	ksft_set_plan(8);
> >
>
> This should probably have been ARRAY_SIZE() to start off with, sorry.

Okay. I'll fix this.


--
Sincerely,
Yeoreum Yun

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v5 6/7] kselftest/arm64/mte: preparation for mte store only test
  2025-06-11 13:10   ` Mark Brown
@ 2025-06-11 14:12     ` Yeoreum Yun
  0 siblings, 0 replies; 17+ messages in thread
From: Yeoreum Yun @ 2025-06-11 14:12 UTC (permalink / raw)
  To: Mark Brown
  Cc: catalin.marinas, pcc, will, anshuman.khandual, joey.gouly, maz,
	oliver.upton, frederic, hardevsinh.palaniya, samuel.holland,
	palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
	yang, mbenes, joel.granados, linux-arm-kernel, linux-kernel

Hi Mark,

> On Wed, Jun 11, 2025 at 10:48:01AM +0100, Yeoreum Yun wrote:
> > 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.
>
> Not verified that that's the case but from inspection:
>
> Reviewed-by: Mark Brown <broonie@kernel.org>

Thanks ;)

> > -	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);
> > +	mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG, false);
> >  	item = ARRAY_SIZE(sizes);
>
> I was going to say on the other series that the boolean flags are kind
> of awkward from a readability point of view, but equally it doesn't feel
> worth it to make these arguments enums so I'll just mention it but it's
> fine either way.

Thanks. later I'll use enum first.

--
Sincerely,
Yeoreum Yun

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v5 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature
  2025-06-11  9:47 ` [PATCH v5 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature Yeoreum Yun
@ 2025-06-11 14:14   ` Mark Brown
  0 siblings, 0 replies; 17+ messages in thread
From: Mark Brown @ 2025-06-11 14:14 UTC (permalink / raw)
  To: Yeoreum Yun
  Cc: catalin.marinas, pcc, will, anshuman.khandual, joey.gouly, maz,
	oliver.upton, frederic, hardevsinh.palaniya, samuel.holland,
	palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
	yang, mbenes, joel.granados, linux-arm-kernel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 260 bytes --]

On Wed, Jun 11, 2025 at 10:47:56AM +0100, Yeoreum Yun wrote:
> 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.

Reviewed-by: Mark Brown <broonie@kernel.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v5 2/7] prtcl: introduce PR_MTE_STORE_ONLY
  2025-06-11  9:47 ` [PATCH v5 2/7] prtcl: introduce PR_MTE_STORE_ONLY Yeoreum Yun
@ 2025-06-11 14:14   ` Mark Brown
  0 siblings, 0 replies; 17+ messages in thread
From: Mark Brown @ 2025-06-11 14:14 UTC (permalink / raw)
  To: Yeoreum Yun
  Cc: catalin.marinas, pcc, will, anshuman.khandual, joey.gouly, maz,
	oliver.upton, frederic, hardevsinh.palaniya, samuel.holland,
	palmer, charlie, thiago.bauermann, bgray, tglx, puranjay, david,
	yang, mbenes, joel.granados, linux-arm-kernel, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 191 bytes --]

On Wed, Jun 11, 2025 at 10:47:57AM +0100, Yeoreum Yun wrote:
> PR_MTE_STORE_ONLY is used to restrict the MTE tag check for store
> opeartion only.

Tested-by: Mark Brown <broonie@kernel.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2025-06-11 14:14 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-11  9:47 [PATCH v5 0/7] support FEAT_MTE_STORE_ONLY feature Yeoreum Yun
2025-06-11  9:47 ` [PATCH v5 1/7] arm64/cpufeature: add MTE_STORE_ONLY feature Yeoreum Yun
2025-06-11 14:14   ` Mark Brown
2025-06-11  9:47 ` [PATCH v5 2/7] prtcl: introduce PR_MTE_STORE_ONLY Yeoreum Yun
2025-06-11 14:14   ` Mark Brown
2025-06-11  9:47 ` [PATCH v5 3/7] arm64/kernel: support store-only mte tag check Yeoreum Yun
2025-06-11 13:19   ` Mark Brown
2025-06-11  9:47 ` [PATCH v5 4/7] arm64/hwcaps: add MTE_STORE_ONLY hwcaps Yeoreum Yun
2025-06-11  9:48 ` [PATCH v5 5/7] tools/kselftest: add MTE_STORE_ONLY feature hwcap test Yeoreum Yun
2025-06-11 12:46   ` Mark Brown
2025-06-11 14:09     ` Yeoreum Yun
2025-06-11  9:48 ` [PATCH v5 6/7] kselftest/arm64/mte: preparation for mte store only test Yeoreum Yun
2025-06-11 13:10   ` Mark Brown
2025-06-11 14:12     ` Yeoreum Yun
2025-06-11  9:48 ` [PATCH v5 7/7] kselftest/arm64/mte: add MTE_STORE_ONLY testcases Yeoreum Yun
2025-06-11 13:02   ` Mark Brown
2025-06-11 14:11     ` Yeoreum Yun

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).