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


