Commit a0bf9776 authored by Ard Biesheuvel's avatar Ard Biesheuvel Committed by Catalin Marinas

arm64: kvm: deal with kernel symbols outside of linear mapping

KVM on arm64 uses a fixed offset between the linear mapping at EL1 and
the HYP mapping at EL2. Before we can move the kernel virtual mapping
out of the linear mapping, we have to make sure that references to kernel
symbols that are accessed via the HYP mapping are translated to their
linear equivalent.
Reviewed-by: default avatarMark Rutland <mark.rutland@arm.com>
Acked-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 157962f5
...@@ -79,6 +79,8 @@ ...@@ -79,6 +79,8 @@
#define rr_lo_hi(a1, a2) a1, a2 #define rr_lo_hi(a1, a2) a1, a2
#endif #endif
#define kvm_ksym_ref(kva) (kva)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
struct kvm; struct kvm;
struct kvm_vcpu; struct kvm_vcpu;
......
...@@ -982,7 +982,7 @@ static void cpu_init_hyp_mode(void *dummy) ...@@ -982,7 +982,7 @@ static void cpu_init_hyp_mode(void *dummy)
pgd_ptr = kvm_mmu_get_httbr(); pgd_ptr = kvm_mmu_get_httbr();
stack_page = __this_cpu_read(kvm_arm_hyp_stack_page); stack_page = __this_cpu_read(kvm_arm_hyp_stack_page);
hyp_stack_ptr = stack_page + PAGE_SIZE; hyp_stack_ptr = stack_page + PAGE_SIZE;
vector_ptr = (unsigned long)__kvm_hyp_vector; vector_ptr = (unsigned long)kvm_ksym_ref(__kvm_hyp_vector);
__cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr);
...@@ -1074,13 +1074,15 @@ static int init_hyp_mode(void) ...@@ -1074,13 +1074,15 @@ static int init_hyp_mode(void)
/* /*
* Map the Hyp-code called directly from the host * Map the Hyp-code called directly from the host
*/ */
err = create_hyp_mappings(__kvm_hyp_code_start, __kvm_hyp_code_end); err = create_hyp_mappings(kvm_ksym_ref(__kvm_hyp_code_start),
kvm_ksym_ref(__kvm_hyp_code_end));
if (err) { if (err) {
kvm_err("Cannot map world-switch code\n"); kvm_err("Cannot map world-switch code\n");
goto out_free_mappings; goto out_free_mappings;
} }
err = create_hyp_mappings(__start_rodata, __end_rodata); err = create_hyp_mappings(kvm_ksym_ref(__start_rodata),
kvm_ksym_ref(__end_rodata));
if (err) { if (err) {
kvm_err("Cannot map rodata section\n"); kvm_err("Cannot map rodata section\n");
goto out_free_mappings; goto out_free_mappings;
......
...@@ -26,7 +26,24 @@ ...@@ -26,7 +26,24 @@
#define KVM_ARM64_DEBUG_DIRTY_SHIFT 0 #define KVM_ARM64_DEBUG_DIRTY_SHIFT 0
#define KVM_ARM64_DEBUG_DIRTY (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT) #define KVM_ARM64_DEBUG_DIRTY (1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
#define kvm_ksym_ref(sym) ((void *)&sym + kvm_ksym_shift)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#if __GNUC__ > 4
#define kvm_ksym_shift (PAGE_OFFSET - KIMAGE_VADDR)
#else
/*
* GCC versions 4.9 and older will fold the constant below into the addend of
* the reference to 'sym' above if kvm_ksym_shift is declared static or if the
* constant is used directly. However, since we use the small code model for
* the core kernel, the reference to 'sym' will be emitted as a adrp/add pair,
* with a +/- 4 GB range, resulting in linker relocation errors if the shift
* is sufficiently large. So prevent the compiler from folding the shift into
* the addend, by making the shift a variable with external linkage.
*/
__weak u64 kvm_ksym_shift = PAGE_OFFSET - KIMAGE_VADDR;
#endif
struct kvm; struct kvm;
struct kvm_vcpu; struct kvm_vcpu;
......
...@@ -307,7 +307,7 @@ static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm, ...@@ -307,7 +307,7 @@ static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
struct kvm_vcpu *kvm_arm_get_running_vcpu(void); struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void); struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void);
u64 kvm_call_hyp(void *hypfn, ...); u64 __kvm_call_hyp(void *hypfn, ...);
void force_vm_exit(const cpumask_t *mask); void force_vm_exit(const cpumask_t *mask);
void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot); void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
...@@ -328,7 +328,7 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr, ...@@ -328,7 +328,7 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
* Call initialization code, and switch to the full blown * Call initialization code, and switch to the full blown
* HYP code. * HYP code.
*/ */
kvm_call_hyp((void *)boot_pgd_ptr, pgd_ptr, __kvm_call_hyp((void *)boot_pgd_ptr, pgd_ptr,
hyp_stack_ptr, vector_ptr); hyp_stack_ptr, vector_ptr);
} }
...@@ -343,4 +343,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); ...@@ -343,4 +343,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu); void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu);
#define kvm_call_hyp(f, ...) __kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__)
#endif /* __ARM64_KVM_HOST_H__ */ #endif /* __ARM64_KVM_HOST_H__ */
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <asm/assembler.h> #include <asm/assembler.h>
/* /*
* u64 kvm_call_hyp(void *hypfn, ...); * u64 __kvm_call_hyp(void *hypfn, ...);
* *
* This is not really a variadic function in the classic C-way and care must * This is not really a variadic function in the classic C-way and care must
* be taken when calling this to ensure parameters are passed in registers * be taken when calling this to ensure parameters are passed in registers
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* used to implement __hyp_get_vectors in the same way as in * used to implement __hyp_get_vectors in the same way as in
* arch/arm64/kernel/hyp_stub.S. * arch/arm64/kernel/hyp_stub.S.
*/ */
ENTRY(kvm_call_hyp) ENTRY(__kvm_call_hyp)
hvc #0 hvc #0
ret ret
ENDPROC(kvm_call_hyp) ENDPROC(__kvm_call_hyp)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment