1 | /* |
2 | * Copyright (C) 2009 Wind River Systems Inc |
3 | * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com |
4 | * Copyright (C) 2004 Microtronix Datacom Ltd |
5 | * Copyright (C) 2001 Vic Phillips, Microtronix Datacom Ltd. |
6 | * |
7 | * Based on head.S for Altera's Excalibur development board with nios processor |
8 | * |
9 | * Based on the following from the Excalibur sdk distribution: |
10 | * NA_MemoryMap.s, NR_JumpToStart.s, NR_Setup.s, NR_CWPManager.s |
11 | * |
12 | * This file is subject to the terms and conditions of the GNU General Public |
13 | * License. See the file "COPYING" in the main directory of this archive |
14 | * for more details. |
15 | */ |
16 | |
17 | #include <linux/init.h> |
18 | #include <linux/linkage.h> |
19 | #include <asm/thread_info.h> |
20 | #include <asm/processor.h> |
21 | #include <asm/cache.h> |
22 | #include <asm/page.h> |
23 | #include <asm/asm-offsets.h> |
24 | #include <asm/asm-macros.h> |
25 | |
26 | /* |
27 | * ZERO_PAGE is a special page that is used for zero-initialized |
28 | * data and COW. |
29 | */ |
30 | .data |
31 | .global empty_zero_page |
32 | .align 12 |
33 | empty_zero_page: |
34 | .space PAGE_SIZE |
35 | |
36 | /* |
37 | * This global variable is used as an extension to the nios' |
38 | * STATUS register to emulate a user/supervisor mode. |
39 | */ |
40 | .data |
41 | .align 2 |
42 | .set noat |
43 | |
44 | .global _current_thread |
45 | _current_thread: |
46 | .long 0 |
47 | /* |
48 | * Input(s): passed from u-boot |
49 | * r4 - Optional pointer to a board information structure. |
50 | * r5 - Optional pointer to the physical starting address of the init RAM |
51 | * disk. |
52 | * r6 - Optional pointer to the physical ending address of the init RAM |
53 | * disk. |
54 | * r7 - Optional pointer to the physical starting address of any kernel |
55 | * command-line parameters. |
56 | */ |
57 | |
58 | /* |
59 | * First executable code - detected and jumped to by the ROM bootstrap |
60 | * if the code resides in flash (looks for "Nios" at offset 0x0c from |
61 | * the potential executable image). |
62 | */ |
63 | __HEAD |
64 | ENTRY(_start) |
65 | wrctl status, r0 /* Disable interrupts */ |
66 | |
67 | /* Initialize all cache lines within the instruction cache */ |
68 | movia r1, NIOS2_ICACHE_SIZE |
69 | movui r2, NIOS2_ICACHE_LINE_SIZE |
70 | |
71 | icache_init: |
72 | initi r1 |
73 | sub r1, r1, r2 |
74 | bgt r1, r0, icache_init |
75 | br 1f |
76 | |
77 | /* |
78 | * This is the default location for the exception handler. Code in jump |
79 | * to our handler |
80 | */ |
81 | ENTRY(exception_handler_hook) |
82 | movia r24, inthandler |
83 | jmp r24 |
84 | |
85 | ENTRY(fast_handler) |
86 | nextpc et |
87 | helper: |
88 | stw r3, r3save - helper(et) |
89 | |
90 | rdctl r3 , pteaddr |
91 | srli r3, r3, 12 |
92 | slli r3, r3, 2 |
93 | movia et, pgd_current |
94 | |
95 | ldw et, 0(et) |
96 | add r3, et, r3 |
97 | ldw et, 0(r3) |
98 | |
99 | rdctl r3, pteaddr |
100 | andi r3, r3, 0xfff |
101 | add et, r3, et |
102 | ldw et, 0(et) |
103 | wrctl tlbacc, et |
104 | nextpc et |
105 | helper2: |
106 | ldw r3, r3save - helper2(et) |
107 | subi ea, ea, 4 |
108 | eret |
109 | r3save: |
110 | .word 0x0 |
111 | ENTRY(fast_handler_end) |
112 | |
113 | 1: |
114 | /* |
115 | * After the instruction cache is initialized, the data cache must |
116 | * also be initialized. |
117 | */ |
118 | movia r1, NIOS2_DCACHE_SIZE |
119 | movui r2, NIOS2_DCACHE_LINE_SIZE |
120 | |
121 | dcache_init: |
122 | initd 0(r1) |
123 | sub r1, r1, r2 |
124 | bgt r1, r0, dcache_init |
125 | |
126 | nextpc r1 /* Find out where we are */ |
127 | chkadr: |
128 | movia r2, chkadr |
129 | beq r1, r2,finish_move /* We are running in RAM done */ |
130 | addi r1, r1,(_start - chkadr) /* Source */ |
131 | movia r2, _start /* Destination */ |
132 | movia r3, __bss_start /* End of copy */ |
133 | |
134 | loop_move: /* r1: src, r2: dest, r3: last dest */ |
135 | ldw r8, 0(r1) /* load a word from [r1] */ |
136 | stw r8, 0(r2) /* store a word to dest [r2] */ |
137 | flushd 0(r2) /* Flush cache for safety */ |
138 | addi r1, r1, 4 /* inc the src addr */ |
139 | addi r2, r2, 4 /* inc the dest addr */ |
140 | blt r2, r3, loop_move |
141 | |
142 | movia r1, finish_move /* VMA(_start)->l1 */ |
143 | jmp r1 /* jmp to _start */ |
144 | |
145 | finish_move: |
146 | |
147 | /* Mask off all possible interrupts */ |
148 | wrctl ienable, r0 |
149 | |
150 | /* Clear .bss */ |
151 | movia r2, __bss_start |
152 | movia r1, __bss_stop |
153 | 1: |
154 | stb r0, 0(r2) |
155 | addi r2, r2, 1 |
156 | bne r1, r2, 1b |
157 | |
158 | movia r1, init_thread_union /* set stack at top of the task union */ |
159 | addi sp, r1, THREAD_SIZE |
160 | movia r2, _current_thread /* Remember current thread */ |
161 | stw r1, 0(r2) |
162 | |
163 | movia r1, nios2_boot_init /* save args r4-r7 passed from u-boot */ |
164 | callr r1 |
165 | |
166 | movia r1, start_kernel /* call start_kernel as a subroutine */ |
167 | callr r1 |
168 | |
169 | /* If we return from start_kernel, break to the oci debugger and |
170 | * buggered we are. |
171 | */ |
172 | break |
173 | |
174 | /* End of startup code */ |
175 | .set at |
176 | |