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