ramips: add code for relocating a kernel to the right place
[15.05/openwrt.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)