[pkvm] Statically link el2.bin

Spit out a statically linked el2.bin file under arch/arm64/kvm/hyp/nvhe/
which can be used for the purposes of analysis.

Signed-off-by: Will Deacon <will@kernel.org>
diff --git a/arch/arm64/include/asm/jump_label.h b/arch/arm64/include/asm/jump_label.h
index cea441b..d5efacc 100644
--- a/arch/arm64/include/asm/jump_label.h
+++ b/arch/arm64/include/asm/jump_label.h
@@ -15,6 +15,12 @@
 
 #define JUMP_LABEL_NOP_SIZE		AARCH64_INSN_SIZE
 
+#ifdef __KVM_NVHE_HYPERVISOR__
+#define __static_key_enabled(k)		(!!__READ_ONCE((k)->enabled.counter))
+#define arch_static_branch(k,b)		(b ^ __static_key_enabled(k))
+#define arch_static_branch_jump(k,b)	(b ^ __static_key_enabled(k))
+#else
+
 static __always_inline bool arch_static_branch(struct static_key *key,
 					       bool branch)
 {
@@ -49,5 +55,6 @@
 	return true;
 }
 
+#endif	/* !__KVM_NVHE_HYPERVISOR__ */
 #endif  /* __ASSEMBLY__ */
 #endif	/* __ASM_JUMP_LABEL_H */
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index ac28e70..57a23f5 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -91,9 +91,9 @@
 /* Static key checked in pmr_sync(). */
 #ifdef CONFIG_ARM64_PSEUDO_NMI
 KVM_NVHE_ALIAS(gic_pmr_sync);
+#endif
 /* Static key checked in GIC_PRIO_IRQOFF. */
 KVM_NVHE_ALIAS(gic_nonsecure_priorities);
-#endif
 
 /* EL2 exception handling */
 KVM_NVHE_ALIAS(__start___kvm_ex_table);
@@ -141,6 +141,11 @@
 KVM_NVHE_ALIAS(kvm_hyp_debug_uart_set_basep);
 #endif
 
+/* Only needed to link when built at -O0 */
+KVM_NVHE_ALIAS(sve_load_state);
+KVM_NVHE_ALIAS(sve_save_state);
+KVM_NVHE_ALIAS(cpu_hwcaps);
+
 #endif /* CONFIG_KVM */
 
 #endif /* __ARM64_KERNEL_IMAGE_VARS_H */
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index c3e2f98..cba037c 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -72,3 +72,10 @@
 # Skip objtool checking for this directory because nVHE code is compiled with
 # non-standard build rules.
 OBJECT_FILES_NON_STANDARD := y
+
+# Hacks for analysis purposes
+ccflags-y += -O0
+extra-y += dummy.o el2.bin
+LDFLAGS_el2.bin := -T
+$(obj)/el2.bin: $(obj)/hyp.lds $(addprefix $(obj)/,$(hyp-obj)) $(obj)/dummy.o FORCE
+	$(call if_changed,ld)
diff --git a/arch/arm64/kvm/hyp/nvhe/dummy.c b/arch/arm64/kvm/hyp/nvhe/dummy.c
new file mode 100644
index 0000000..5f16969
--- /dev/null
+++ b/arch/arm64/kvm/hyp/nvhe/dummy.c
@@ -0,0 +1,85 @@
+// Dummy definitions to produce a fully linked EL2 binary for analysis.
+
+#define KVM_NVHE_ALIAS(sym)	unsigned long sym
+
+// XXX: Following imported from image-vars.h
+
+/*
+ * KVM nVHE code has its own symbol namespace prefixed with __kvm_nvhe_, to
+ * separate it from the kernel proper. The following symbols are legally
+ * accessed by it, therefore provide aliases to make them linkable.
+ * Do not include symbols which may not be safely accessed under hypervisor
+ * 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);
+KVM_NVHE_ALIAS(kvm_update_kimg_phys_offset);
+KVM_NVHE_ALIAS(kvm_get_kimage_voffset);
+
+/* Global kernel state accessed by nVHE hyp code. */
+KVM_NVHE_ALIAS(kvm_vgic_global_state);
+
+/* Kernel symbols used to call panic() from nVHE hyp code (via ERET). */
+KVM_NVHE_ALIAS(__hyp_panic_string);
+KVM_NVHE_ALIAS(panic);
+
+/* Vectors installed by hyp-init on reset HVC. */
+KVM_NVHE_ALIAS(__hyp_stub_vectors);
+
+/* 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);
+#endif
+/* Static key checked in GIC_PRIO_IRQOFF. */
+KVM_NVHE_ALIAS(gic_nonsecure_priorities);
+
+/* EL2 exception handling */
+KVM_NVHE_ALIAS(__start___kvm_ex_table);
+KVM_NVHE_ALIAS(__stop___kvm_ex_table);
+
+/* Array containing bases of nVHE per-CPU memory regions. */
+KVM_NVHE_ALIAS(kvm_arm_hyp_percpu_base);
+
+/* Hypevisor VA size */
+KVM_NVHE_ALIAS(hyp_va_bits);
+
+/* Kernel memory sections */
+KVM_NVHE_ALIAS(__start_rodata);
+KVM_NVHE_ALIAS(__end_rodata);
+KVM_NVHE_ALIAS(__bss_start);
+KVM_NVHE_ALIAS(__bss_stop);
+
+/* Hyp memory sections */
+KVM_NVHE_ALIAS(__hyp_idmap_text_start);
+KVM_NVHE_ALIAS(__hyp_idmap_text_end);
+KVM_NVHE_ALIAS(__hyp_text_start);
+KVM_NVHE_ALIAS(__hyp_text_end);
+KVM_NVHE_ALIAS(__hyp_data_ro_after_init_start);
+KVM_NVHE_ALIAS(__hyp_data_ro_after_init_end);
+KVM_NVHE_ALIAS(__hyp_bss_start);
+KVM_NVHE_ALIAS(__hyp_bss_end);
+
+/* pKVM static key */
+KVM_NVHE_ALIAS(kvm_protected_mode_initialized);
+
+#ifdef CONFIG_KVM_ARM_HYP_DEBUG_UART
+KVM_NVHE_ALIAS(kvm_hyp_debug_uart_set_basep);
+#endif
+
+/* Only needed to link when built at -O0 */
+KVM_NVHE_ALIAS(sve_load_state);
+KVM_NVHE_ALIAS(sve_save_state);
+KVM_NVHE_ALIAS(cpu_hwcaps);
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 1d827ad2..29b904d 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -150,7 +150,7 @@
 
 #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = kimg_fn_ptr(handle_##x)
 
-static const hcall_t *host_hcall[] = {
+static const hcall_t *host_hcall[] __ro_after_init = {
 	HANDLE_FUNC(__kvm_vcpu_run),
 	HANDLE_FUNC(__kvm_flush_vm_context),
 	HANDLE_FUNC(__kvm_tlb_flush_vmid_ipa),