]> git.sur5r.net Git - u-boot/blob - arch/mips/cpu/xburst/start.S
MIPS: add dynamic relocation support
[u-boot] / arch / mips / cpu / xburst / start.S
1 /*
2  *  Startup Code for MIPS32 XBURST CPU-core
3  *
4  *  Copyright (c) 2010 Xiangfu Liu <xiangfu@sharism.cc>
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24
25 #include <config.h>
26 #include <version.h>
27 #include <asm/regdef.h>
28 #include <asm/mipsregs.h>
29 #include <asm/addrspace.h>
30 #include <asm/cacheops.h>
31
32         .set noreorder
33
34         .globl _start
35         .text
36 _start:
37         /* Initialize $gp */
38         bal     1f
39          nop
40         .word   _gp
41 1:
42         lw      gp, 0(ra)
43
44         /* Set up temporary stack */
45         li      sp, CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_INIT_SP_OFFSET
46
47         la      t9, board_init_f
48         jr      t9
49          nop
50
51 /*
52  * void relocate_code (addr_sp, gd, addr_moni)
53  *
54  * This "function" does not return, instead it continues in RAM
55  * after relocating the monitor code.
56  *
57  * a0 = addr_sp
58  * a1 = gd
59  * a2 = destination address
60  */
61         .globl  relocate_code
62         .ent    relocate_code
63 relocate_code:
64         move    sp, a0                  # set new stack pointer
65
66         li      t0, CONFIG_SYS_MONITOR_BASE
67         sub     t6, a2, t0              # t6 <-- relocation offset
68
69         la      t3, in_ram
70         lw      t2, -12(t3)             # t2 <-- __image_copy_end
71         move    t1, a2
72
73         add     gp, t6                  # adjust gp
74
75         /*
76          * t0 = source address
77          * t1 = target address
78          * t2 = source end address
79          */
80 1:
81         lw      t3, 0(t0)
82         sw      t3, 0(t1)
83         addu    t0, 4
84         blt     t0, t2, 1b
85          addu   t1, 4
86
87         /* If caches were enabled, we would have to flush them here. */
88
89         /* flush d-cache */
90         li      t0, KSEG0
91         addi    t1, t0, CONFIG_SYS_DCACHE_SIZE
92 2:
93         cache   INDEX_WRITEBACK_INV_D, 0(t0)
94         bne     t0, t1, 2b
95          addi   t0, CONFIG_SYS_CACHELINE_SIZE
96
97         sync
98
99         /* flush i-cache */
100         li      t0, KSEG0
101         addi    t1, t0, CONFIG_SYS_ICACHE_SIZE
102 3:
103         cache   INDEX_INVALIDATE_I, 0(t0)
104         bne     t0, t1, 3b
105          addi   t0, CONFIG_SYS_CACHELINE_SIZE
106
107         /* Invalidate BTB */
108         mfc0    t0, CP0_CONFIG, 7
109         nop
110         ori     t0, 2
111         mtc0    t0, CP0_CONFIG, 7
112         nop
113
114         /* Jump to where we've relocated ourselves */
115         addi    t0, a2, in_ram - _start
116         jr      t0
117          nop
118
119         .word   __rel_dyn_end
120         .word   __rel_dyn_start
121         .word   __image_copy_end
122         .word   _GLOBAL_OFFSET_TABLE_
123         .word   num_got_entries
124
125 in_ram:
126         /*
127          * Now we want to update GOT.
128          *
129          * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object
130          * generated by GNU ld. Skip these reserved entries from relocation.
131          */
132         lw      t3, -4(t0)              # t3 <-- num_got_entries
133         lw      t4, -8(t0)              # t4 <-- _GLOBAL_OFFSET_TABLE_
134         add     t4, t6                  # t4 now holds relocated _G_O_T_
135         addi    t4, t4, 8               # skipping first two entries
136         li      t2, 2
137 1:
138         lw      t1, 0(t4)
139         beqz    t1, 2f
140          add    t1, t6
141         sw      t1, 0(t4)
142 2:
143         addi    t2, 1
144         blt     t2, t3, 1b
145          addi   t4, 4
146
147         /* Update dynamic relocations */
148         lw      t1, -16(t0)             # t1 <-- __rel_dyn_start
149         lw      t2, -20(t0)             # t2 <-- __rel_dyn_end
150
151         b       2f                      # skip first reserved entry
152          addi   t1, 8
153
154 1:
155         lw      t3, -4(t1)              # t3 <-- relocation info
156
157         sub     t3, 3
158         bnez    t3, 2f                  # skip non R_MIPS_REL32 entries
159          nop
160
161         lw      t3, -8(t1)              # t3 <-- location to fix up in FLASH
162
163         lw      t4, 0(t3)               # t4 <-- original pointer
164         add     t4, t6                  # t4 <-- adjusted pointer
165
166         add     t3, t6                  # t3 <-- location to fix up in RAM
167         sw      t4, 0(t3)
168
169 2:
170         blt     t1, t2, 1b
171          addi   t1, 8                   # each rel.dyn entry is 8 bytes
172
173         /*
174          * Clear BSS
175          *
176          * GOT is now relocated. Thus __bss_start and __bss_end can be
177          * accessed directly via $gp.
178          */
179         la      t1, __bss_start         # t1 <-- __bss_start
180         la      t2, __bss_end           # t2 <-- __bss_end
181
182 1:
183         sw      zero, 0(t1)
184         blt     t1, t2, 1b
185          addi   t1, 4
186
187         move    a0, a1                  # a0 <-- gd
188         la      t9, board_init_r
189         jr      t9
190          move   a1, a2
191
192         .end    relocate_code