arm64/ptrace: Support access to TPIDR2_EL0
authorMark Brown <broonie@kernel.org>
Mon, 29 Aug 2022 15:49:20 +0000 (16:49 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Wed, 21 Sep 2022 16:26:58 +0000 (17:26 +0100)
SME introduces an additional EL0 register, TPIDR2_EL0, intended for use
by userspace as part of the SME. Provide ptrace access to it through the
existing NT_ARM_TLS regset used for TPIDR_EL0 by expanding it to two
registers with TPIDR2_EL0 being the second one.

Existing programs that query the size of the register set will be able
to observe the increased size of the register set. Programs that assume
the register set is single register will see no change. On systems that
do not support SME TPIDR2_EL0 will read as 0 and writes will be ignored,
support for SME should be queried via hwcaps as normal.

Signed-off-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20220829154921.837871-4-broonie@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/kernel/ptrace.c

index eb7c08d..0e9764f 100644 (file)
@@ -666,10 +666,18 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset,
 static int tls_get(struct task_struct *target, const struct user_regset *regset,
                   struct membuf to)
 {
+       int ret;
+
        if (target == current)
                tls_preserve_current_state();
 
-       return membuf_store(&to, target->thread.uw.tp_value);
+       ret = membuf_store(&to, target->thread.uw.tp_value);
+       if (system_supports_tpidr2())
+               ret = membuf_store(&to, target->thread.tpidr2_el0);
+       else
+               ret = membuf_zero(&to, sizeof(u64));
+
+       return ret;
 }
 
 static int tls_set(struct task_struct *target, const struct user_regset *regset,
@@ -677,13 +685,20 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,
                   const void *kbuf, const void __user *ubuf)
 {
        int ret;
-       unsigned long tls = target->thread.uw.tp_value;
+       unsigned long tls[2];
 
-       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
+       tls[0] = target->thread.uw.tp_value;
+       if (system_supports_sme())
+               tls[1] = target->thread.tpidr2_el0;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, tls, 0, count);
        if (ret)
                return ret;
 
-       target->thread.uw.tp_value = tls;
+       target->thread.uw.tp_value = tls[0];
+       if (system_supports_sme())
+               target->thread.tpidr2_el0 = tls[1];
+
        return ret;
 }
 
@@ -1392,7 +1407,7 @@ static const struct user_regset aarch64_regsets[] = {
        },
        [REGSET_TLS] = {
                .core_note_type = NT_ARM_TLS,
-               .n = 1,
+               .n = 2,
                .size = sizeof(void *),
                .align = sizeof(void *),
                .regset_get = tls_get,