move new files out from platform support patch
[openwrt/openwrt.git] / target / linux / ubicom32 / files / arch / ubicom32 / kernel / head.S
1 /*
2 * arch/ubicom32/kernel/head.S
3 * <TODO: Replace with short file description>
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 *
7 * This file is part of the Ubicom32 Linux Kernel Port.
8 *
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
22 *
23 * Ubicom32 implementation derived from (with many thanks):
24 * arch/m68knommu
25 * arch/blackfin
26 * arch/parisc
27 */
28 #include <linux/sys.h>
29 #include <linux/linkage.h>
30 #include <asm/asm-offsets.h>
31 #include <asm/page_offset.h>
32 #define __ASM__
33 #include <asm/ip5000.h>
34
35
36 #define SRC_AN A3
37 #define DST_AN A4
38
39 #define PARAM_DN D0
40 #define TMP_DN D15
41 #define TMP2_DN D14
42
43 /*
44 * The following code is placed at the start of the Linux section of memory.
45 * This is the primary entry point for Linux.
46 *
47 * However, we also want the syscall entry/exit code to be at a fixed address.
48 * So we take the primary entry point and reserve 16 bytes. That address is
49 * where the system_call entry point exists. This 16 bytes basically allows
50 * us to jump around the system_call entry point code to the actual startup
51 * code.
52 *
53 * Linux Memory Map (see vlinux.lds.S):
54 * 0x40400000 - Primary Entry Point for Linux (jump around code below).
55 * 0x40400010 - Old syscall Entry Point.
56 */
57
58 .sect .skip_syscall, "ax", @progbits
59 .global __skip_syscall_section
60 __skip_syscall_section:
61 moveai A3, #%hi(_start)
62 lea.1 A3, %lo(_start)(A3)
63 ret A3
64 /*
65 * __os_node_offset contains the offset from KERNELBASE to the os_node, it is
66 * not intended to be used by anything except the boot code.
67 */
68 __os_node_offset:
69 .long (_os_node - KERNELSTART)
70
71 .text
72 .global _start
73
74 /*
75 * start()
76 * This is the start of the Linux kernel.
77 */
78 _start:
79 move.4 SCRATCHPAD1, #0
80
81
82 /*
83 * Setup the range registers... the loader has setup a few, but we will go ahead
84 * and correct them for our own limits. Note that once set these are never
85 * changed again. The ranges are as follows
86 *
87 * D_RANGE0 - io block (set up by loaded)
88 *
89 * I_RANGE0 and D_RANGE1 - kernel/ultra loader address space bottom of ocm-> top
90 * of ram typically 0x3ffc0000 - 0x440000000
91 * I_RANGE1 - kernel / userspace transition area (aka syscalls, context switches)
92 * typically 0x3FFC0030 - ~0x3FFC0200
93 * I_RANGE2 / D_RANGE2 - slab area
94 * typically 0x40A00000 - ~0x44000000
95 * I_RANGE3
96 * old system call interface if enabled.
97 *
98 * D_RANGE3, D_RANGE4 - unused.
99 */
100 moveai SRC_AN, #%hi(PAGE_OFFSET_RAW)
101 lea.4 SRC_AN, %lo(PAGE_OFFSET_RAW)(SRC_AN)
102 move.4 D_RANGE1_LO, SRC_AN
103 move.4 I_RANGE0_LO, SRC_AN
104
105 ; don't try to calculate I_RANGE_HI, see below
106 ; moveai SRC_AN, #%hi(___init_end-4)
107 ; lea.4 SRC_AN, %lo(___init_end-4)(SRC_AN)
108 ; move.4 I_RANGE0_HI, SRC_AN
109
110 moveai SRC_AN, #%hi(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)
111 lea.4 SRC_AN, %lo(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)(SRC_AN)
112 move.4 D_RANGE1_HI, SRC_AN
113
114 ; for now allow the whole ram to be executable as well so we don't run into problems
115 ; once we load user more code.
116 move.4 I_RANGE0_HI, SRC_AN
117
118 #ifdef CONFIG_PROTECT_KERNEL
119 ; when kernel protection is enabled, we only open up syscall and non kernel text
120 ; for userspace apps, for now only irange registers registers 1 and 2 are used for userspace.
121
122 ;; syscall range
123 moveai SRC_AN, #%hi(__syscall_text_run_begin)
124 lea.4 SRC_AN, %lo(__syscall_text_run_begin)(SRC_AN)
125 move.4 I_RANGE1_LO, SRC_AN
126 moveai SRC_AN, #%hi(__syscall_text_run_end)
127 lea.4 SRC_AN, %lo(__syscall_text_run_end)(SRC_AN)
128 move.4 I_RANGE1_HI, SRC_AN
129
130 ;; slab instructions
131 moveai SRC_AN, #%hi(_edata)
132 lea.4 SRC_AN, %lo(_edata)(SRC_AN)
133 move.4 I_RANGE2_LO, SRC_AN
134 ;; End of DDR is already in range0 hi so just copy it.
135 move.4 I_RANGE2_HI, I_RANGE0_HI
136
137 #ifdef CONFIG_OLD_40400010_SYSTEM_CALL
138 ;; create a small hole for old syscall location
139 moveai SRC_AN, #%hi(0x40400000)
140 lea.4 I_RANGE3_LO, 0x10(SRC_AN)
141 lea.4 I_RANGE3_HI, 0x14(SRC_AN)
142 #endif
143 ;; slab data (same as slab instructions but starting a little earlier).
144 moveai SRC_AN, #%hi(_data_protection_end)
145 lea.4 SRC_AN, %lo(_data_protection_end)(SRC_AN)
146 move.4 D_RANGE2_LO, SRC_AN
147 move.4 D_RANGE2_HI, I_RANGE0_HI
148
149 ;; enable ranges
150 ;; skip I_RANGE0_EN
151 move.4 I_RANGE1_EN, #-1
152 move.4 I_RANGE2_EN, #-1
153 #ifdef CONFIG_OLD_40400010_SYSTEM_CALL
154 move.4 I_RANGE3_EN, #-1
155 #else
156 move.4 I_RANGE3_EN, #0
157 #endif
158 ;; skip D_RANGE0_EN or D_RANGE1_EN
159 move.4 D_RANGE2_EN, #-1
160 move.4 D_RANGE3_EN, #0
161 move.4 D_RANGE4_EN, #0
162 #endif
163
164 ;
165 ; If __ocm_free_begin is smaller than __ocm_free_end the
166 ; setup OCM text and data ram banks properly
167 ;
168 moveai DST_AN, #%hi(__ocm_free_begin)
169 lea.4 TMP_DN, %lo(__ocm_free_begin)(DST_AN)
170 moveai DST_AN, #%hi(__ocm_free_end)
171 lea.4 TMP2_DN, %lo(__ocm_free_end)(DST_AN)
172 sub.4 #0, TMP2_DN, TMP_DN
173 jmple.f 2f
174 moveai DST_AN, #%hi(__data_begin)
175 lea.4 TMP_DN, %lo(__data_begin)(DST_AN)
176 moveai DST_AN, #%hi(OCMSTART)
177 lea.4 TMP2_DN, %lo(OCMSTART)(DST_AN)
178 sub.4 TMP_DN, TMP_DN, TMP2_DN
179 lsr.4 TMP_DN, TMP_DN, #15
180 lsl.4 TMP_DN, #1, TMP_DN
181 moveai DST_AN, #%hi(OCMC_BASE)
182 add.4 OCMC_BANK_MASK(DST_AN), #-1, TMP_DN
183 pipe_flush 0
184 2:
185 ;
186 ; Load .ocm_text
187 ;
188 moveai DST_AN, #%hi(__ocm_text_run_end)
189 lea.4 TMP_DN, %lo(__ocm_text_run_end)(DST_AN)
190 moveai DST_AN, #%hi(__ocm_text_run_begin)
191 lea.4 DST_AN, %lo(__ocm_text_run_begin)(DST_AN)
192 moveai SRC_AN, #%hi(__ocm_text_load_begin)
193 lea.4 SRC_AN, %lo(__ocm_text_load_begin)(SRC_AN)
194 jmpt.t 2f
195
196 1: move.4 (DST_AN)4++, (SRC_AN)4++
197
198 2: sub.4 #0, DST_AN, TMP_DN
199 jmpne.t 1b
200 ;
201 ; Load .syscall_text
202 ;
203 moveai DST_AN, #%hi(__syscall_text_run_end)
204 lea.4 TMP_DN, %lo(__syscall_text_run_end)(DST_AN)
205 moveai DST_AN, #%hi(__syscall_text_run_begin)
206 lea.4 DST_AN, %lo(__syscall_text_run_begin)(DST_AN)
207 moveai SRC_AN, #%hi(__syscall_text_load_begin)
208 lea.4 SRC_AN, %lo(__syscall_text_load_begin)(SRC_AN)
209 jmpt.t 2f
210
211 1: move.4 (DST_AN)4++, (SRC_AN)4++
212
213 2: sub.4 #0, DST_AN, TMP_DN
214 jmpne.t 1b
215
216 ;
217 ; Load .ocm_data
218 ;
219 moveai DST_AN, #%hi(__ocm_data_run_end)
220 lea.4 TMP_DN, %lo(__ocm_data_run_end)(DST_AN)
221 moveai DST_AN, #%hi(__ocm_data_run_begin)
222 lea.4 DST_AN, %lo(__ocm_data_run_begin)(DST_AN)
223 moveai SRC_AN, #%hi(__ocm_data_load_begin)
224 lea.4 SRC_AN, %lo(__ocm_data_load_begin)(SRC_AN)
225 jmpt.t 2f
226
227 1: move.4 (DST_AN)4++, (SRC_AN)4++
228
229 2: sub.4 #0, DST_AN, TMP_DN
230 jmpne.t 1b
231
232 ; Clear .bss
233 ;
234 moveai SRC_AN, #%hi(_ebss)
235 lea.4 TMP_DN, %lo(_ebss)(SRC_AN)
236 moveai DST_AN, #%hi(_sbss)
237 lea.4 DST_AN, %lo(_sbss)(DST_AN)
238 jmpt.t 2f
239
240 1: move.4 (DST_AN)4++, #0
241
242 2: sub.4 #0, DST_AN, TMP_DN
243 jmpne.t 1b
244
245 ; save our parameter to devtree (after clearing .bss)
246 moveai DST_AN, #%hi(devtree)
247 lea.4 DST_AN, %lo(devtree)(DST_AN)
248 move.4 (DST_AN), PARAM_DN
249
250 moveai sp, #%hi(init_thread_union)
251 lea.4 sp, %lo(init_thread_union)(sp)
252 movei TMP_DN, #ASM_THREAD_SIZE
253 add.4 sp, sp, TMP_DN
254 move.4 -4(sp)++, #0 ; nesting level = 0
255 move.4 -4(sp)++, #1 ; KERNEL_THREAD
256
257 ;; ip3k-elf-gdb backend now sets scratchpad3 to 1 when either continue
258 ;; or single step commands are issued. scratchpad3 is set to 0 when the
259 ;; debugger detaches from the board.
260 move.4 TMP_DN, scratchpad3
261 lsl.4 TMP_DN, TMP_DN, #0x0
262 jmpeq.f _jump_to_start_kernel
263 _ok_to_set_break_points_in_linux:
264 ;; THREAD_STALL
265 move.4 mt_dbg_active_clr,#-1
266 ;; stalling the threads isn't instantaneous.. need to flush the pipe.
267 pipe_flush 0
268 pipe_flush 0
269
270 _jump_to_start_kernel:
271 moveai SRC_AN, #%hi(start_kernel)
272 lea.4 SRC_AN, %lo(start_kernel)(SRC_AN)
273 ret SRC_AN