[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.
*/