Skip to content

Commit

Permalink
arm64: kexec: configure EL2 vectors for kexec
Browse files Browse the repository at this point in the history
If we have a EL2 mode without VHE, the EL2 vectors are needed in order
to switch to EL2 and jump to new world with hypervisor privileges.

In preparation to MMU enabled relocation, configure our EL2 table now.

Kexec uses #HVC_SOFT_RESTART to branch to the new world, so extend
el1_sync vector that is provided by trans_pgd_copy_el2_vectors() to
support this case.

Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/20210930143113.1502553-9-pasha.tatashin@soleen.com
Signed-off-by: Will Deacon <will@kernel.org>
  • Loading branch information
Pasha Tatashin authored and Will Deacon committed Oct 1, 2021
1 parent 878fdbd commit 08eae0e
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 2 deletions.
2 changes: 1 addition & 1 deletion arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1135,7 +1135,7 @@ config CRASH_DUMP

config TRANS_TABLE
def_bool y
depends on HIBERNATION
depends on HIBERNATION || KEXEC_CORE

config XEN_DOM0
def_bool y
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/include/asm/kexec.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ struct kimage_arch {
void *dtb;
phys_addr_t dtb_mem;
phys_addr_t kern_reloc;
phys_addr_t el2_vectors;
};

#ifdef CONFIG_KEXEC_FILE
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ int main(void)
#endif
#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_HEAD, offsetof(struct kimage, head));
DEFINE(KIMAGE_START, offsetof(struct kimage, start));
BLANK();
Expand Down
31 changes: 31 additions & 0 deletions arch/arm64/kernel/machine_kexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <asm/mmu.h>
#include <asm/mmu_context.h>
#include <asm/page.h>
#include <asm/trans_pgd.h>

#include "cpu-reset.h"

Expand All @@ -43,7 +44,9 @@ static void _kexec_image_info(const char *func, int line,
pr_debug(" start: %lx\n", kimage->start);
pr_debug(" head: %lx\n", kimage->head);
pr_debug(" nr_segments: %lu\n", kimage->nr_segments);
pr_debug(" dtb_mem: %pa\n", &kimage->arch.dtb_mem);
pr_debug(" kern_reloc: %pa\n", &kimage->arch.kern_reloc);
pr_debug(" el2_vectors: %pa\n", &kimage->arch.el2_vectors);

for (i = 0; i < kimage->nr_segments; i++) {
pr_debug(" segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n",
Expand Down Expand Up @@ -143,9 +146,27 @@ static void kexec_segment_flush(const struct kimage *kimage)
}
}

/* Allocates pages for kexec page table */
static void *kexec_page_alloc(void *arg)
{
struct kimage *kimage = (struct kimage *)arg;
struct page *page = kimage_alloc_control_pages(kimage, 0);

if (!page)
return NULL;

memset(page_address(page), 0, PAGE_SIZE);

return page_address(page);
}

int machine_kexec_post_load(struct kimage *kimage)
{
void *reloc_code = page_to_virt(kimage->control_code_page);
struct trans_pgd_info info = {
.trans_alloc_page = kexec_page_alloc,
.trans_alloc_arg = kimage,
};

/* If in place, relocation is not used, only flush next kernel */
if (kimage->head & IND_DONE) {
Expand All @@ -154,6 +175,14 @@ int machine_kexec_post_load(struct kimage *kimage)
return 0;
}

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

memcpy(reloc_code, arm64_relocate_new_kernel,
arm64_relocate_new_kernel_size);
kimage->arch.kern_reloc = __pa(reloc_code);
Expand Down Expand Up @@ -209,6 +238,8 @@ void machine_kexec(struct kimage *kimage)
restart(is_hyp_nvhe(), kimage->start, kimage->arch.dtb_mem,
0, 0);
} else {
if (is_hyp_nvhe())
__hyp_set_vectors(kimage->arch.el2_vectors);
cpu_soft_restart(kimage->arch.kern_reloc, virt_to_phys(kimage),
0, 0);
}
Expand Down
9 changes: 8 additions & 1 deletion arch/arm64/mm/trans_pgd-asm.S
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ SYM_CODE_START_LOCAL(el1_sync)
msr vbar_el2, x1
mov x0, xzr
eret
1: /* Unexpected argument, set an error */
1: cmp x0, #HVC_SOFT_RESTART /* Called from kexec */
b.ne 2f
mov x0, x2
mov x2, x4
mov x4, x1
mov x1, x3
br x4
2: /* Unexpected argument, set an error */
mov_q x0, HVC_STUB_ERR
eret
SYM_CODE_END(el1_sync)
Expand Down

0 comments on commit 08eae0e

Please sign in to comment.