19a046f07c
Currently, relocation code declares start and end variables which are used to compute its size. The better way to do this is to use ld script, and put relocation function in its own section. 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-11-pasha.tatashin@soleen.com Signed-off-by: Will Deacon <will@kernel.org>
81 lines
2.4 KiB
ArmAsm
81 lines
2.4 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* kexec for arm64
|
|
*
|
|
* Copyright (C) Linaro.
|
|
* Copyright (C) Huawei Futurewei Technologies.
|
|
*/
|
|
|
|
#include <linux/kexec.h>
|
|
#include <linux/linkage.h>
|
|
|
|
#include <asm/assembler.h>
|
|
#include <asm/kexec.h>
|
|
#include <asm/page.h>
|
|
#include <asm/sysreg.h>
|
|
#include <asm/virt.h>
|
|
|
|
.section ".kexec_relocate.text", "ax"
|
|
/*
|
|
* arm64_relocate_new_kernel - Put a 2nd stage image in place and boot it.
|
|
*
|
|
* The memory that the old kernel occupies may be overwritten when copying the
|
|
* new image to its final location. To assure that the
|
|
* arm64_relocate_new_kernel routine which does that copy is not overwritten,
|
|
* all code and data needed by arm64_relocate_new_kernel must be between the
|
|
* symbols arm64_relocate_new_kernel and arm64_relocate_new_kernel_end. The
|
|
* machine_kexec() routine will copy arm64_relocate_new_kernel to the kexec
|
|
* safe memory that has been set up to be preserved during the copy operation.
|
|
*/
|
|
SYM_CODE_START(arm64_relocate_new_kernel)
|
|
/* Setup the list loop variables. */
|
|
ldr x16, [x0, #KIMAGE_HEAD] /* x16 = kimage_head */
|
|
mov x14, xzr /* x14 = entry ptr */
|
|
mov x13, xzr /* x13 = copy dest */
|
|
raw_dcache_line_size x15, x1 /* x15 = dcache line size */
|
|
.Lloop:
|
|
and x12, x16, PAGE_MASK /* x12 = addr */
|
|
|
|
/* Test the entry flags. */
|
|
.Ltest_source:
|
|
tbz x16, IND_SOURCE_BIT, .Ltest_indirection
|
|
|
|
/* Invalidate dest page to PoC. */
|
|
mov x2, x13
|
|
add x1, x2, #PAGE_SIZE
|
|
dcache_by_myline_op ivac, sy, x2, x1, x15, x20
|
|
copy_page x13, x12, x1, x2, x3, x4, x5, x6, x7, x8
|
|
b .Lnext
|
|
.Ltest_indirection:
|
|
tbz x16, IND_INDIRECTION_BIT, .Ltest_destination
|
|
mov x14, x12 /* ptr = addr */
|
|
b .Lnext
|
|
.Ltest_destination:
|
|
tbz x16, IND_DESTINATION_BIT, .Lnext
|
|
mov x13, x12 /* dest = addr */
|
|
.Lnext:
|
|
ldr x16, [x14], #8 /* entry = *ptr++ */
|
|
tbz x16, IND_DONE_BIT, .Lloop /* while (!(entry & DONE)) */
|
|
/* wait for writes from copy_page to finish */
|
|
dsb nsh
|
|
ic iallu
|
|
dsb nsh
|
|
isb
|
|
|
|
/* Start new image. */
|
|
ldr x1, [x0, #KIMAGE_ARCH_EL2_VECTORS] /* relocation start */
|
|
cbz x1, .Lel1
|
|
ldr x1, [x0, #KIMAGE_START] /* relocation start */
|
|
ldr x2, [x0, #KIMAGE_ARCH_DTB_MEM] /* dtb address */
|
|
mov x3, xzr
|
|
mov x4, xzr
|
|
mov x0, #HVC_SOFT_RESTART
|
|
hvc #0 /* Jumps from el2 */
|
|
.Lel1:
|
|
ldr x4, [x0, #KIMAGE_START] /* relocation start */
|
|
ldr x0, [x0, #KIMAGE_ARCH_DTB_MEM] /* dtb address */
|
|
mov x2, xzr
|
|
mov x3, xzr
|
|
br x4 /* Jumps from el1 */
|
|
SYM_CODE_END(arm64_relocate_new_kernel)
|