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 | 58 ++++++++++++++++++--- arch/arm64/kernel/vdso/Makefile | 60 +++++++++++++++++++--- include/linux/compiler.h | 3 +- 4 files changed, 111 insertions(+), 16 deletions(-)
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index f5ac0cb0147e..839a522d83b8 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -177,6 +177,8 @@ install zinstall: PHONY += vdso_install vdso_install: $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@ + $(if $(CONFIG_CHERI_PURECAP_UABI), \ + $(Q)$(MAKE) BUILD_PURECAP_VDSO=y $(build)=arch/arm64/kernel/vdso $@) $(if $(CONFIG_COMPAT_VDSO), \ $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@)
@@ -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..17151df887d4 100644 --- a/arch/arm64/include/asm/vdso/gettimeofday.h +++ b/arch/arm64/include/asm/vdso/gettimeofday.h @@ -11,22 +11,36 @@ #include <asm/barrier.h> #include <asm/unistd.h> #include <asm/sysreg.h> +#include <linux/stringify.h>
#define VDSO_HAS_CLOCK_GETRES 1
+/* + * 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" __stringify(n) +#define PTR_REG_OP "C" +#else +#define PTR_REG(n) "x" __stringify(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 +49,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 +57,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 +66,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 +74,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 +113,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 +151,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..185eafcf709b 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -13,7 +13,6 @@ obj-vdso := vgettimeofday.o note.o sigreturn.o
# Build rules targets := $(obj-vdso) vdso.so vdso.so.dbg -obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
btildflags-$(CONFIG_ARM64_BTI_KERNEL) += -z force-bti
@@ -33,6 +32,29 @@ 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 + # Specify building for purecap + PURECAP_FLAGS := -mabi=purecap + # Remove this flag as capability registers are not considered + # as general purpose registers by the compiler. + 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. @@ -48,6 +70,9 @@ KCOV_INSTRUMENT := n
CFLAGS_vgettimeofday.o = -O2 -mcmodel=tiny -fasynchronous-unwind-tables
+CFLAGS_REMOVE_purecap/vgettimeofday.o = $(CFLAGS_REMOVE_vgettimeofday.o) +CFLAGS_purecap/vgettimeofday.o = $(CFLAGS_vgettimeofday.o) + ifneq ($(c-gettimeofday-y),) CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y) endif @@ -58,13 +83,34 @@ GCOV_PROFILE := n targets += vdso.lds CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+obj-vdso := $(addprefix $(output-dir)/, $(obj-vdso)) + +#Make the purecap directory under vdso/ +$(output-dir): +ifdef BUILD_PURECAP_VDSO + @mkdir -p $(output-dir) +endif + +# Explicit build rules are required for .o files when building for purecap, +# as the path to the output directory for built objects no longer matches +# the path to the source files. +# Regular: $(output-dir)/*.o == $(src)/*.[c|S] -> builds with implicit rule +# Purecap: $(output-dir)/*.o != $(src)/*.[c|S] -> needs an explicit rule +ifdef BUILD_PURECAP_VDSO +$(output-dir)/%.o: $(srctree)/$(src)/%.c FORCE | $(output-dir) + $(call if_changed_rule,cc_o_c) + +$(output-dir)/%.o: $(srctree)/$(src)/%.S FORCE | $(output-dir) + $(call if_changed_rule,as_o_S) +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: OBJCOPYFLAGS := -S +$(output-dir)/%.so: $(output-dir)/%.so.dbg FORCE $(call if_changed,objcopy)
# Generate VDSO offsets using helper script @@ -72,7 +118,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,9 +127,9 @@ 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)
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__ */