root/arch/arm/kernel/relocate_kernel.S
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * relocate_kernel.S - put the kernel image in place to boot
 */

#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/kexec.h>

        .align  3       /* not needed for this code, but keeps fncpy() happy */

ENTRY(relocate_new_kernel)

        adr     r7, relocate_new_kernel_end
        ldr     r0, [r7, #KEXEC_INDIR_PAGE]
        ldr     r1, [r7, #KEXEC_START_ADDR]

        /*
         * If there is no indirection page (we are doing crashdumps)
         * skip any relocation.
         */
        cmp     r0, #0
        beq     2f

0:      /* top, read another word for the indirection page */
        ldr     r3, [r0],#4

        /* Is it a destination page. Put destination address to r4 */
        tst     r3,#1
        beq     1f
        bic     r4,r3,#1
        b       0b
1:
        /* Is it an indirection page */
        tst     r3,#2
        beq     1f
        bic     r0,r3,#2
        b       0b
1:

        /* are we done ? */
        tst     r3,#4
        beq     1f
        b       2f

1:
        /* is it source ? */
        tst     r3,#8
        beq     0b
        bic r3,r3,#8
        mov r6,#1024
9:
        ldr r5,[r3],#4
        str r5,[r4],#4
        subs r6,r6,#1
        bne 9b
        b 0b

2:
        /* Jump to relocated kernel */
        mov     lr, r1
        mov     r0, #0
        ldr     r1, [r7, #KEXEC_MACH_TYPE]
        ldr     r2, [r7, #KEXEC_R2]
 ARM(   ret     lr      )
 THUMB( bx      lr      )

ENDPROC(relocate_new_kernel)

        .align  3
relocate_new_kernel_end:

        .globl relocate_new_kernel_size
relocate_new_kernel_size:
        .long relocate_new_kernel_end - relocate_new_kernel