Auto-generate list of allowed symbol aliases
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h index c615b28..5003a58 100644 --- a/arch/arm64/kernel/image-vars.h +++ b/arch/arm64/kernel/image-vars.h
@@ -61,10 +61,6 @@ __efistub__ctype = _ctype; * memory mappings. */ -/* Alternative callbacks for init-time patching of nVHE hyp code. */ -KVM_NVHE_ALIAS(kvm_patch_vector_branch); -KVM_NVHE_ALIAS(kvm_update_va_mask); - /* Global kernel state accessed by nVHE hyp code. */ KVM_NVHE_ALIAS(kvm_vgic_global_state); @@ -84,21 +80,6 @@ KVM_NVHE_ALIAS(idmap_t0sz); /* Kernel symbol used by icache_is_vpipt(). */ KVM_NVHE_ALIAS(__icache_flags); -/* Kernel symbols needed for cpus_have_final/const_caps checks. */ -KVM_NVHE_ALIAS(arm64_const_caps_ready); -KVM_NVHE_ALIAS(cpu_hwcap_keys); - -/* Static keys which are set if a vGIC trap should be handled in hyp. */ -KVM_NVHE_ALIAS(vgic_v2_cpuif_trap); -KVM_NVHE_ALIAS(vgic_v3_cpuif_trap); - -/* Static key checked in pmr_sync(). */ -#ifdef CONFIG_ARM64_PSEUDO_NMI -KVM_NVHE_ALIAS(gic_pmr_sync); -/* Static key checked in GIC_PRIO_IRQOFF. */ -KVM_NVHE_ALIAS(gic_nonsecure_priorities); -#endif - /* EL2 exception handling */ KVM_NVHE_ALIAS(__start___kvm_ex_table); KVM_NVHE_ALIAS(__stop___kvm_ex_table);
diff --git a/arch/arm64/kvm/hyp/nvhe/.gitignore b/arch/arm64/kvm/hyp/nvhe/.gitignore index 695d73d..7f0372a 100644 --- a/arch/arm64/kvm/hyp/nvhe/.gitignore +++ b/arch/arm64/kvm/hyp/nvhe/.gitignore
@@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only hyp.lds +hyp-import.sym \ No newline at end of file
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile index ddde15f..f8d3d42 100644 --- a/arch/arm64/kvm/hyp/nvhe/Makefile +++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -18,7 +18,7 @@ hyp-obj := $(patsubst %.o,%.nvhe.o,$(obj-y)) obj-y := kvm_nvhe.o -extra-y := $(hyp-obj) kvm_nvhe.tmp.o hyp.lds +extra-y := $(hyp-obj) kvm_nvhe.tmp.o hyp.lds hyp-import.sym # 1) Compile all source files to `.nvhe.o` object files. The file extension # avoids file name clashes for files shared with VHE. @@ -41,15 +41,27 @@ $(obj)/kvm_nvhe.tmp.o: $(obj)/hyp.lds $(addprefix $(obj)/,$(hyp-obj)) FORCE $(call if_changed,ld) -# 4) Produce the final 'kvm_nvhe.o', ready to be linked into 'vmlinux'. -# Prefixes names of ELF symbols with '__kvm_nvhe_'. -$(obj)/kvm_nvhe.o: $(obj)/kvm_nvhe.tmp.o FORCE +# 4) Generate a list of symbols that should not be prefixed. +# These are symbols used before the host is deprivileged, eg. alternative +# callbacks and static keys. +gen_auto_alias := $(srctree)/$(src)/gen_auto_alias.sh +$(obj)/hyp-import.sym: $(obj)/kvm_nvhe.tmp.o $(gen_auto_alias) FORCE + $(call if_changed,hypinfo) + +quiet_cmd_hypinfo = HYPINFO $@ + cmd_hypinfo = $(gen_auto_alias) $< > $@ + +# 5) Produce the final 'kvm_nvhe.o', ready to be linked into 'vmlinux'. +# Prefixes names of ELF symbols with '__kvm_nvhe_', except for those +# enumerated in hyp-import.txt. +$(obj)/kvm_nvhe.o: $(obj)/kvm_nvhe.tmp.o $(obj)/hyp-import.sym FORCE $(call if_changed,hypcopy) # The HYPCOPY command uses `objcopy` to prefix all ELF symbol names # to avoid clashes with VHE code/data. quiet_cmd_hypcopy = HYPCOPY $@ - cmd_hypcopy = $(OBJCOPY) --prefix-symbols=__kvm_nvhe_ $< $@ + cmd_hypcopy = $(OBJCOPY) --prefix-symbols=__kvm_nvhe_ $< $@ && \ + $(OBJCOPY) --redefine-syms=$(obj)/hyp-alias.lds $@ # Remove ftrace and Shadow Call Stack CFLAGS. # This is equivalent to the 'notrace' and '__noscs' annotations.
diff --git a/arch/arm64/kvm/hyp/nvhe/gen_auto_alias.sh b/arch/arm64/kvm/hyp/nvhe/gen_auto_alias.sh new file mode 100755 index 0000000..87c82b4 --- /dev/null +++ b/arch/arm64/kvm/hyp/nvhe/gen_auto_alias.sh
@@ -0,0 +1,93 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Author: David Brazdil <dbrazdil@google.com> +# + +LC_ALL=C + +HYP_NAMESPACE="__kvm_nvhe_" + +# Note: https://bugs.llvm.org/show_bug.cgi?id=41886 +# Must list .rela sections for llvm-objdump + +# Allow all alternative callbacks +AUTO_SECTIONS=".rela.altinstructions " + +# Allow all static keys +AUTO_SECTIONS+=".rela__jump_table " + +fail() { + echo "ERROR: $1" 1>&2 + exit 1 +} + +assert_defined() { + test -v "$1" || fail "Environment variable $1 not defined" +} + +starts_with() { + case "$1" in + "$2"*) true;; + *) false;; + esac +} + +substr_from() { + echo "$1" | cut -c${2}- +} + +strlen() { + echo -n "$1" | wc -m +} + +assert_is_hyp_symbol() { + if ! starts_with "$SYM" "$HYP_NAMESPACE" + then + fail "Unexpected symbol name: $SYM" + fi +} + +base_sym_name() { + substr_from "$SYM" `strlen "$HYP_NAMESPACE"` +} + +for_each_undef_symbol() { + assert_defined "NM" + + "$NM" -u "$1" | while read LINE + do + if ! starts_with "$LINE" "U " + then + fail "Unexpected input: $LINE" + fi + + substr_from "$LINE" 3 + done +} + +list_relocs() { + assert_defined "OBJDUMP" + + SECTION_ARGS="" + for SECTION in $AUTO_SECTIONS + do + SECTION_ARGS+="-j$SECTION " + done + + "$OBJDUMP" -r $SECTION_ARGS "$1" +} + +list_contains_sym() { + grep "$1" 1>/dev/null <<<"$2" +} + +AUTO_LIST=`list_relocs "$1"` + +for_each_undef_symbol "$1" | while read SYM +do + if list_contains_sym "$SYM" "$AUTO_LIST" + then + echo "${HYP_NAMESPACE}${SYM} ${SYM}" + fi +done