Modify the vDSO Makefile such that it can also build a vDSO for the purecap ABI and change the fallbacks to use capability registers when running in purecap. Therefore, under PCuABI, vDSOs will be built for both aarch64 (COMPAT64) and a purecap.
Note that this change only implements the build of the purecap vDSO. Mapping of this vDSO by the kernel into user address space will be done in a subsequent patch.
Signed-off-by: Aditya Deshpande aditya.deshpande@arm.com --- arch/arm64/Makefile | 6 +++ arch/arm64/include/asm/vdso/gettimeofday.h | 60 +++++++++++++++++++--- arch/arm64/kernel/vdso/Makefile | 41 ++++++++++++--- include/linux/compiler.h | 3 +- include/linux/types.h | 4 ++ include/linux/user_ptr.h | 1 + 6 files changed, 99 insertions(+), 16 deletions(-)
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index f5ac0cb0147e..41e7a415ec08 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -179,6 +179,8 @@ vdso_install: $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@ $(if $(CONFIG_COMPAT_VDSO), \ $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@) + $(if $(CONFIG_CHERI_PURECAP_UABI), \ + $(Q)$(MAKE) BUILD_PURECAP_VDSO=y $(build)=arch/arm64/kernel/vdso $@)
archprepare: $(Q)$(MAKE) $(build)=arch/arm64/tools kapi @@ -204,6 +206,10 @@ prepare: vdso_prepare vdso_prepare: prepare0 $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso \ include/generated/vdso-offsets.h arch/arm64/kernel/vdso/vdso.so +ifdef CONFIG_CHERI_PURECAP_UABI + $(Q)$(MAKE) BUILD_PURECAP_VDSO=y $(build)=arch/arm64/kernel/vdso \ + include/generated/vdso-purecap-offsets.h arch/arm64/kernel/vdso-purecap/vdso.so +endif ifdef CONFIG_COMPAT_VDSO $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 \ include/generated/vdso32-offsets.h arch/arm64/kernel/vdso32/vdso.so diff --git a/arch/arm64/include/asm/vdso/gettimeofday.h b/arch/arm64/include/asm/vdso/gettimeofday.h index 764d13e2916c..0ff23704c5c6 100644 --- a/arch/arm64/include/asm/vdso/gettimeofday.h +++ b/arch/arm64/include/asm/vdso/gettimeofday.h @@ -14,19 +14,35 @@
#define VDSO_HAS_CLOCK_GETRES 1
+// // Stringizing macros +#define xstr(s) str(s) +#define str(s) #s + +/* Inline Assembly Macros for Purecap + * PTR_REG(n) will expand to "cn" under purecap, and "xn" under non-purecap + * PTR_REG_OP will expand to "C" under purecap and "r" under non-purecap. + */ +#if defined(__CHERI_PURE_CAPABILITY__) +#define PTR_REG(n) "c" xstr(n) +#define PTR_REG_OP "C" +#else +#define PTR_REG(n) "x" xstr(n) +#define PTR_REG_OP "r" +#endif /* __CHERI_PURE_CAPABILITY__ */ + static __always_inline int gettimeofday_fallback(struct __kernel_old_timeval *_tv, struct timezone *_tz) { - register struct timezone *tz asm("x1") = _tz; - register struct __kernel_old_timeval *tv asm("x0") = _tv; + register struct timezone *tz asm(PTR_REG(1)) = _tz; + register struct __kernel_old_timeval *tv asm(PTR_REG(0)) = _tv; register long ret asm ("x0"); register long nr asm("x8") = __NR_gettimeofday;
asm volatile( " svc #0\n" : "=r" (ret) - : "r" (tv), "r" (tz), "r" (nr) + : PTR_REG_OP (tv), PTR_REG_OP (tz), "r" (nr) : "memory");
return ret; @@ -35,7 +51,7 @@ int gettimeofday_fallback(struct __kernel_old_timeval *_tv, static __always_inline long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) { - register struct __kernel_timespec *ts asm("x1") = _ts; + register struct __kernel_timespec *ts asm(PTR_REG(1)) = _ts; register clockid_t clkid asm("x0") = _clkid; register long ret asm ("x0"); register long nr asm("x8") = __NR_clock_gettime; @@ -43,7 +59,7 @@ long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) asm volatile( " svc #0\n" : "=r" (ret) - : "r" (clkid), "r" (ts), "r" (nr) + : "r" (clkid), PTR_REG_OP (ts), "r" (nr) : "memory");
return ret; @@ -52,7 +68,7 @@ long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) static __always_inline int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) { - register struct __kernel_timespec *ts asm("x1") = _ts; + register struct __kernel_timespec *ts asm(PTR_REG(1)) = _ts; register clockid_t clkid asm("x0") = _clkid; register long ret asm ("x0"); register long nr asm("x8") = __NR_clock_getres; @@ -60,7 +76,7 @@ int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) asm volatile( " svc #0\n" : "=r" (ret) - : "r" (clkid), "r" (ts), "r" (nr) + : "r" (clkid), PTR_REG_OP (ts), "r" (nr) : "memory");
return ret; @@ -99,6 +115,32 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, return res; }
+#if defined(__CHERI_PURE_CAPABILITY__) +static __always_inline +const struct vdso_data *__arch_get_vdso_data(void) +{ + const struct vdso_data *vd; + asm(".hidden _vdso_data\n\t" + "adrp %0, _vdso_data\n\t" + "add %0, %0, #:lo12:_vdso_data" + : "=C"(vd)); + return vd; +} + +#ifdef CONFIG_TIME_NS +static __always_inline +const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd) +{ + const struct vdso_data *td; + asm(".hidden _timens_data\n\t" + "adrp %0, _timens_data\n\t" + "add %0, %0, #:lo12:_timens_data" + : "=C"(td)); + return td; +} +#endif /* CONFIG_TIME_NS */ + +#else /* !__CHERI_PURE_CAPABILITY__ */ static __always_inline const struct vdso_data *__arch_get_vdso_data(void) { @@ -111,7 +153,9 @@ const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd) { return _timens_data; } -#endif +#endif /* CONFIG_TIME_NS */ + +#endif /* __CHERI_PURE_CAPABILITY__ */
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile index fe7a53c6781f..07705ec1304d 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -33,6 +33,26 @@ ldflags-y += -T ccflags-y := -fno-common -fno-builtin -fno-stack-protector -ffixed-x18 ccflags-y += -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
+# When building for PCuABI, this Makefile will be called twice: first to build +# the regular arm64 vDSO, and second to build the purecap vDSO. We must change +# certain variables/flags depending on which vDSO we are building. +ifdef BUILD_PURECAP_VDSO + PURECAP_FLAGS := -mabi=purecap + REMOVE_FLAGS := -mgeneral-regs-only + ccflags-y += $(PURECAP_FLAGS) + asflags-y := $(PURECAP_FLAGS) + ccflags-remove-y := $(REMOVE_FLAGS) + asflags-remove-y := $(REMOVE_FLAGS) + +# We want the purecap vDSO in its own directory (kernel/vdso-purecap) + output-dir := $(obj)-purecap +# Put the offsets for the purecap vDSO into their own header file + offsets := include/generated/vdso-purecap-offsets.h +else + output-dir := $(obj) + offsets := include/generated/vdso-offsets.h +endif + # -Wmissing-prototypes and -Wmissing-declarations are removed from # the CFLAGS of vgettimeofday.c to make possible to build the # kernel with CONFIG_WERROR enabled. @@ -58,13 +78,20 @@ GCOV_PROFILE := n targets += vdso.lds CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+# Make the vdso-purecap directory +purecap_mkdir: +ifdef BUILD_PURECAP_VDSO + @mkdir -p $(output-dir) +endif + # Link rule for the .so file, .lds has to be first -$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE +$(output-dir)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE $(call if_changed,vdsold_and_vdso_check)
# Strip rule for the .so file -$(obj)/%.so: OBJCOPYFLAGS := -S -$(obj)/%.so: $(obj)/%.so.dbg FORCE +$(output-dir)/%.so: purecap_mkdir +$(output-dir)/%.so: OBJCOPYFLAGS := -S +$(output-dir)/%.so: $(output-dir)/%.so.dbg FORCE $(call if_changed,objcopy)
# Generate VDSO offsets using helper script @@ -72,7 +99,7 @@ gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh quiet_cmd_vdsosym = VDSOSYM $@ cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
-include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE +$(offsets): $(output-dir)/vdso.so.dbg FORCE $(call if_changed,vdsosym)
# Actual build commands @@ -81,10 +108,10 @@ quiet_cmd_vdsold_and_vdso_check = LD $@
# Install commands for the unstripped file quiet_cmd_vdso_install = INSTALL $@ - cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ + cmd_vdso_install = cp $(output-dir)/$@.dbg $(MODLIB)/vdso/$@
-vdso.so: $(obj)/vdso.so.dbg +vdso.so: $(output-dir)/vdso.so.dbg @mkdir -p $(MODLIB)/vdso $(call cmd,vdso_install)
-vdso_install: vdso.so +vdso_install: purecap_mkdir vdso.so diff --git a/include/linux/compiler.h b/include/linux/compiler.h index d7779a18b24f..7864350d0edb 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -3,6 +3,7 @@ #define __LINUX_COMPILER_H
#include <linux/compiler_types.h> +#include <linux/types.h>
#ifndef __ASSEMBLY__
@@ -222,7 +223,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, */ static inline void *offset_to_ptr(const int *off) { - return (void *)((unsigned long)off + *off); + return (void *)((uintptr_t)off + *off); }
#endif /* __ASSEMBLY__ */ diff --git a/include/linux/types.h b/include/linux/types.h index 897c134c1e8a..aa661f26fb6c 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -46,7 +46,11 @@ typedef __kernel_gid32_t gid_t; typedef __kernel_uid16_t uid16_t; typedef __kernel_gid16_t gid16_t;
+#ifdef __CHERI_PURE_CAPABILITY__ +typedef __uintcap_t uintptr_t; +#else typedef unsigned long uintptr_t; +#endif
#ifdef CONFIG_CHERI_PURECAP_UABI typedef __uintcap_t user_uintptr_t; diff --git a/include/linux/user_ptr.h b/include/linux/user_ptr.h index 2c2180f0f0c3..21bfe5075141 100644 --- a/include/linux/user_ptr.h +++ b/include/linux/user_ptr.h @@ -3,6 +3,7 @@ #define _LINUX_USER_PTR_H
#include <linux/typecheck.h> +#include <linux/types.h>
/** * as_user_ptr() - Convert an arbitrary integer value to a user pointer.