update x-wrt url for backfire
[10.03/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