| /* |
| * relocate_kernel.S - put the kernel image in place to boot |
| */ |
| |
| #include <asm/kexec.h> |
| |
| .globl relocate_new_kernel |
| relocate_new_kernel: |
| |
| /* Move boot params back to where the kernel expects them */ |
| |
| ldr r0,kexec_boot_params_address |
| teq r0,#0 |
| beq 8f |
| |
| ldr r1,kexec_boot_params_copy |
| mov r6,#KEXEC_BOOT_PARAMS_SIZE/4 |
| 7: |
| ldr r5,[r1],#4 |
| str r5,[r0],#4 |
| subs r6,r6,#1 |
| bne 7b |
| |
| 8: |
| /* Boot params moved, now go on with the kernel */ |
| |
| ldr r0,kexec_indirection_page |
| ldr r1,kexec_start_address |
| |
| |
| 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,0 |
| beq 1f |
| bic r4,r3,#1 |
| b 0b |
| 1: |
| /* Is it an indirection page */ |
| tst r3,#2,0 |
| beq 1f |
| bic r0,r3,#2 |
| b 0b |
| 1: |
| |
| /* are we done ? */ |
| tst r3,#4,0 |
| beq 1f |
| b 2f |
| |
| 1: |
| /* is it source ? */ |
| tst r3,#8,0 |
| 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,kexec_mach_type |
| ldr r2,kexec_boot_params_address |
| mov pc,lr |
| |
| .globl kexec_start_address |
| kexec_start_address: |
| .long 0x0 |
| |
| .globl kexec_indirection_page |
| kexec_indirection_page: |
| .long 0x0 |
| |
| .globl kexec_mach_type |
| kexec_mach_type: |
| .long 0x0 |
| |
| /* phy addr where new kernel will expect to find boot params */ |
| .globl kexec_boot_params_address |
| kexec_boot_params_address: |
| .long 0x0 |
| |
| /* phy addr where old kernel put a copy of orig boot params */ |
| .globl kexec_boot_params_copy |
| kexec_boot_params_copy: |
| .long 0x0 |
| |
| relocate_new_kernel_end: |
| |
| .globl relocate_new_kernel_size |
| relocate_new_kernel_size: |
| .long relocate_new_kernel_end - relocate_new_kernel |
| |
| |