Commit e7ae2ecd authored by Marc Zyngier's avatar Marc Zyngier
Browse files

Merge branch 'kvm-arm64/hyp-reloc' into kvmarm-master/next



Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents c5db649f bc93763f
Loading
Loading
Loading
Loading
+27 −2
Original line number Diff line number Diff line
@@ -7,6 +7,9 @@
#ifndef __ARM64_HYP_IMAGE_H__
#define __ARM64_HYP_IMAGE_H__

#define __HYP_CONCAT(a, b)	a ## b
#define HYP_CONCAT(a, b)	__HYP_CONCAT(a, b)

/*
 * KVM nVHE code has its own symbol namespace prefixed with __kvm_nvhe_,
 * to separate it from the kernel proper.
@@ -21,9 +24,31 @@
 */
#define HYP_SECTION_NAME(NAME)	.hyp##NAME

/* Symbol defined at the beginning of each hyp section. */
#define HYP_SECTION_SYMBOL_NAME(NAME) \
	HYP_CONCAT(__hyp_section_, HYP_SECTION_NAME(NAME))

/*
 * Helper to generate linker script statements starting a hyp section.
 *
 * A symbol with a well-known name is defined at the first byte. This
 * is used as a base for hyp relocations (see gen-hyprel.c). It must
 * be defined inside the section so the linker of `vmlinux` cannot
 * separate it from the section data.
 */
#define BEGIN_HYP_SECTION(NAME)				\
	HYP_SECTION_NAME(NAME) : {			\
		HYP_SECTION_SYMBOL_NAME(NAME) = .;

/* Helper to generate linker script statements ending a hyp section. */
#define END_HYP_SECTION					\
	}

/* Defines an ELF hyp section from input section @NAME and its subsections. */
#define HYP_SECTION(NAME)			\
	HYP_SECTION_NAME(NAME) : { *(NAME NAME##.*) }
	BEGIN_HYP_SECTION(NAME)			\
		*(NAME NAME##.*)		\
	END_HYP_SECTION

/*
 * Defines a linker script alias of a kernel-proper symbol referenced by
+0 −26
Original line number Diff line number Diff line
@@ -199,32 +199,6 @@ extern void __vgic_v3_init_lrs(void);

extern u32 __kvm_get_mdcr_el2(void);

#if defined(GCC_VERSION) && GCC_VERSION < 50000
#define SYM_CONSTRAINT	"i"
#else
#define SYM_CONSTRAINT	"S"
#endif

/*
 * Obtain the PC-relative address of a kernel symbol
 * s: symbol
 *
 * The goal of this macro is to return a symbol's address based on a
 * PC-relative computation, as opposed to a loading the VA from a
 * constant pool or something similar. This works well for HYP, as an
 * absolute VA is guaranteed to be wrong. Only use this if trying to
 * obtain the address of a symbol (i.e. not something you obtained by
 * following a pointer).
 */
#define hyp_symbol_addr(s)						\
	({								\
		typeof(s) *addr;					\
		asm("adrp	%0, %1\n"				\
		    "add	%0, %0, :lo12:%1\n"			\
		    : "=r" (addr) : SYM_CONSTRAINT (&s));		\
		addr;							\
	})

#define __KVM_EXTABLE(from, to)						\
	"	.pushsection	__kvm_ex_table, \"a\"\n"		\
	"	.align		3\n"					\
+17 −44
Original line number Diff line number Diff line
@@ -73,49 +73,39 @@ alternative_cb_end
.endm

/*
 * Convert a kernel image address to a PA
 * reg: kernel address to be converted in place
 * Convert a hypervisor VA to a PA
 * reg: hypervisor address to be converted in place
 * tmp: temporary register
 *
 * The actual code generation takes place in kvm_get_kimage_voffset, and
 * the instructions below are only there to reserve the space and
 * perform the register allocation (kvm_get_kimage_voffset uses the
 * specific registers encoded in the instructions).
 */
.macro kimg_pa reg, tmp
alternative_cb kvm_get_kimage_voffset
	movz	\tmp, #0
	movk	\tmp, #0, lsl #16
	movk	\tmp, #0, lsl #32
	movk	\tmp, #0, lsl #48
alternative_cb_end

	/* reg = __pa(reg) */
	sub	\reg, \reg, \tmp
.macro hyp_pa reg, tmp
	ldr_l	\tmp, hyp_physvirt_offset
	add	\reg, \reg, \tmp
.endm

/*
 * Convert a kernel image address to a hyp VA
 * reg: kernel address to be converted in place
 * Convert a hypervisor VA to a kernel image address
 * reg: hypervisor address to be converted in place
 * tmp: temporary register
 *
 * The actual code generation takes place in kvm_get_kimage_voffset, and
 * the instructions below are only there to reserve the space and
 * perform the register allocation (kvm_update_kimg_phys_offset uses the
 * perform the register allocation (kvm_get_kimage_voffset uses the
 * specific registers encoded in the instructions).
 */
.macro kimg_hyp_va reg, tmp
alternative_cb kvm_update_kimg_phys_offset
.macro hyp_kimg_va reg, tmp
	/* Convert hyp VA -> PA. */
	hyp_pa	\reg, \tmp

	/* Load kimage_voffset. */
alternative_cb kvm_get_kimage_voffset
	movz	\tmp, #0
	movk	\tmp, #0, lsl #16
	movk	\tmp, #0, lsl #32
	movk	\tmp, #0, lsl #48
alternative_cb_end

	sub	\reg, \reg, \tmp
	mov_q	\tmp, PAGE_OFFSET
	orr	\reg, \reg, \tmp
	kern_hyp_va \reg
	/* Convert PA -> kimg VA. */
	add	\reg, \reg, \tmp
.endm

#else
@@ -129,6 +119,7 @@ alternative_cb_end
void kvm_update_va_mask(struct alt_instr *alt,
			__le32 *origptr, __le32 *updptr, int nr_inst);
void kvm_compute_layout(void);
void kvm_apply_hyp_relocations(void);

static __always_inline unsigned long __kern_hyp_va(unsigned long v)
{
@@ -144,24 +135,6 @@ static __always_inline unsigned long __kern_hyp_va(unsigned long v)

#define kern_hyp_va(v) 	((typeof(v))(__kern_hyp_va((unsigned long)(v))))

static __always_inline unsigned long __kimg_hyp_va(unsigned long v)
{
	unsigned long offset;

	asm volatile(ALTERNATIVE_CB("movz %0, #0\n"
				    "movk %0, #0, lsl #16\n"
				    "movk %0, #0, lsl #32\n"
				    "movk %0, #0, lsl #48\n",
				    kvm_update_kimg_phys_offset)
		     : "=r" (offset));

	return __kern_hyp_va((v - offset) | PAGE_OFFSET);
}

#define kimg_fn_hyp_va(v) 	((typeof(*v))(__kimg_hyp_va((unsigned long)(v))))

#define kimg_fn_ptr(x)	(typeof(x) **)(x)

/*
 * We currently support using a VM-specified IPA size. For backward
 * compatibility, the default IPA size is fixed to 40bits.
+2 −1
Original line number Diff line number Diff line
@@ -11,7 +11,8 @@ extern char __alt_instructions[], __alt_instructions_end[];
extern char __hibernate_exit_text_start[], __hibernate_exit_text_end[];
extern char __hyp_idmap_text_start[], __hyp_idmap_text_end[];
extern char __hyp_text_start[], __hyp_text_end[];
extern char __hyp_data_ro_after_init_start[], __hyp_data_ro_after_init_end[];
extern char __hyp_rodata_start[], __hyp_rodata_end[];
extern char __hyp_reloc_begin[], __hyp_reloc_end[];
extern char __idmap_text_start[], __idmap_text_end[];
extern char __initdata_begin[], __initdata_end[];
extern char __inittext_begin[], __inittext_end[];
+0 −1
Original line number Diff line number Diff line
@@ -64,7 +64,6 @@ __efistub__ctype = _ctype;
/* 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. */
Loading