| /* 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 |