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 @@
  * 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 @@
 /* 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