1/*
2 * relocate_kernel.S - put the kernel image in place to boot
3 * Copyright (C) 2002-2003 Eric Biederman  <ebiederm@xmission.com>
4 *
5 * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
6 *
7 * This source code is licensed under the GNU General Public License,
8 * Version 2.  See the file COPYING for more details.
9 */
10
11#include <asm/reg.h>
12#include <asm/ppc_asm.h>
13#include <asm/processor.h>
14
15#include <asm/kexec.h>
16
17#define PAGE_SIZE      4096 /* must be same value as in <asm/page.h> */
18
19	/*
20	 * Must be relocatable PIC code callable as a C function.
21	 */
22	.globl relocate_new_kernel
23relocate_new_kernel:
24	/* r3 = page_list   */
25	/* r4 = reboot_code_buffer */
26	/* r5 = start_address      */
27
28	li	r0, 0
29
30	/*
31	 * Set Machine Status Register to a known status,
32	 * switch the MMU off and jump to 1: in a single step.
33	 */
34
35	mr	r8, r0
36	ori     r8, r8, MSR_RI|MSR_ME
37	mtspr	SPRN_SRR1, r8
38	addi	r8, r4, 1f - relocate_new_kernel
39	mtspr	SPRN_SRR0, r8
40	sync
41	rfi
42
431:
44	/* from this point address translation is turned off */
45	/* and interrupts are disabled */
46
47	/* set a new stack at the bottom of our page... */
48	/* (not really needed now) */
49	addi	r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
50	stw	r0, 0(r1)
51
52	/* Do the copies */
53	li	r6, 0 /* checksum */
54	mr	r0, r3
55	b	1f
56
570:	/* top, read another word for the indirection page */
58	lwzu	r0, 4(r3)
59
601:
61	/* is it a destination page? (r8) */
62	rlwinm.	r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
63	beq	2f
64
65	rlwinm	r8, r0, 0, 0, 19 /* clear kexec flags, page align */
66	b	0b
67
682:	/* is it an indirection page? (r3) */
69	rlwinm.	r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
70	beq	2f
71
72	rlwinm	r3, r0, 0, 0, 19 /* clear kexec flags, page align */
73	subi	r3, r3, 4
74	b	0b
75
762:	/* are we done? */
77	rlwinm.	r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
78	beq	2f
79	b	3f
80
812:	/* is it a source page? (r9) */
82	rlwinm.	r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
83	beq	0b
84
85	rlwinm	r9, r0, 0, 0, 19 /* clear kexec flags, page align */
86
87	li	r7, PAGE_SIZE / 4
88	mtctr   r7
89	subi    r9, r9, 4
90	subi    r8, r8, 4
919:
92	lwzu    r0, 4(r9)  /* do the copy */
93	xor	r6, r6, r0
94	stwu    r0, 4(r8)
95	dcbst	0, r8
96	sync
97	icbi	0, r8
98	bdnz    9b
99
100	addi    r9, r9, 4
101	addi    r8, r8, 4
102	b	0b
103
1043:
105
106	/* To be certain of avoiding problems with self-modifying code
107	 * execute a serializing instruction here.
108	 */
109	isync
110	sync
111
112	/* jump to the entry point, usually the setup routine */
113	mtlr	r5
114	blrl
115
1161:	b	1b
117
118relocate_new_kernel_end:
119
120	.globl relocate_new_kernel_size
121relocate_new_kernel_size:
122	.long relocate_new_kernel_end - relocate_new_kernel
123