1/*
2 * (C) Copyright 2011-2012
3 * Pali Rohár <pali.rohar@gmail.com>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <config.h>
25
26relocaddr:		/* address of this relocaddr section after coping */
27	.word .		/* address of section (calculated at compile time) */
28
29startaddr:		/* address of u-boot after copying */
30	.word CONFIG_SYS_TEXT_BASE
31
32kernaddr:		/* address of kernel after copying */
33	.word KERNEL_ADDRESS
34
35kernsize:		/* maximal size of kernel image */
36	.word KERNEL_MAXSIZE
37
38kernoffs:		/* offset of kernel image in loaded u-boot */
39	.word KERNEL_OFFSET
40
41imagesize:		/* maximal size of image */
42	.word IMAGE_MAXSIZE
43
44ih_magic:		/* IH_MAGIC in big endian from include/image.h */
45	.word 0x56190527
46
47/*
48 * Routine: save_boot_params (called after reset from start.S)
49 * Description: Copy attached kernel to address KERNEL_ADDRESS
50 *              Copy u-boot to address CONFIG_SYS_TEXT_BASE
51 *              Return to copied u-boot address
52 */
53
54.global save_boot_params
55save_boot_params:
56
57
58/* Copy valid attached kernel to address KERNEL_ADDRESS */
59
60copy_kernel_start:
61	adr	r0, relocaddr	/* r0 - address of section relocaddr */
62	ldr	r1, relocaddr	/* r1 - address of relocaddr after relocation */
63	cmp	r0, r1
64
65	/* r4 - calculated offset */
66	subhi	r4, r0, r1
67	sublo	r4, r1, r0
68
69	/* r0 - start of kernel before */
70	ldr	r0, startaddr
71	addhi	r0, r0, r4
72	sublo	r0, r0, r4
73	ldr	r1, kernoffs
74	add	r0, r0, r1
75
76	/* r3 - start of kernel after */
77	ldr	r3, kernaddr
78
79	/* r2 - end of kernel after */
80	ldr	r1, kernsize
81	add	r2, r3, r1
82
83	/* r1 - end of kernel before */
84	add	r1, r0, r1
85
86	/* remove header in target kernel */
87	mov	r5, #0
88	str	r5, [r3]
89
90	/* check for valid kernel uImage */
91	ldr	r4, [r0]	/* r4 - 4 bytes header of kernel */
92	ldr	r5, ih_magic	/* r5 - IH_MAGIC */
93	cmp	r4, r5
94	bne	copy_kernel_end	/* skip if invalid image */
95
96copy_kernel_loop:
97	ldmdb	r1!, {r3 - r10}
98	stmdb	r2!, {r3 - r10}
99	cmp	r1, r0
100	bhi	copy_kernel_loop
101
102copy_kernel_end:
103	mov	r5, #0
104	str	r5, [r0]	/* remove 4 bytes header of kernel */
105
106
107/* Fix u-boot code */
108
109fix_start:
110	adr	r0, relocaddr	/* r0 - address of section relocaddr */
111	ldr	r1, relocaddr	/* r1 - address of relocaddr after relocation */
112	cmp	r0, r1
113
114	beq	copy_uboot_end	/* skip if u-boot is on correct address */
115
116	/* r5 - calculated offset */
117	subhi	r5, r0, r1
118	sublo	r5, r1, r0
119
120	/* r6 - maximal u-boot size */
121	ldr	r6, imagesize
122
123	/* fix return address */
124	subhi	lr, lr, r5
125	addlo	lr, lr, r5
126
127	/* r1 - start of u-boot after */
128	ldr	r1, startaddr
129
130	/* r0 - start of u-boot before */
131	addhi	r0, r1, r5
132	sublo	r0, r1, r5
133
134	/* check if we need to move uboot copy code before calling it */
135	cmp	r5, r6
136	bhi	copy_uboot_start /* now coping u-boot code directly is safe */
137
138
139copy_code_start:
140	/* r0 - start of u-boot before */
141	/* r1 - start of u-boot after */
142	/* r6 - maximal u-boot size */
143
144	/* r7 - maximal kernel size */
145	ldr	r7, kernsize
146
147	/* r4 - end of kernel before */
148	add	r4, r0, r6
149	add	r4, r4, r7
150
151	/* r5 - end of u-boot after */
152	ldr	r5, startaddr
153	add	r5, r5, r6
154
155	/* r2 - start of loop code after */
156	cmp	r4, r5		/* higher address (r4 or r5) */
157	movhs	r2, r4
158	movlo	r2, r5
159
160	/* r3 - end of loop code before */
161	adr	r3, end
162
163	/* r4 - end of loop code after */
164	adr	r4, copy_uboot_start
165	sub	r4, r3, r4
166	add	r4, r2, r4
167
168copy_code_loop:
169	ldmdb	r3!, {r7 - r10}
170	stmdb	r4!, {r7 - r10}
171	cmp	r4, r2
172	bhi	copy_code_loop
173
174copy_code_end:
175	mov	pc, r2
176
177
178/* Copy u-boot to address CONFIG_SYS_TEXT_BASE */
179
180copy_uboot_start:
181	/* r0 - start of u-boot before */
182	/* r1 - start of u-boot after */
183	/* r6 - maximal u-boot size */
184
185	/* r2 - end of u-boot after */
186	add	r2, r1, r6
187
188	/* condition for copying from left to right */
189	cmp	r0, r1
190	addlo	r1, r0, r6	/* r1 - end of u-boot before */
191	blo	copy_uboot_loop_right
192
193copy_uboot_loop_left:
194	ldmia	r0!, {r3 - r10}
195	stmia	r1!, {r3 - r10}
196	cmp	r1, r2
197	blo	copy_uboot_loop_left
198	b	copy_uboot_end
199
200copy_uboot_loop_right:
201	ldmdb	r1!, {r3 - r10}
202	stmdb	r2!, {r3 - r10}
203	cmp	r1, r0
204	bhi	copy_uboot_loop_right
205
206copy_uboot_end:
207	bx	lr
208
209end:
210