[pkvm] Statically link el2.bin built at -O0

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 4291feb..04b4c09 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -90,9 +90,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);
@@ -138,6 +138,13 @@
 KVM_NVHE_ALIAS(kvm_hyp_debug_uart_set_basep);
 #endif
 
+/* Only needed to link when built at -O0 */
+KVM_NVHE_ALIAS(cpu_hwcaps);
+#ifdef CONFIG_TRACE_IRQFLAGS
+KVM_NVHE_ALIAS(trace_hardirqs_off);
+KVM_NVHE_ALIAS(trace_hardirqs_on);
+#endif
+
 #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 2428f17..b60b48f 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -97,3 +97,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..4f69048
--- /dev/null
+++ b/arch/arm64/kvm/hyp/nvhe/dummy.c
@@ -0,0 +1,99 @@
+// Dummy definitions to produce a fully linked EL2 binary for analysis.
+
+#define KVM_NVHE_ALIAS(sym)	unsigned long sym
+#define KVM_NVHE_ALIAS_HYP(x,y)	unsigned long __kvm_nvhe_##y
+
+// XXX: Following imported directly 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_get_kimage_voffset);
+KVM_NVHE_ALIAS(kvm_compute_final_ctr_el0);
+
+/* 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(nvhe_hyp_panic_handler);
+
+/* 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);
+
+/* PMU available static key */
+KVM_NVHE_ALIAS(kvm_arm_pmu_available);
+
+/* Position-independent library routines */
+KVM_NVHE_ALIAS_HYP(clear_page, __pi_clear_page);
+KVM_NVHE_ALIAS_HYP(copy_page, __pi_copy_page);
+KVM_NVHE_ALIAS_HYP(memcpy, __pi_memcpy);
+KVM_NVHE_ALIAS_HYP(memset, __pi_memset);
+
+#ifdef CONFIG_KASAN
+KVM_NVHE_ALIAS_HYP(__memcpy, __pi_memcpy);
+KVM_NVHE_ALIAS_HYP(__memset, __pi_memset);
+#endif
+
+/* 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_bss_start);
+KVM_NVHE_ALIAS(__hyp_bss_end);
+KVM_NVHE_ALIAS(__hyp_rodata_start);
+KVM_NVHE_ALIAS(__hyp_rodata_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(cpu_hwcaps);
+#ifdef CONFIG_TRACE_IRQFLAGS
+KVM_NVHE_ALIAS(trace_hardirqs_off);
+KVM_NVHE_ALIAS(trace_hardirqs_on);
+#endif
diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
index d017b12..3880491 100644
--- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c
+++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
@@ -28,9 +28,13 @@
 
 static struct hyp_pool host_s2_pool;
 
-const pkvm_id pkvm_host_id	= 0;
-const pkvm_id pkvm_hyp_id	= (1 << 16);
-const pkvm_id pkvm_host_poison	= pkvm_hyp_id + 1;
+#define PKVM_HOST_ID	0
+#define PKVM_HYP_ID	(1 << 16)
+#define PKVM_HOST_POISON (PKVM_HYP_ID + 1)
+
+const pkvm_id pkvm_host_id	= PKVM_HOST_ID;
+const pkvm_id pkvm_hyp_id	= PKVM_HYP_ID;
+const pkvm_id pkvm_host_poison	= PKVM_HOST_POISON;
 
 static pkvm_id pkvm_guest_id(struct kvm_vcpu *vcpu)
 {
@@ -1814,10 +1818,10 @@
 	}
 
 	switch (kvm_get_owner_id(pte)) {
-	case pkvm_host_id:
+	case PKVM_HOST_ID:
 		ret = 0;
 		break;
-	case pkvm_host_poison:
+	case PKVM_HOST_POISON:
 		ret = hyp_zero_page(addr);
 		if (ret)
 			goto unlock;
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index d285ff5..b9ec2c7 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -21,6 +21,21 @@
 #include <nvhe/pkvm.h>
 #include <nvhe/trap_handler.h>
 
+int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+				const unsigned long *bitmap2, unsigned int bits)
+{
+	unsigned int k;
+	unsigned int lim = bits/BITS_PER_LONG;
+	unsigned long result = 0;
+
+	for (k = 0; k < lim; k++)
+		result |= (dst[k] = bitmap1[k] & bitmap2[k]);
+	if (bits % BITS_PER_LONG)
+		result |= (dst[k] = bitmap1[k] & bitmap2[k] &
+			   BITMAP_LAST_WORD_MASK(bits));
+	return result != 0;
+}
+
 /*
  * Set trap register values based on features in ID_AA64PFR0.
  */