diff mbox series

[v2,10/17] linux-user/aarch64: Implement PR_MTE_TCF and PR_MTE_TAG

Message ID 20200605041733.415188-11-richard.henderson@linaro.org (mailing list archive)
State New, archived
Headers show
Series target-arm: Implement ARMv8.5-MemTag, user mode | expand

Commit Message

Richard Henderson June 5, 2020, 4:17 a.m. UTC
These prctl fields are required for the function of MTE.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/aarch64/target_syscall.h |  9 ++++++
 linux-user/syscall.c                | 46 +++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)

Comments

Peter Maydell June 25, 2020, 4:50 p.m. UTC | #1
On Fri, 5 Jun 2020 at 05:17, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> These prctl fields are required for the function of MTE.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

This API doesn't seem to be in the upstream kernel yet, right?

> +                    /*
> +                     * Write PR_MTE_TCF to SCTLR_EL1[TCF0].
> +                     * Note that the syscall values are consistent with hw.
> +                     */
> +                    env->cp15.sctlr_el[1] =
> +                        deposit64(env->cp15.sctlr_el[1], 38, 2,
> +                                  arg2 >> TARGET_PR_MTE_TCF_SHIFT);

This actually will be per-thread since each linux-user thread has
its own CPU. You probably need to do something to make it be
inherited across clone and fork, though (assuming those are
the required semantics).

thanks
-- PMM
Richard Henderson Dec. 17, 2020, 5:24 p.m. UTC | #2
On 6/25/20 11:50 AM, Peter Maydell wrote:
> On Fri, 5 Jun 2020 at 05:17, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> These prctl fields are required for the function of MTE.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> 
> This API doesn't seem to be in the upstream kernel yet, right?

It has finally landed in 5.10.
Thus the long delay since my last revision.

>> +                    /*
>> +                     * Write PR_MTE_TCF to SCTLR_EL1[TCF0].
>> +                     * Note that the syscall values are consistent with hw.
>> +                     */
>> +                    env->cp15.sctlr_el[1] =
>> +                        deposit64(env->cp15.sctlr_el[1], 38, 2,
>> +                                  arg2 >> TARGET_PR_MTE_TCF_SHIFT);
> 
> This actually will be per-thread since each linux-user thread has
> its own CPU. You probably need to do something to make it be
> inherited across clone and fork, though (assuming those are
> the required semantics).

FWIW, these are a per-thread quantities.

>From arch/arm64/kernel/mte.c:
> void mte_thread_switch(struct task_struct *next)
> {
>         if (!system_supports_mte())
>                 return;
> 
>         /* avoid expensive SCTLR_EL1 accesses if no change */
>         if (current->thread.sctlr_tcf0 != next->thread.sctlr_tcf0)
>                 update_sctlr_el1_tcf0(next->thread.sctlr_tcf0);
>         update_gcr_el1_excl(next->thread.gcr_user_incl);
> }

I don't think I have to do anything special wrt fork/clone, as env->cp15 will
get copied by our own cpu_copy().


r~
diff mbox series

Patch

diff --git a/linux-user/aarch64/target_syscall.h b/linux-user/aarch64/target_syscall.h
index 5fb0bf4a5d..779ca0c805 100644
--- a/linux-user/aarch64/target_syscall.h
+++ b/linux-user/aarch64/target_syscall.h
@@ -32,5 +32,14 @@  struct target_pt_regs {
 #define TARGET_PR_SET_TAGGED_ADDR_CTRL 55
 #define TARGET_PR_GET_TAGGED_ADDR_CTRL 56
 # define TARGET_PR_TAGGED_ADDR_ENABLE  (1UL << 0)
+/* MTE tag check fault modes */
+# define TARGET_PR_MTE_TCF_SHIFT       1
+# define TARGET_PR_MTE_TCF_NONE        (0UL << TARGET_PR_MTE_TCF_SHIFT)
+# define TARGET_PR_MTE_TCF_SYNC        (1UL << TARGET_PR_MTE_TCF_SHIFT)
+# define TARGET_PR_MTE_TCF_ASYNC       (2UL << TARGET_PR_MTE_TCF_SHIFT)
+# define TARGET_PR_MTE_TCF_MASK        (3UL << TARGET_PR_MTE_TCF_SHIFT)
+/* MTE tag inclusion mask */
+# define TARGET_PR_MTE_TAG_SHIFT       3
+# define TARGET_PR_MTE_TAG_MASK        (0xffffUL << TARGET_PR_MTE_TAG_SHIFT)
 
 #endif /* AARCH64_TARGET_SYSCALL_H */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index e4da53c5b3..9cf3ce872d 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -10463,10 +10463,47 @@  static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         case TARGET_PR_SET_TAGGED_ADDR_CTRL:
             {
                 abi_ulong valid_mask = TARGET_PR_TAGGED_ADDR_ENABLE;
+                CPUARMState *env = cpu_env;
+                ARMCPU *cpu = env_archcpu(env);
+
+                if (cpu_isar_feature(aa64_mte, cpu)) {
+                    valid_mask |= TARGET_PR_MTE_TCF_MASK;
+                    valid_mask |= TARGET_PR_MTE_TAG_MASK;
+                }
 
                 if ((arg2 & ~valid_mask) || arg3 || arg4 || arg5) {
                     return -TARGET_EINVAL;
                 }
+
+                if (cpu_isar_feature(aa64_mte, cpu)) {
+                    switch (arg2 & TARGET_PR_MTE_TCF_MASK) {
+                    case TARGET_PR_MTE_TCF_NONE:
+                    case TARGET_PR_MTE_TCF_SYNC:
+                    case TARGET_PR_MTE_TCF_ASYNC:
+                        break;
+                    default:
+                        return -EINVAL;
+                    }
+
+                    /*
+                     * Write PR_MTE_TCF to SCTLR_EL1[TCF0].
+                     * Note that the syscall values are consistent with hw.
+                     */
+                    env->cp15.sctlr_el[1] =
+                        deposit64(env->cp15.sctlr_el[1], 38, 2,
+                                  arg2 >> TARGET_PR_MTE_TCF_SHIFT);
+
+                    /*
+                     * Write PR_MTE_TAG to GCR_EL1[Exclude].
+                     * Note that the syscall uses an include mask,
+                     * and hardware uses an exclude mask -- invert.
+                     */
+                    env->cp15.gcr_el1 =
+                        deposit64(env->cp15.gcr_el1, 0, 16,
+                                  ~arg2 >> TARGET_PR_MTE_TAG_SHIFT);
+                    arm_rebuild_hflags(env);
+                }
+
                 untagged_addr_mask = (arg2 & TARGET_PR_TAGGED_ADDR_ENABLE
                                       ? MAKE_64BIT_MASK(0, 56) : -1);
                 return 0;
@@ -10474,6 +10511,8 @@  static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         case TARGET_PR_GET_TAGGED_ADDR_CTRL:
             {
                 abi_long ret = 0;
+                CPUARMState *env = cpu_env;
+                ARMCPU *cpu = env_archcpu(env);
 
                 if (arg2 || arg3 || arg4 || arg5) {
                     return -TARGET_EINVAL;
@@ -10481,6 +10520,13 @@  static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                 if (~untagged_addr_mask != 0) {
                     ret |= TARGET_PR_TAGGED_ADDR_ENABLE;
                 }
+                if (cpu_isar_feature(aa64_mte, cpu)) {
+                    /* See above. */
+                    ret |= (extract64(env->cp15.sctlr_el[1], 38, 2)
+                            << TARGET_PR_MTE_TCF_SHIFT);
+                    ret = deposit64(ret, TARGET_PR_MTE_TAG_SHIFT, 16,
+                                    ~env->cp15.gcr_el1);
+                }
                 return ret;
             }
 #endif /* AARCH64 */