Message ID | 20210115224645.1196742-13-richard.henderson@linaro.org |
---|---|
State | New |
Headers | show |
Series | target-arm: Implement ARMv8.5-MemTag, user mode | expand |
On Fri, 15 Jan 2021 at 22:47, Richard Henderson <richard.henderson@linaro.org> wrote: > > This is the prctl bit that controls whether syscalls accept tagged > addresses. See Documentation/arm64/tagged-address-abi.rst in the > linux kernel. > > Signed-off-by: Richard Henderson <richard.henderson@linaro.org> > --- > linux-user/aarch64/target_syscall.h | 4 ++++ > target/arm/cpu-param.h | 3 +++ > target/arm/cpu.h | 23 +++++++++++++++++++++++ > linux-user/syscall.c | 25 +++++++++++++++++++++++++ > target/arm/cpu.c | 3 +++ > 5 files changed, 58 insertions(+) > > diff --git a/linux-user/aarch64/target_syscall.h b/linux-user/aarch64/target_syscall.h > index 3194e6b009..820601dfcc 100644 > --- a/linux-user/aarch64/target_syscall.h > +++ b/linux-user/aarch64/target_syscall.h > @@ -30,4 +30,8 @@ struct target_pt_regs { > # define TARGET_PR_PAC_APDBKEY (1 << 3) > # define TARGET_PR_PAC_APGAKEY (1 << 4) > > +#define TARGET_PR_SET_TAGGED_ADDR_CTRL 55 > +#define TARGET_PR_GET_TAGGED_ADDR_CTRL 56 > +# define TARGET_PR_TAGGED_ADDR_ENABLE (1UL << 0) Stray extra space. Otherwise Reviewed-by: Peter Maydell <peter.maydell@linaro.org> thanks -- PMM
On Fri, 15 Jan 2021 at 22:47, Richard Henderson <richard.henderson@linaro.org> wrote: > > This is the prctl bit that controls whether syscalls accept tagged > addresses. See Documentation/arm64/tagged-address-abi.rst in the > linux kernel. > +#ifdef TARGET_TAGGED_ADDRESSES > +/** > + * cpu_untagged_addr: > + * @cs: CPU context > + * @x: tagged address > + * > + * Remove any address tag from @x. This is explicitly related to the > + * linux syscall TIF_TAGGED_ADDR setting, not TBI in general. > + * > + * There should be a better place to put this, but we need this in > + * include/exec/cpu_ldst.h, and not some place linux-user specific. > + */ > +static inline target_ulong cpu_untagged_addr(CPUState *cs, target_ulong x) > +{ > + ARMCPU *cpu = ARM_CPU(cs); > + return x & cpu->env.untagged_addr_mask; > +} > +#endif Forgot to mention: this only does the right thing on addresses in the lower half of the address space. I guess that's mostly OK for our purposes? It probably means that if a guest program deliberately dereferences a bad address in the top half of the address space we'll report the wrong (ie different to what a real kernel reports) address value to it in the SEGV signal handler. The kernel's "untagged_addr()" implementation: https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/asm/memory.h#L203 slightly confusingly does "untag the addr if it's in the userspace half, leave the tag bits alone if in the kernel half". thanks -- PMM
On Fri, 22 Jan 2021 at 11:53, Peter Maydell <peter.maydell@linaro.org> wrote: > The kernel's "untagged_addr()" implementation: > https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/asm/memory.h#L203 > slightly confusingly does "untag the addr if it's in the userspace > half, leave the tag bits alone if in the kernel half". ...and a kernel person has just explained to me the rationale: TBI is always enabled for userspace and never for the kernel, so "always clear tag bits for a userspace address, never clear them for a kernel address" is the right behaviour. I think we should have the same logic. -- PMM
diff --git a/linux-user/aarch64/target_syscall.h b/linux-user/aarch64/target_syscall.h index 3194e6b009..820601dfcc 100644 --- a/linux-user/aarch64/target_syscall.h +++ b/linux-user/aarch64/target_syscall.h @@ -30,4 +30,8 @@ struct target_pt_regs { # define TARGET_PR_PAC_APDBKEY (1 << 3) # define TARGET_PR_PAC_APGAKEY (1 << 4) +#define TARGET_PR_SET_TAGGED_ADDR_CTRL 55 +#define TARGET_PR_GET_TAGGED_ADDR_CTRL 56 +# define TARGET_PR_TAGGED_ADDR_ENABLE (1UL << 0) + #endif /* AARCH64_TARGET_SYSCALL_H */ diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index 6321385b46..f922aa0650 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -20,6 +20,9 @@ #ifdef CONFIG_USER_ONLY #define TARGET_PAGE_BITS 12 +# ifdef TARGET_AARCH64 +# define TARGET_TAGGED_ADDRESSES +# endif #else /* * ARMv7 and later CPUs have 4K pages minimum, but ARMv5 and v6 diff --git a/target/arm/cpu.h b/target/arm/cpu.h index f3bca73d98..6ddfd9ebe6 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -712,6 +712,10 @@ typedef struct CPUARMState { const struct arm_boot_info *boot_info; /* Store GICv3CPUState to access from this struct */ void *gicv3state; + +#ifdef TARGET_TAGGED_ADDRESSES + target_ulong untagged_addr_mask; +#endif } CPUARMState; static inline void set_feature(CPUARMState *env, int feature) @@ -3556,6 +3560,25 @@ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x) */ #define PAGE_BTI PAGE_TARGET_1 +#ifdef TARGET_TAGGED_ADDRESSES +/** + * cpu_untagged_addr: + * @cs: CPU context + * @x: tagged address + * + * Remove any address tag from @x. This is explicitly related to the + * linux syscall TIF_TAGGED_ADDR setting, not TBI in general. + * + * There should be a better place to put this, but we need this in + * include/exec/cpu_ldst.h, and not some place linux-user specific. + */ +static inline target_ulong cpu_untagged_addr(CPUState *cs, target_ulong x) +{ + ARMCPU *cpu = ARM_CPU(cs); + return x & cpu->env.untagged_addr_mask; +} +#endif + /* * Naming convention for isar_feature functions: * Functions which test 32-bit ID registers should have _aa32_ in diff --git a/linux-user/syscall.c b/linux-user/syscall.c index bec2ab7769..ebb4e2898c 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -10948,6 +10948,31 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, } } return -TARGET_EINVAL; + case TARGET_PR_SET_TAGGED_ADDR_CTRL: + { + abi_ulong valid_mask = TARGET_PR_TAGGED_ADDR_ENABLE; + CPUARMState *env = cpu_env; + + if ((arg2 & ~valid_mask) || arg3 || arg4 || arg5) { + return -TARGET_EINVAL; + } + env->untagged_addr_mask = (arg2 & TARGET_PR_TAGGED_ADDR_ENABLE + ? MAKE_64BIT_MASK(0, 56) : -1); + return 0; + } + case TARGET_PR_GET_TAGGED_ADDR_CTRL: + { + abi_long ret = 0; + CPUARMState *env = cpu_env; + + if (arg2 || arg3 || arg4 || arg5) { + return -TARGET_EINVAL; + } + if (env->untagged_addr_mask != -1) { + ret |= TARGET_PR_TAGGED_ADDR_ENABLE; + } + return ret; + } #endif /* AARCH64 */ case PR_GET_SECCOMP: case PR_SET_SECCOMP: diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 8387e94b94..abc0affd00 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -208,6 +208,9 @@ static void arm_cpu_reset(DeviceState *dev) * Do not modify this without other changes. */ env->cp15.tcr_el[1].raw_tcr = (3ULL << 37); +# ifdef TARGET_TAGGED_ADDRESSES + env->untagged_addr_mask = -1; +# endif #else /* Reset into the highest available EL */ if (arm_feature(env, ARM_FEATURE_EL3)) {
This is the prctl bit that controls whether syscalls accept tagged addresses. See Documentation/arm64/tagged-address-abi.rst in the linux kernel. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/aarch64/target_syscall.h | 4 ++++ target/arm/cpu-param.h | 3 +++ target/arm/cpu.h | 23 +++++++++++++++++++++++ linux-user/syscall.c | 25 +++++++++++++++++++++++++ target/arm/cpu.c | 3 +++ 5 files changed, 58 insertions(+) -- 2.25.1