Commit 3744b528 authored by Pasha Tatashin's avatar Pasha Tatashin Committed by Will Deacon
Browse files

arm64: kexec: install a copy of the linear-map



To perform the kexec relocation with the MMU enabled, we need a copy
of the linear map.

Create one, and install it from the relocation code. This has to be done
from the assembly code as it will be idmapped with TTBR0. The kernel
runs in TTRB1, so can't use the break-before-make sequence on the mapping
it is executing from.

The makes no difference yet as the relocation code runs with the MMU
disabled.

Suggested-by: default avatarJames Morse <james.morse@arm.com>
Signed-off-by: default avatarPasha Tatashin <pasha.tatashin@soleen.com>
Acked-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/20210930143113.1502553-12-pasha.tatashin@soleen.com


Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 19a046f0
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -483,6 +483,25 @@ alternative_endif
	_cond_extable .Licache_op\@, \fixup
	.endm

/*
 * To prevent the possibility of old and new partial table walks being visible
 * in the tlb, switch the ttbr to a zero page when we invalidate the old
 * records. D4.7.1 'General TLB maintenance requirements' in ARM DDI 0487A.i
 * Even switching to our copied tables will cause a changed output address at
 * each stage of the walk.
 */
	.macro break_before_make_ttbr_switch zero_page, page_table, tmp, tmp2
	phys_to_ttbr \tmp, \zero_page
	msr	ttbr1_el1, \tmp
	isb
	tlbi	vmalle1
	dsb	nsh
	phys_to_ttbr \tmp, \page_table
	offset_ttbr1 \tmp, \tmp2
	msr	ttbr1_el1, \tmp
	isb
	.endm

/*
 * reset_pmuserenr_el0 - reset PMUSERENR_EL0 if PMUv3 present
 */
+2 −0
Original line number Diff line number Diff line
@@ -97,6 +97,8 @@ struct kimage_arch {
	phys_addr_t dtb_mem;
	phys_addr_t kern_reloc;
	phys_addr_t el2_vectors;
	phys_addr_t ttbr1;
	phys_addr_t zero_page;
};

#ifdef CONFIG_KEXEC_FILE
+2 −0
Original line number Diff line number Diff line
@@ -175,6 +175,8 @@ int main(void)
#ifdef CONFIG_KEXEC_CORE
  DEFINE(KIMAGE_ARCH_DTB_MEM,		offsetof(struct kimage, arch.dtb_mem));
  DEFINE(KIMAGE_ARCH_EL2_VECTORS,	offsetof(struct kimage, arch.el2_vectors));
  DEFINE(KIMAGE_ARCH_ZERO_PAGE,		offsetof(struct kimage, arch.zero_page));
  DEFINE(KIMAGE_ARCH_TTBR1,		offsetof(struct kimage, arch.ttbr1));
  DEFINE(KIMAGE_HEAD,			offsetof(struct kimage, head));
  DEFINE(KIMAGE_START,			offsetof(struct kimage, start));
  BLANK();
+0 −20
Original line number Diff line number Diff line
@@ -15,26 +15,6 @@
#include <asm/page.h>
#include <asm/virt.h>

/*
 * To prevent the possibility of old and new partial table walks being visible
 * in the tlb, switch the ttbr to a zero page when we invalidate the old
 * records. D4.7.1 'General TLB maintenance requirements' in ARM DDI 0487A.i
 * Even switching to our copied tables will cause a changed output address at
 * each stage of the walk.
 */
.macro break_before_make_ttbr_switch zero_page, page_table, tmp, tmp2
	phys_to_ttbr \tmp, \zero_page
	msr	ttbr1_el1, \tmp
	isb
	tlbi	vmalle1
	dsb	nsh
	phys_to_ttbr \tmp, \page_table
	offset_ttbr1 \tmp, \tmp2
	msr	ttbr1_el1, \tmp
	isb
.endm


/*
 * Resume from hibernate
 *
+14 −2
Original line number Diff line number Diff line
@@ -159,6 +159,8 @@ static void *kexec_page_alloc(void *arg)

int machine_kexec_post_load(struct kimage *kimage)
{
	int rc;
	pgd_t *trans_pgd;
	void *reloc_code = page_to_virt(kimage->control_code_page);
	long reloc_size;
	struct trans_pgd_info info = {
@@ -175,12 +177,22 @@ int machine_kexec_post_load(struct kimage *kimage)

	kimage->arch.el2_vectors = 0;
	if (is_hyp_nvhe()) {
		int rc = trans_pgd_copy_el2_vectors(&info,
		rc = trans_pgd_copy_el2_vectors(&info,
						&kimage->arch.el2_vectors);
		if (rc)
			return rc;
	}

	/* Create a copy of the linear map */
	trans_pgd = kexec_page_alloc(kimage);
	if (!trans_pgd)
		return -ENOMEM;
	rc = trans_pgd_create_copy(&info, &trans_pgd, PAGE_OFFSET, PAGE_END);
	if (rc)
		return rc;
	kimage->arch.ttbr1 = __pa(trans_pgd);
	kimage->arch.zero_page = __pa(empty_zero_page);

	reloc_size = __relocate_new_kernel_end - __relocate_new_kernel_start;
	memcpy(reloc_code, __relocate_new_kernel_start, reloc_size);
	kimage->arch.kern_reloc = __pa(reloc_code);
Loading