ramips: add code for relocating a kernel to the right place
[openwrt/staging/dedeckeh.git] / target / linux / ramips / image / relocate / head.S
1 /*
2 * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
3 *
4 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
5 *
6 * Some parts of this code was based on the OpenWrt specific lzma-loader
7 * for the BCM47xx and ADM5120 based boards:
8 * Copyright (C) 2004 Manuel Novoa III (mjn3@codepoet.org)
9 * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License version 2 as published
13 * by the Free Software Foundation.
14 */
15
16 #include <asm/asm.h>
17 #include <asm/regdef.h>
18 #include "cp0regdef.h"
19 #include "cacheops.h"
20
21 #define KSEG0 0x80000000
22
23 .macro ehb
24 sll zero, 3
25 .endm
26
27 .macro reset
28 li t0, 0xbe000034
29 lw t1, 0(t0)
30 ori t1, 1
31 sw t1, 0(t0)
32 .endm
33
34 .text
35
36 LEAF(startup)
37 .set noreorder
38 .set mips32
39
40 .fill 0x10000
41
42 mtc0 zero, CP0_WATCHLO # clear watch registers
43 mtc0 zero, CP0_WATCHHI
44 mtc0 zero, CP0_CAUSE # clear before writing status register
45
46 mfc0 t0, CP0_STATUS
47 li t1, 0x1000001f
48 or t0, t1
49 xori t0, 0x1f
50 mtc0 t0, CP0_STATUS
51 ehb
52
53 mtc0 zero, CP0_COUNT
54 mtc0 zero, CP0_COMPARE
55 ehb
56
57 la t0, __reloc_label # get linked address of label
58 bal __reloc_label # branch and link to label to
59 nop # get actual address
60 __reloc_label:
61 subu t0, ra, t0 # get reloc_delta
62
63 /* Copy our code to the right place */
64 la t1, _code_start # get linked address of _code_start
65 la t2, _code_end # get linked address of _code_end
66
67 addu t4, t2, t0 # calculate actual address of _code_end
68 lw t5, 0(t4) # get extra data size
69
70 add t2, t5
71 add t2, 4
72
73 add t0, t1 # calculate actual address of _code_start
74
75 __reloc_copy:
76 lw t3, 0(t0)
77 sw t3, 0(t1)
78 add t1, 4
79 blt t1, t2, __reloc_copy
80 add t0, 4
81
82 /* flush cache */
83 la t0, _code_start
84 la t1, _code_end
85
86 li t2, ~(CONFIG_CACHELINE_SIZE - 1)
87 and t0, t2
88 and t1, t2
89 li t2, CONFIG_CACHELINE_SIZE
90
91 b __flush_check
92 nop
93
94 __flush_line:
95 cache Hit_Writeback_Inv_D, 0(t0)
96 cache Hit_Invalidate_I, 0(t0)
97 add t0, t2
98
99 __flush_check:
100 bne t0, t1, __flush_line
101 nop
102
103 sync
104
105 la t0, __reloc_back
106 j t0
107 nop
108
109 __reloc_back:
110 la t0, _code_end
111 add t0, 4
112
113 addu t1, t0, t5
114
115 li t2, KERNEL_ADDR
116
117 __kernel_copy:
118 lw t3, 0(t0)
119 sw t3, 0(t2)
120 add t0, 4
121 blt t0, t1, __kernel_copy
122 add t2, 4
123
124 /* flush cache */
125 li t0, KERNEL_ADDR
126 addu t1, t0, t5
127
128 add t1, CONFIG_CACHELINE_SIZE - 1
129 li t2, ~(CONFIG_CACHELINE_SIZE - 1)
130 and t0, t2
131 and t1, t2
132 li t2, CONFIG_CACHELINE_SIZE
133
134 b __kernel_flush_check
135 nop
136
137 __kernel_flush_line:
138 cache Hit_Writeback_Inv_D, 0(t0)
139 cache Hit_Invalidate_I, 0(t0)
140 add t0, t2
141
142 __kernel_flush_check:
143 bne t0, t1, __kernel_flush_line
144 nop
145
146 sync
147
148 li t0, KERNEL_ADDR
149 jr t0
150 nop
151
152 .set reorder
153 END(startup)