root/arch/parisc/kernel/relocate_kernel.S
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/linkage.h>
#include <linux/kexec.h>

#include <asm/assembly.h>
#include <asm/asm-offsets.h>
#include <asm/page.h>
#include <asm/setup.h>
#include <asm/psw.h>

.level PA_ASM_LEVEL

.macro  kexec_param name
.align 8
ENTRY(kexec\()_\name)
#ifdef CONFIG_64BIT
        .dword 0
#else
        .word 0
#endif

ENTRY(kexec\()_\name\()_offset)
        .word kexec\()_\name - relocate_new_kernel
.endm

.text

/* args:
 * r26 - kimage->head
 * r25 - start address of kernel
 * r24 - physical address of relocate code
 */

ENTRY_CFI(relocate_new_kernel)
0:      copy    %arg1, %rp
        /* disable I and Q bit, so we are allowed to execute RFI */
        rsm PSW_SM_I, %r0
        nop
        nop
        nop
        nop
        nop
        nop
        nop

        rsm PSW_SM_Q, %r0
        nop
        nop
        nop
        nop
        nop
        nop
        nop

        /*
         * After return-from-interrupt, we want to run without Code/Data
         * translation enabled just like on a normal boot.
         */

        /* calculate new physical execution address */
        ldo     1f-0b(%arg2), %r1
        mtctl   %r0, %cr17 /* IIASQ */
        mtctl   %r0, %cr17 /* IIASQ */
        mtctl   %r1, %cr18 /* IIAOQ */
        ldo     4(%r1),%r1
        mtctl   %r1, %cr18 /* IIAOQ */
#ifdef CONFIG_64BIT
        depdi,z 1, PSW_W_BIT, 1, %r1
        mtctl   %r1, %cr22 /* IPSW */
#else
        mtctl   %r0, %cr22 /* IPSW */
#endif
        /* lets go... */
        rfi
1:      nop
        nop

.Lloop:
        LDREG,ma        REG_SZ(%arg0), %r3
        /* If crash kernel, no copy needed */
        cmpib,COND(=),n 0,%r3,boot

        bb,<,n          %r3, 31 - IND_DONE_BIT, boot
        bb,>=,n         %r3, 31 - IND_INDIRECTION_BIT, .Lnotind
        /* indirection, load and restart */
        movb            %r3, %arg0, .Lloop
        depi            0, 31, PAGE_SHIFT, %arg0

.Lnotind:
        bb,>=,n         %r3, 31 - IND_DESTINATION_BIT, .Lnotdest
        b               .Lloop
        copy            %r3, %r20

.Lnotdest:
        bb,>=           %r3, 31 - IND_SOURCE_BIT, .Lloop
        depi            0, 31, PAGE_SHIFT, %r3
        copy            %r3, %r21

        /* copy page */
        copy            %r0, %r18
        zdepi           1, 31 - PAGE_SHIFT, 1, %r18
        add             %r20, %r18, %r17

        depi            0, 31, PAGE_SHIFT, %r20
.Lcopy:
        copy            %r20, %r12
        LDREG,ma        REG_SZ(%r21), %r8
        LDREG,ma        REG_SZ(%r21), %r9
        LDREG,ma        REG_SZ(%r21), %r10
        LDREG,ma        REG_SZ(%r21), %r11
        STREG,ma        %r8, REG_SZ(%r20)
        STREG,ma        %r9, REG_SZ(%r20)
        STREG,ma        %r10, REG_SZ(%r20)
        STREG,ma        %r11, REG_SZ(%r20)

#ifndef CONFIG_64BIT
        LDREG,ma        REG_SZ(%r21), %r8
        LDREG,ma        REG_SZ(%r21), %r9
        LDREG,ma        REG_SZ(%r21), %r10
        LDREG,ma        REG_SZ(%r21), %r11
        STREG,ma        %r8, REG_SZ(%r20)
        STREG,ma        %r9, REG_SZ(%r20)
        STREG,ma        %r10, REG_SZ(%r20)
        STREG,ma        %r11, REG_SZ(%r20)
#endif

        fdc             %r0(%r12)
        cmpb,COND(<<)   %r20,%r17,.Lcopy
        fic             (%sr4, %r12)
        b,n             .Lloop

boot:
        mtctl   %r0, %cr15

        LDREG   kexec_free_mem-0b(%arg2), %arg0
        LDREG   kexec_cmdline-0b(%arg2), %arg1
        LDREG   kexec_initrd_end-0b(%arg2), %arg3
        LDREG   kexec_initrd_start-0b(%arg2), %arg2
        bv,n %r0(%rp)

ENDPROC_CFI(relocate_new_kernel);

ENTRY(relocate_new_kernel_size)
       .word relocate_new_kernel_size - relocate_new_kernel

kexec_param cmdline
kexec_param initrd_start
kexec_param initrd_end
kexec_param free_mem