1 | /* crt0.S -- startup file for OpenRISC 1000. |
---|
2 | * |
---|
3 | * Copyright (c) 2011, 2014 Authors |
---|
4 | * |
---|
5 | * Contributor Julius Baxter <juliusbaxter@gmail.com> |
---|
6 | * Contributor Stefan Wallentowitz <stefan.wallentowitz@tum.de> |
---|
7 | * |
---|
8 | * The authors hereby grant permission to use, copy, modify, distribute, |
---|
9 | * and license this software and its documentation for any purpose, provided |
---|
10 | * that existing copyright notices are retained in all copies and that this |
---|
11 | * notice is included verbatim in any distributions. No written agreement, |
---|
12 | * license, or royalty fee is required for any of the authorized uses. |
---|
13 | * Modifications to this software may be copyrighted by their authors |
---|
14 | * and need not follow the licensing terms described here, provided that |
---|
15 | * the new terms are clearly indicated on the first page of each file where |
---|
16 | * they apply. |
---|
17 | */ |
---|
18 | |
---|
19 | /* -------------------------------------------------------------------------- */ |
---|
20 | /* Coding convention: |
---|
21 | Assembly is hard to read per se, so please follow the following coding |
---|
22 | conventions to keep it consistent and ease reading: |
---|
23 | * internal jump labels start with L, no identation |
---|
24 | * assemble lines have one tab identation |
---|
25 | * attributes (.section, .global, ..) are indented with one tab |
---|
26 | * code is structured using tabs, i.e., use 'l.sw\t0(r1),r1' with a single |
---|
27 | tab. libgloss assumes 8 space tab width, so that might look unstructured |
---|
28 | with tab widths below 6. Nevertheless don't use spaces or two tabs. |
---|
29 | * no space after comma |
---|
30 | * use the defined macros if possible as they reduce errors |
---|
31 | * use OR1K_INST with OR1K_DELAYED(_NOP) |
---|
32 | * OR1K_DELAYED is multiline for better readability, the inner parts are |
---|
33 | indented with another tab. |
---|
34 | * COMMENT! Try to accompy every line with a meaningful comment. If possible |
---|
35 | use pseudo code to describe the code. Also mention intentions and not only |
---|
36 | the obvious things.. */ |
---|
37 | /* -------------------------------------------------------------------------- */ |
---|
38 | |
---|
39 | #include "newlib.h" |
---|
40 | #include "include/or1k-asm.h" |
---|
41 | #include "include/or1k-sprs.h" |
---|
42 | |
---|
43 | /* -------------------------------------------------------------------------- */ |
---|
44 | // Stack definitions |
---|
45 | /* -------------------------------------------------------------------------- */ |
---|
46 | |
---|
47 | // Stacks |
---|
48 | // Memory layout: |
---|
49 | // +--------------------+ <- board_mem_base+board_mem_size/exception_stack_top |
---|
50 | // | exception stack(s) | |
---|
51 | // +--------------------+ <- stack_top |
---|
52 | // | stack(s) | |
---|
53 | // +--------------------+ <- stack_bottom |
---|
54 | // | heap | |
---|
55 | // +--------------------+ |
---|
56 | // | text, data, bss.. | |
---|
57 | // +--------------------+ |
---|
58 | |
---|
59 | // Reserved stack size |
---|
60 | #define STACK_SIZE 8192 |
---|
61 | |
---|
62 | // Reserved stack size for exceptions (can usually be smaller than normal stack) |
---|
63 | #define EXCEPTION_STACK_SIZE 8192 |
---|
64 | |
---|
65 | // Size of space required to store state |
---|
66 | // This value must match that in the support library or1k_exception_handler |
---|
67 | // function |
---|
68 | #define EXCEPTION_STACK_FRAME 136 |
---|
69 | |
---|
70 | #define REDZONE 128 |
---|
71 | |
---|
72 | .extern _or1k_stack_top /* points to the next address after the stack */ |
---|
73 | .extern _or1k_stack_bottom /* points to the last address in the stack */ |
---|
74 | .extern _or1k_exception_stack_top |
---|
75 | .extern _or1k_exception_stack_bottom |
---|
76 | .extern _or1k_exception_level /* Nesting level of exceptions */ |
---|
77 | |
---|
78 | .section .data |
---|
79 | .global _or1k_stack_size /* reserved stack size */ |
---|
80 | .global _or1k_exception_stack_size |
---|
81 | .global _or1k_exception_level |
---|
82 | |
---|
83 | _or1k_stack_size: .word STACK_SIZE |
---|
84 | _or1k_exception_stack_size: .word EXCEPTION_STACK_SIZE |
---|
85 | |
---|
86 | #ifdef __OR1K_MULTICORE__ |
---|
87 | .extern _or1k_stack_core |
---|
88 | .extern _or1k_exception_stack_core |
---|
89 | #endif |
---|
90 | |
---|
91 | #define SHADOW_REG(x) (OR1K_SPR_SYS_GPR_BASE + 32 + x) |
---|
92 | |
---|
93 | /* -------------------------------------------------------------------------- */ |
---|
94 | /*!Macro to handle exceptions. |
---|
95 | |
---|
96 | Load NPC into r3, EPCR into r4 |
---|
97 | */ |
---|
98 | /* -------------------------------------------------------------------------- */ |
---|
99 | |
---|
100 | #ifdef HAVE_INITFINI_ARRAY |
---|
101 | #define _init __libc_init_array |
---|
102 | #define _fini __libc_fini_array |
---|
103 | #endif |
---|
104 | |
---|
105 | #define GPR_BUF_OFFSET(x) (x << 2) |
---|
106 | |
---|
107 | #ifndef __OR1K_MULTICORE__ |
---|
108 | #define CALL_EXCEPTION_HANDLER(id) \ |
---|
109 | /* Store current stack pointer to address 4 */ \ |
---|
110 | l.sw 0x4(r0),r1; \ |
---|
111 | /* Load address of exception nesting level */ \ |
---|
112 | l.movhi r1,hi(_or1k_exception_level); \ |
---|
113 | l.ori r1,r1,lo(_or1k_exception_level); \ |
---|
114 | /* Load the current nesting level */ \ |
---|
115 | l.lwz r1,0(r1); \ |
---|
116 | /* Set flag if this is the outer (first) exception */ \ |
---|
117 | l.sfeq r1,r0; \ |
---|
118 | /* Branch to the code for nested exceptions */ \ |
---|
119 | OR1K_DELAYED_NOP( \ |
---|
120 | OR1K_INST(l.bnf .Lnested_##id) \ |
---|
121 | ); \ |
---|
122 | /* Load top of the exception stack */ \ |
---|
123 | l.movhi r1,hi(_or1k_exception_stack_top); \ |
---|
124 | l.ori r1,r1,lo(_or1k_exception_stack_top); \ |
---|
125 | OR1K_DELAYED( \ |
---|
126 | /* Load value from array to stack pointer */ \ |
---|
127 | OR1K_INST(l.lwz r1,0(r1)), \ |
---|
128 | /* and jump over the nested code */ \ |
---|
129 | OR1K_INST(l.j .Lnesting_done_##id) \ |
---|
130 | ); \ |
---|
131 | .Lnested_##id: \ |
---|
132 | /* Load back the stack pointer */ \ |
---|
133 | l.lwz r1,0x4(r0); \ |
---|
134 | /* Add redzone, nesting needs this */ \ |
---|
135 | l.addi r1,r1,-REDZONE; \ |
---|
136 | .Lnesting_done_##id: \ |
---|
137 | /* Reserve red zone and context space */ \ |
---|
138 | l.addi r1,r1,-EXCEPTION_STACK_FRAME; \ |
---|
139 | /* Store GPR3 in context */ \ |
---|
140 | l.sw GPR_BUF_OFFSET(3)(r1),r3; \ |
---|
141 | /* Load back software's stack pointer */ \ |
---|
142 | l.lwz r3,0x4(r0); \ |
---|
143 | /* Store this in the context */ \ |
---|
144 | l.sw GPR_BUF_OFFSET(1)(r1),r3; \ |
---|
145 | /* Store GPR4 in the context */ \ |
---|
146 | l.sw GPR_BUF_OFFSET(4)(r1),r4; \ |
---|
147 | /* Load address of the exception level */ \ |
---|
148 | l.movhi r3,hi(_or1k_exception_level); \ |
---|
149 | l.ori r3,r3,lo(_or1k_exception_level); \ |
---|
150 | /* Load current value */ \ |
---|
151 | l.lwz r4,0(r3); \ |
---|
152 | /* Increment level */ \ |
---|
153 | l.addi r4,r4,1; \ |
---|
154 | /* Store back */ \ |
---|
155 | l.sw 0(r3),r4; \ |
---|
156 | /* Copy the current program counter as first */ \ |
---|
157 | /* argument for the exception handler. This */ \ |
---|
158 | /* is then used to determine the exception. */ \ |
---|
159 | l.mfspr r3,r0,OR1K_SPR_SYS_NPC_ADDR; \ |
---|
160 | OR1K_DELAYED( \ |
---|
161 | /* Copy program counter of exception as */ \ |
---|
162 | /* second argument to the exception handler */ \ |
---|
163 | OR1K_INST(l.mfspr r4,r0,OR1K_SPR_SYS_EPCR_BASE),\ |
---|
164 | /* Jump to exception handler. This will rfe */ \ |
---|
165 | OR1K_INST(l.j _or1k_exception_handler) \ |
---|
166 | ) |
---|
167 | #else |
---|
168 | #define CALL_EXCEPTION_HANDLER(id) \ |
---|
169 | /* Store current stack pointer to shadow reg */ \ |
---|
170 | l.mtspr r0,r1,SHADOW_REG(1); \ |
---|
171 | /* Store current GPR3 for temporary use */ \ |
---|
172 | l.mtspr r0,r3,SHADOW_REG(2); \ |
---|
173 | /* Store current GPR2 for the level pointer */ \ |
---|
174 | l.mtspr r0,r4,SHADOW_REG(3); \ |
---|
175 | /* Load nesting level of exceptions */ \ |
---|
176 | l.movhi r4,hi(_or1k_exception_level); \ |
---|
177 | l.ori r4,r4,lo(_or1k_exception_level); \ |
---|
178 | /* Load array pointer */ \ |
---|
179 | l.lwz r4,0(r4); \ |
---|
180 | /* Get core id */ \ |
---|
181 | l.mfspr r3,r0,OR1K_SPR_SYS_COREID_ADDR; \ |
---|
182 | /* Generate offset */ \ |
---|
183 | l.slli r3,r3,2; \ |
---|
184 | /* Generate core nesting level address */ \ |
---|
185 | l.add r4,r4,r3; \ |
---|
186 | /* Load nesting level */ \ |
---|
187 | l.lwz r3,0(r4); \ |
---|
188 | /* Increment nesting level */ \ |
---|
189 | l.addi r3,r3,1; \ |
---|
190 | /* Write back nesting level */ \ |
---|
191 | l.sw 0(r4),r3; \ |
---|
192 | /* Set flag if this is the outer (first) exception */ \ |
---|
193 | l.sfeqi r3,1; \ |
---|
194 | /* Branch to the code for nested exceptions */ \ |
---|
195 | OR1K_DELAYED_NOP( \ |
---|
196 | OR1K_INST(l.bnf .Lnested_##id) \ |
---|
197 | ); \ |
---|
198 | /* Load pointer to exception stack array */ \ |
---|
199 | l.movhi r1,hi(_or1k_exception_stack_core); \ |
---|
200 | l.ori r1,r1,lo(_or1k_exception_stack_core); \ |
---|
201 | l.lwz r1,0(r1); \ |
---|
202 | /* Get core id */ \ |
---|
203 | l.mfspr r3,r0,OR1K_SPR_SYS_COREID_ADDR; \ |
---|
204 | /* Calculate offset in array */ \ |
---|
205 | l.slli r3,r3,2; \ |
---|
206 | l.add r1,r1,r3; \ |
---|
207 | OR1K_DELAYED( \ |
---|
208 | /* Load value from array to stack pointer */ \ |
---|
209 | OR1K_INST(l.lwz r1,0(r1)), \ |
---|
210 | /* and jump over nested exception pointer */ \ |
---|
211 | OR1K_INST(l.j .Lnesting_done_##id) \ |
---|
212 | ); \ |
---|
213 | .Lnested_##id: \ |
---|
214 | /* The stack pointer is still active */ \ |
---|
215 | /* Add redzone, nesting needs this */ \ |
---|
216 | l.addi r1,r1,-REDZONE; \ |
---|
217 | .Lnesting_done_##id: \ |
---|
218 | /* Reserve context space */ \ |
---|
219 | l.addi r1,r1,-EXCEPTION_STACK_FRAME; \ |
---|
220 | /* Load back software's stack pointer */ \ |
---|
221 | l.mfspr r3,r0,SHADOW_REG(1); \ |
---|
222 | /* Store this in the context */ \ |
---|
223 | l.sw GPR_BUF_OFFSET(1)(r1),r3; \ |
---|
224 | /* Load back GPR3 */ \ |
---|
225 | l.mfspr r3,r0,SHADOW_REG(2); \ |
---|
226 | /* Store this in the context */ \ |
---|
227 | l.sw GPR_BUF_OFFSET(3)(r1),r3; \ |
---|
228 | /* Load back GPR4 */ \ |
---|
229 | l.mfspr r4,r0,SHADOW_REG(3); \ |
---|
230 | /* Store GPR4 in the context */ \ |
---|
231 | l.sw GPR_BUF_OFFSET(4)(r1),r4; \ |
---|
232 | /* Copy the current program counter as first */ \ |
---|
233 | /* argument for the exception handler. This */ \ |
---|
234 | /* is then used to determine the exception. */ \ |
---|
235 | l.mfspr r3,r0,OR1K_SPR_SYS_NPC_ADDR; \ |
---|
236 | OR1K_DELAYED( \ |
---|
237 | /* Copy program counter of exception as */ \ |
---|
238 | /* second argument to the exception handler */ \ |
---|
239 | OR1K_INST(l.mfspr r4,r0,OR1K_SPR_SYS_EPCR_BASE),\ |
---|
240 | /* Jump to exception handler. This will rfe */ \ |
---|
241 | OR1K_INST(l.j _or1k_exception_handler) \ |
---|
242 | ) |
---|
243 | #endif |
---|
244 | |
---|
245 | /* -------------------------------------------------------------------------- */ |
---|
246 | /*!Exception vectors */ |
---|
247 | /* -------------------------------------------------------------------------- */ |
---|
248 | .section .vectors,"ax" |
---|
249 | |
---|
250 | /* 0x100: RESET exception */ |
---|
251 | .org 0x100 |
---|
252 | _or1k_reset: |
---|
253 | l.movhi r0,0 |
---|
254 | #ifdef __OR1K_MULTICORE__ |
---|
255 | // This is a hack that relies on the fact, that all cores start at the |
---|
256 | // same time and they are similarily fast |
---|
257 | l.sw 0x4(r0),r0 |
---|
258 | // Similarly, we use address 8 to signal how many cores have exit'ed |
---|
259 | l.sw 0x8(r0),r0 |
---|
260 | #endif |
---|
261 | l.movhi r1,0 |
---|
262 | l.movhi r2,0 |
---|
263 | l.movhi r3,0 |
---|
264 | l.movhi r4,0 |
---|
265 | l.movhi r5,0 |
---|
266 | l.movhi r6,0 |
---|
267 | l.movhi r7,0 |
---|
268 | l.movhi r8,0 |
---|
269 | l.movhi r9,0 |
---|
270 | l.movhi r10,0 |
---|
271 | l.movhi r11,0 |
---|
272 | l.movhi r12,0 |
---|
273 | l.movhi r13,0 |
---|
274 | l.movhi r14,0 |
---|
275 | l.movhi r15,0 |
---|
276 | l.movhi r16,0 |
---|
277 | l.movhi r17,0 |
---|
278 | l.movhi r18,0 |
---|
279 | l.movhi r19,0 |
---|
280 | l.movhi r20,0 |
---|
281 | l.movhi r21,0 |
---|
282 | l.movhi r22,0 |
---|
283 | l.movhi r23,0 |
---|
284 | l.movhi r24,0 |
---|
285 | l.movhi r25,0 |
---|
286 | l.movhi r26,0 |
---|
287 | l.movhi r27,0 |
---|
288 | l.movhi r28,0 |
---|
289 | l.movhi r29,0 |
---|
290 | l.movhi r30,0 |
---|
291 | l.movhi r31,0 |
---|
292 | |
---|
293 | /* Clear status register, set supervisor mode */ |
---|
294 | l.ori r1,r0,OR1K_SPR_SYS_SR_SM_MASK |
---|
295 | l.mtspr r0,r1,OR1K_SPR_SYS_SR_ADDR |
---|
296 | /* Clear timer mode register*/ |
---|
297 | l.mtspr r0,r0,OR1K_SPR_TICK_TTMR_ADDR |
---|
298 | /* Jump to program initialisation code */ |
---|
299 | LOAD_SYMBOL_2_GPR(r4, _or1k_start) |
---|
300 | OR1K_DELAYED_NOP(OR1K_INST(l.jr r4)) |
---|
301 | |
---|
302 | .org 0x200 |
---|
303 | CALL_EXCEPTION_HANDLER(2) |
---|
304 | |
---|
305 | /* 0x300: Data Page Fault exception */ |
---|
306 | .org 0x300 |
---|
307 | CALL_EXCEPTION_HANDLER(3) |
---|
308 | |
---|
309 | /* 0x400: Insn Page Fault exception */ |
---|
310 | .org 0x400 |
---|
311 | CALL_EXCEPTION_HANDLER(4) |
---|
312 | |
---|
313 | /* 0x500: Timer exception */ |
---|
314 | .org 0x500 |
---|
315 | CALL_EXCEPTION_HANDLER(5) |
---|
316 | |
---|
317 | /* 0x600: Aligment exception */ |
---|
318 | .org 0x600 |
---|
319 | CALL_EXCEPTION_HANDLER(6) |
---|
320 | |
---|
321 | /* 0x700: Illegal insn exception */ |
---|
322 | .org 0x700 |
---|
323 | CALL_EXCEPTION_HANDLER(7) |
---|
324 | |
---|
325 | /* 0x800: External interrupt exception */ |
---|
326 | .org 0x800 |
---|
327 | CALL_EXCEPTION_HANDLER(8) |
---|
328 | |
---|
329 | /* 0x900: DTLB miss exception */ |
---|
330 | .org 0x900 |
---|
331 | CALL_EXCEPTION_HANDLER(9) |
---|
332 | |
---|
333 | /* 0xa00: ITLB miss exception */ |
---|
334 | .org 0xa00 |
---|
335 | CALL_EXCEPTION_HANDLER(10) |
---|
336 | |
---|
337 | /* 0xb00: Range exception */ |
---|
338 | .org 0xb00 |
---|
339 | CALL_EXCEPTION_HANDLER(11) |
---|
340 | |
---|
341 | /* 0xc00: Syscall exception */ |
---|
342 | .org 0xc00 |
---|
343 | CALL_EXCEPTION_HANDLER(12) |
---|
344 | |
---|
345 | /* 0xd00: Floating point exception */ |
---|
346 | .org 0xd00 |
---|
347 | CALL_EXCEPTION_HANDLER(13) |
---|
348 | |
---|
349 | /* 0xe00: Trap exception */ |
---|
350 | .org 0xe00 |
---|
351 | CALL_EXCEPTION_HANDLER(14) |
---|
352 | |
---|
353 | /* 0xf00: Reserved exceptions */ |
---|
354 | .org 0xf00 |
---|
355 | CALL_EXCEPTION_HANDLER(15) |
---|
356 | |
---|
357 | .org 0x1000 |
---|
358 | CALL_EXCEPTION_HANDLER(16) |
---|
359 | |
---|
360 | .org 0x1100 |
---|
361 | CALL_EXCEPTION_HANDLER(17) |
---|
362 | |
---|
363 | .org 0x1200 |
---|
364 | CALL_EXCEPTION_HANDLER(18) |
---|
365 | |
---|
366 | .org 0x1300 |
---|
367 | CALL_EXCEPTION_HANDLER(19) |
---|
368 | |
---|
369 | .org 0x1400 |
---|
370 | CALL_EXCEPTION_HANDLER(20) |
---|
371 | |
---|
372 | .org 0x1500 |
---|
373 | CALL_EXCEPTION_HANDLER(21) |
---|
374 | |
---|
375 | .org 0x1600 |
---|
376 | CALL_EXCEPTION_HANDLER(22) |
---|
377 | |
---|
378 | .org 0x1700 |
---|
379 | CALL_EXCEPTION_HANDLER(23) |
---|
380 | |
---|
381 | .org 0x1800 |
---|
382 | CALL_EXCEPTION_HANDLER(24) |
---|
383 | |
---|
384 | .org 0x1900 |
---|
385 | CALL_EXCEPTION_HANDLER(25) |
---|
386 | |
---|
387 | .org 0x1a00 |
---|
388 | CALL_EXCEPTION_HANDLER(26) |
---|
389 | |
---|
390 | .org 0x1b00 |
---|
391 | CALL_EXCEPTION_HANDLER(27) |
---|
392 | |
---|
393 | .org 0x1c00 |
---|
394 | CALL_EXCEPTION_HANDLER(28) |
---|
395 | |
---|
396 | .org 0x1d00 |
---|
397 | CALL_EXCEPTION_HANDLER(29) |
---|
398 | |
---|
399 | .org 0x1e00 |
---|
400 | CALL_EXCEPTION_HANDLER(30) |
---|
401 | |
---|
402 | .org 0x1f00 |
---|
403 | CALL_EXCEPTION_HANDLER(31) |
---|
404 | |
---|
405 | /* Pad to the end */ |
---|
406 | .org 0x1ffc |
---|
407 | l.nop |
---|
408 | |
---|
409 | /* -------------------------------------------------------------------------- */ |
---|
410 | /*!Main entry point |
---|
411 | |
---|
412 | This is the initialization code of the library. It performs these steps: |
---|
413 | |
---|
414 | * Call early board initialization: |
---|
415 | Before anything happened, the board support may do some very early |
---|
416 | initialization. This is at maximum some very basic stuff that would |
---|
417 | otherwise prevent the following code from functioning. Other initialization |
---|
418 | of peripherals etc. is done later (before calling main). |
---|
419 | See the description below and README.board for details. |
---|
420 | |
---|
421 | * Initialize the stacks: |
---|
422 | Two stacks are configured: The system stack is used by the software and |
---|
423 | the exception stack is used when an exception occurs. We added this as |
---|
424 | this should be flexible with respect to the usage of virtual memory. |
---|
425 | |
---|
426 | * Activate the caches: |
---|
427 | If available the caches are initiliazed and activated. |
---|
428 | |
---|
429 | * Clear BSS: |
---|
430 | The BSS are essentially the uninitialized C variables. They are set to 0 |
---|
431 | by default. This is performed by this function. |
---|
432 | |
---|
433 | * Initialize the impure data structure: |
---|
434 | Similarly, we need two library contexts, one for the normal software and |
---|
435 | one that is used during exceptions. The impure data structure holds |
---|
436 | the context information of the library. The called C function will setup |
---|
437 | both data structures. There is furthermore a pointer to the currently |
---|
438 | active impure data structure, which is initially set to the normal one. |
---|
439 | |
---|
440 | * Initialize or1k support library reentrant data structures |
---|
441 | |
---|
442 | * Initialize constructors: |
---|
443 | Call the static and global constructors |
---|
444 | |
---|
445 | * Set up destructors to call from exit |
---|
446 | The library will call the function set via atexit() during exit(). We set |
---|
447 | it to call the _fini function which performs destruction. |
---|
448 | |
---|
449 | * Call board initialization: |
---|
450 | The board initialization can perform board specific initializations such as |
---|
451 | configuring peripherals etc. |
---|
452 | |
---|
453 | * Jump to main |
---|
454 | Call main with argc = 0 and *argv[] = 0 |
---|
455 | |
---|
456 | * Call exit after main returns |
---|
457 | Now we call exit() |
---|
458 | |
---|
459 | * Loop forever |
---|
460 | We are dead. |
---|
461 | */ |
---|
462 | |
---|
463 | /* -------------------------------------------------------------------------- */ |
---|
464 | .section .text |
---|
465 | |
---|
466 | /* Following externs from board-specific object passed at link time */ |
---|
467 | .extern _or1k_board_mem_base |
---|
468 | .extern _or1k_board_mem_size |
---|
469 | .extern _or1k_board_uart_base |
---|
470 | |
---|
471 | /* The early board initialization may for example read the memory size and |
---|
472 | set the mem_base and mem_size or do some preliminary board |
---|
473 | initialization. As we do not have a stack at this time, the function may |
---|
474 | not use the stack (and therefore be a or call a C function. But it can |
---|
475 | safely use all registers. |
---|
476 | |
---|
477 | We define a default implementation, which allows board files in C. As |
---|
478 | described above, this can only be used in assembly (board_*.S) as at |
---|
479 | the early stage not stack is available. A board that needs early |
---|
480 | initialization can overwrite the function with .global _board_init_early. |
---|
481 | |
---|
482 | Recommendation: Only use when you really need it! */ |
---|
483 | .weak _or1k_board_init_early |
---|
484 | _or1k_board_init_early: |
---|
485 | OR1K_DELAYED_NOP(OR1K_INST(l.jr r9)) |
---|
486 | |
---|
487 | /* The board initialization is then called after the C library and UART |
---|
488 | are initialized. It can then be used to configure UART or other |
---|
489 | devices before the actual main function is called. */ |
---|
490 | .extern _or1k_board_init |
---|
491 | |
---|
492 | .global _or1k_start |
---|
493 | .type _or1k_start,@function |
---|
494 | _or1k_start: |
---|
495 | /* It is good to initialize and enable the caches before we do anything, |
---|
496 | otherwise the cores will continuously access the bus during the wait |
---|
497 | time for the boot barrier (0x4). |
---|
498 | Fortunately or1k_cache_init does not need a stack */ |
---|
499 | OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_cache_init)) |
---|
500 | |
---|
501 | #ifdef __OR1K_MULTICORE__ |
---|
502 | // All but core 0 have to wait |
---|
503 | l.mfspr r1, r0, OR1K_SPR_SYS_COREID_ADDR |
---|
504 | l.sfeq r1, r0 |
---|
505 | OR1K_DELAYED_NOP(OR1K_INST(l.bf .Lcore0)) |
---|
506 | .Lspin: |
---|
507 | /* r1 will be used by the other cores to check for the boot variable |
---|
508 | Check if r1 is still zero, core 0 will set it to 1 once it booted |
---|
509 | As the cache is already turned on, this will not create traffic on |
---|
510 | the bus, but the change is snooped by cache coherency then */ |
---|
511 | l.lwz r1,0x4(r0) |
---|
512 | l.sfeq r1, r0 |
---|
513 | OR1K_DELAYED_NOP(OR1K_INST(l.bf .Lspin)) |
---|
514 | |
---|
515 | /* Initialize core i stack */ |
---|
516 | // _or1k_stack_core is the array of stack pointers |
---|
517 | LOAD_SYMBOL_2_GPR(r2,_or1k_stack_core) |
---|
518 | // Load the base address |
---|
519 | l.lwz r2,0(r2) |
---|
520 | // Generate offset in array |
---|
521 | l.mfspr r1,r0,OR1K_SPR_SYS_COREID_ADDR |
---|
522 | l.slli r1,r1,2 |
---|
523 | // Add to array base |
---|
524 | l.add r2,r2,r1 |
---|
525 | // Load pointer to the stack top and set frame pointer |
---|
526 | l.lwz r1,0(r2) |
---|
527 | l.or r2,r1,r1 |
---|
528 | |
---|
529 | // The slave cores are done, jump to main part |
---|
530 | OR1K_DELAYED_NOP(OR1K_INST(l.j .Linit_done)); |
---|
531 | |
---|
532 | /* Only core 0 executes the initialization code */ |
---|
533 | .Lcore0: |
---|
534 | #endif |
---|
535 | /* Call early board initialization */ |
---|
536 | OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_board_init_early)) |
---|
537 | |
---|
538 | /* Clear BSS */ |
---|
539 | .Lclear_bss: |
---|
540 | LOAD_SYMBOL_2_GPR(r3,__bss_start) |
---|
541 | LOAD_SYMBOL_2_GPR(r4,end) |
---|
542 | |
---|
543 | .Lclear_bss_loop: |
---|
544 | l.sw (0)(r3),r0 |
---|
545 | l.sfltu r3,r4 |
---|
546 | OR1K_DELAYED( |
---|
547 | OR1K_INST(l.addi r3,r3,4), |
---|
548 | OR1K_INST(l.bf .Lclear_bss_loop) |
---|
549 | ) |
---|
550 | |
---|
551 | /* Initialise stack and frame pointer (set to same value) */ |
---|
552 | LOAD_SYMBOL_2_GPR(r1,_or1k_board_mem_base) |
---|
553 | l.lwz r1,0(r1) |
---|
554 | LOAD_SYMBOL_2_GPR(r2,_or1k_board_mem_size) |
---|
555 | l.lwz r2,0(r2) |
---|
556 | l.add r1,r1,r2 |
---|
557 | |
---|
558 | /* Store exception stack top address */ |
---|
559 | LOAD_SYMBOL_2_GPR(r3,_or1k_exception_stack_top) |
---|
560 | l.sw 0(r3),r1 |
---|
561 | |
---|
562 | /* Store exception stack bottom address */ |
---|
563 | // calculate bottom address |
---|
564 | // r3 = *exception stack size |
---|
565 | LOAD_SYMBOL_2_GPR(r3,_or1k_exception_stack_size) |
---|
566 | // r3 = exception stack size |
---|
567 | l.lwz r3,0(r3) |
---|
568 | #ifdef __OR1K_MULTICORE__ |
---|
569 | l.mfspr r4,r0,OR1K_SPR_SYS_NUMCORES_ADDR |
---|
570 | l.mul r3,r4,r3 |
---|
571 | #endif |
---|
572 | // r4 = exception stack top - exception stack size = exception stack bottom |
---|
573 | l.sub r4,r1,r3 |
---|
574 | // r5 = *exception stack bottom |
---|
575 | LOAD_SYMBOL_2_GPR(r5,_or1k_exception_stack_bottom) |
---|
576 | // store |
---|
577 | l.sw 0(r5),r4 |
---|
578 | |
---|
579 | // Move stack pointer accordingly |
---|
580 | l.or r1,r0,r4 |
---|
581 | l.or r2,r1,r1 |
---|
582 | |
---|
583 | /* Store stack top address */ |
---|
584 | LOAD_SYMBOL_2_GPR(r3,_or1k_stack_top) |
---|
585 | l.sw 0(r3),r1 |
---|
586 | |
---|
587 | /* Store stack bottom address */ |
---|
588 | // calculate bottom address |
---|
589 | // r3 = stack size |
---|
590 | LOAD_SYMBOL_2_GPR(r3,_or1k_stack_size) |
---|
591 | l.lwz r3,0(r3) |
---|
592 | #ifdef __OR1K_MULTICORE__ |
---|
593 | l.mfspr r4, r0, OR1K_SPR_SYS_NUMCORES_ADDR |
---|
594 | l.mul r3, r4, r3 |
---|
595 | #endif |
---|
596 | // r4 = stack top - stack size = stack bottom |
---|
597 | // -> stack bottom |
---|
598 | l.sub r4,r1,r3 |
---|
599 | // r5 = *exception stack bottom |
---|
600 | LOAD_SYMBOL_2_GPR(r5,_or1k_stack_bottom) |
---|
601 | // store to variable |
---|
602 | l.sw 0(r5),r4 |
---|
603 | |
---|
604 | /* Reinitialize the or1k support library */ |
---|
605 | OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_init)) |
---|
606 | |
---|
607 | /* Reinitialize the reentrancy structure */ |
---|
608 | OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_libc_impure_init)) |
---|
609 | |
---|
610 | /* Call global and static constructors */ |
---|
611 | OR1K_DELAYED_NOP(OR1K_INST(l.jal _init)) |
---|
612 | |
---|
613 | /* Set up destructors to be called from exit if main ever returns */ |
---|
614 | l.movhi r3,hi(_fini) |
---|
615 | OR1K_DELAYED( |
---|
616 | OR1K_INST(l.ori r3,r3,lo(_fini)), |
---|
617 | OR1K_INST(l.jal atexit) |
---|
618 | ) |
---|
619 | |
---|
620 | /* Check if UART is to be initialised */ |
---|
621 | LOAD_SYMBOL_2_GPR(r4,_or1k_board_uart_base) |
---|
622 | l.lwz r4,0(r4) |
---|
623 | /* Is base set? If not, no UART */ |
---|
624 | l.sfne r4,r0 |
---|
625 | l.bnf .Lskip_uart |
---|
626 | l.or r3,r0,r0 |
---|
627 | OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_uart_init)) |
---|
628 | |
---|
629 | .Lskip_uart: |
---|
630 | /* Board initialization */ |
---|
631 | OR1K_DELAYED_NOP(OR1K_INST(l.jal _or1k_board_init)) |
---|
632 | |
---|
633 | #ifdef __OR1K_MULTICORE__ |
---|
634 | // Start other cores |
---|
635 | l.ori r3, r0, 1 |
---|
636 | l.sw 0x4(r0), r3 |
---|
637 | #endif |
---|
638 | |
---|
639 | .Linit_done: |
---|
640 | /* Jump to main program entry point (argc = argv = envp = 0) */ |
---|
641 | l.or r3,r0,r0 |
---|
642 | l.or r4,r0,r0 |
---|
643 | OR1K_DELAYED( |
---|
644 | OR1K_INST(l.or r5,r0,r0), |
---|
645 | OR1K_INST(l.jal main) |
---|
646 | ) |
---|
647 | |
---|
648 | #ifdef __OR1K_MULTICORE__ |
---|
649 | .incrementexit: |
---|
650 | /* Atomically increment number of finished cores */ |
---|
651 | l.lwa r3,0x8(r0) |
---|
652 | l.addi r3,r3,1 |
---|
653 | l.swa 0x8(r0),r3 |
---|
654 | OR1K_DELAYED_NOP(OR1K_INST(l.bnf .incrementexit)); |
---|
655 | /* Compare to number of cores in this cluster */ |
---|
656 | l.mfspr r4,r0, OR1K_SPR_SYS_NUMCORES_ADDR |
---|
657 | /* Compare to number of finished tasks */ |
---|
658 | l.sfeq r3,r4 |
---|
659 | /* Last core needs to desctruct library etc. */ |
---|
660 | OR1K_DELAYED_NOP(OR1K_INST(l.bf .exitcorelast)); |
---|
661 | OR1K_DELAYED( |
---|
662 | OR1K_INST(l.addi r3,r11,0), |
---|
663 | OR1K_INST(l.jal _exit) |
---|
664 | ) |
---|
665 | .exitcorelast: |
---|
666 | #endif |
---|
667 | /* If program exits, call exit routine */ |
---|
668 | OR1K_DELAYED( |
---|
669 | OR1K_INST(l.addi r3,r11,0), |
---|
670 | OR1K_INST(l.jal exit) |
---|
671 | ) |
---|
672 | |
---|
673 | /* Loop forever */ |
---|
674 | .Lloop_forever: |
---|
675 | OR1K_DELAYED_NOP(OR1K_INST(l.j .Lloop_forever)) |
---|
676 | |
---|
677 | .size _or1k_start,.-_or1k_start |
---|