1 | /* |
---|
2 | * __cpu_kentry.S - unified kernel entry point |
---|
3 | * |
---|
4 | * Author Ghassan Almaless (2007,2008,2009,2010,2011,2012) |
---|
5 | * |
---|
6 | * Copyright (c) UPMC Sorbonne Universites |
---|
7 | * |
---|
8 | * This file is part of ALMOS-kernel. |
---|
9 | * |
---|
10 | * ALMOS-kernel is free software; you can redistribute it and/or modify it |
---|
11 | * under the terms of the GNU General Public License as published by |
---|
12 | * the Free Software Foundation; version 2.0 of the License. |
---|
13 | * |
---|
14 | * ALMOS-kernel is distributed in the hope that it will be useful, but |
---|
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
17 | * General Public License for more details. |
---|
18 | * |
---|
19 | * You should have received a copy of the GNU General Public License |
---|
20 | * along with ALMOS-kernel; if not, write to the Free Software Foundation, |
---|
21 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
---|
22 | */ |
---|
23 | |
---|
24 | #include <cpu-regs.h> |
---|
25 | #define _ALMOS_ASM_ |
---|
26 | #include <boot-info.h> |
---|
27 | |
---|
28 | #--------------------------------------------------------------------------------- |
---|
29 | # This file defines the unique kernel entry point in case of |
---|
30 | # Exception / Interrupt/Syscall for a MIPS32 processor core. |
---|
31 | # The base address of the segment containing this code TODO [AG] |
---|
32 | #--------------------------------------------------------------------------------- |
---|
33 | |
---|
34 | .section .kentry,"ax",@progbits |
---|
35 | .extern cpu_do_interrupt |
---|
36 | .extern cpu_do_exception |
---|
37 | .extern cpu_do_syscall |
---|
38 | .extern cpu_kentry |
---|
39 | .extern cpu_kexit |
---|
40 | .org 0x180 |
---|
41 | .ent kentry |
---|
42 | .global kentry |
---|
43 | .global kentry_load |
---|
44 | .set noat |
---|
45 | .set noreorder |
---|
46 | |
---|
47 | #define SAVE_SIZE REGS_NR*4 |
---|
48 | |
---|
49 | #FIXME: PROC_WIDTH support only 4 proc clusters! |
---|
50 | |
---|
51 | #define PROC_WIDTH 2 |
---|
52 | #define XY_WIDTH 8 |
---|
53 | #define XY_MASK 0xFF |
---|
54 | #define MMU_MD_MASK 0xF |
---|
55 | |
---|
56 | #------------------------------------------------------------------------------- |
---|
57 | # Kernel Entry point |
---|
58 | #------------------------------------------------------------------------------- |
---|
59 | kentry: |
---|
60 | mfc0 $26, $12 # read SR |
---|
61 | andi $26, $26, 0x10 # KSU bitmask |
---|
62 | beq $26, $0, KERNEL_MODE |
---|
63 | ori $26, $0, 0x3 # MMU OFF value |
---|
64 | |
---|
65 | |
---|
66 | LOAD_KERNEL_STACK: |
---|
67 | mtc2 $26, $1 # set MMU OFF |
---|
68 | nop |
---|
69 | mfc0 $26, $4, # read current thread pointer ($26) |
---|
70 | sw $27, (TLS_K1*4)($26) # save user value |
---|
71 | |
---|
72 | #$27 register can now be used |
---|
73 | sw $29, (SP*4)($26) # save user stack |
---|
74 | lw $29, (KSP*4)($26) # read kernel stack |
---|
75 | |
---|
76 | ori $27, $0, 0xF # MMU old value: assumed ON |
---|
77 | sw $27, (MMU_MD*4)($26) # save MMU MODE |
---|
78 | |
---|
79 | j UNIFIED_MODE |
---|
80 | or $27, $0, $26 # pointer to uzone ($27) |
---|
81 | |
---|
82 | #Use only $26 to save two values: MMU_MODE (4 bits) and XY_DATA_EXT (8bits) |
---|
83 | #$26 content (in hex): 0x00000MXY (M is the value of MMU_MODE and XY is ...) |
---|
84 | #N.B: MMU MODE is also modified by cpu_do_exception |
---|
85 | |
---|
86 | KERNEL_MODE: |
---|
87 | #get old PADDR_EXT (in $26 at bits 0-7) |
---|
88 | and $26, $26, $0 # $26 <= 0x00000000 |
---|
89 | mfc2 $26, $24 # $26 <= 0x??????XY |
---|
90 | andi $26, $26, XY_MASK # $26 <= 0x000000XY |
---|
91 | #set PADDR_EXT to point to local mem |
---|
92 | mfc0 $27, $15, 1 # read ebase |
---|
93 | andi $27, $27, 0xFFF # extract arch cpu id |
---|
94 | srl $27, $27, PROC_WIDTH # extract cluster xy |
---|
95 | mtc2 $27, $24 # set XY PADDR_EXT |
---|
96 | |
---|
97 | #get old MMU MODE (in $26 at bits 8-11) |
---|
98 | mfc2 $27, $1 # get MMU MODE old value |
---|
99 | andi $27, $27, MMU_MD_MASK # $27 <= 0x0000000M |
---|
100 | sll $27, $27, XY_WIDTH # $27 <= 0x00000M00 |
---|
101 | or $26, $26, $27 # $26 <= 0x00000MXY <= (0x000000XY or 0x00000M00) |
---|
102 | #set MMU OFF |
---|
103 | ori $27, $0, 0x3 # MMU OFF value |
---|
104 | mtc2 $27, $1 # set MMU OFF |
---|
105 | |
---|
106 | #save old stack, MMU_MODE and PADDR_EXT |
---|
107 | addiu $27, $29, -(SAVE_SIZE) # allocate a region on stack ($27) |
---|
108 | sw $29, (SP*4)($27) # save old stack ($29 can be used) |
---|
109 | |
---|
110 | srl $29, $26, XY_WIDTH # $29 <= 0x0000000M |
---|
111 | sw $29, (MMU_MD*4)($27) # save MMU MODE |
---|
112 | andi $26, $26, XY_MASK # $26 <= 0x000000XY |
---|
113 | sw $26, (DP_EXT*4)($27) # save old DATA PADDR EXT (0x000000XY) |
---|
114 | |
---|
115 | or $29, $27, $0 # set new stack |
---|
116 | mfc0 $26, $4, 2 # $26 <= this thread pointer |
---|
117 | |
---|
118 | # $27: zone for saving the cpu registers |
---|
119 | # $26: current thread pointer ($this) |
---|
120 | # $29: kstack |
---|
121 | |
---|
122 | UNIFIED_MODE: |
---|
123 | sw $1, (AT*4)($27) |
---|
124 | sw $2, (V0*4)($27) |
---|
125 | sw $3, (V1*4)($27) |
---|
126 | sw $4, (A0*4)($27) |
---|
127 | sw $5, (A1*4)($27) |
---|
128 | sw $6, (A2*4)($27) |
---|
129 | sw $7, (A3*4)($27) |
---|
130 | sw $8, (T0*4)($27) |
---|
131 | sw $9, (T1*4)($27) |
---|
132 | sw $10, (T2*4)($27) |
---|
133 | sw $11, (T3*4)($27) |
---|
134 | sw $12, (T4*4)($27) |
---|
135 | sw $13, (T5*4)($27) |
---|
136 | sw $14, (T6*4)($27) |
---|
137 | sw $15, (T7*4)($27) |
---|
138 | sw $24, (T8*4)($27) |
---|
139 | sw $25, (T9*4)($27) |
---|
140 | sw $16, (S0*4)($27) |
---|
141 | sw $17, (S1*4)($27) |
---|
142 | sw $18, (S2*4)($27) |
---|
143 | sw $19, (S3*4)($27) |
---|
144 | sw $20, (S4*4)($27) |
---|
145 | sw $21, (S5*4)($27) |
---|
146 | sw $22, (S6*4)($27) |
---|
147 | sw $23, (S7*4)($27) |
---|
148 | sw $30, (S8*4)($27) |
---|
149 | sw $28, (GP*4)($27) |
---|
150 | sw $31, (RA*4)($27) # save RA |
---|
151 | |
---|
152 | mfc0 $16, $14 # Read EPC |
---|
153 | sw $16, (EPC*4)($27) # Save EPC |
---|
154 | mflo $14 # read LO |
---|
155 | sw $14, (LO*4)($27) # save LO |
---|
156 | mfhi $15 # read HI |
---|
157 | sw $15, (HI*4)($27) # save HI |
---|
158 | |
---|
159 | mfc0 $18, $12 # Read current SR |
---|
160 | sw $18, (SR*4)($27) # Save SR |
---|
161 | srl $3, $18, 5 # put SR in kernel mode, IRQ disabled, clear exl |
---|
162 | sll $3, $3, 5 # ... |
---|
163 | mtc0 $3, $12 # Set new SR |
---|
164 | |
---|
165 | mfc0 $17, $13 # read CR |
---|
166 | sw $17, (CR*4)($27) # Save CR |
---|
167 | andi $1, $17, 0x3F # $1 <= XCODE from CP0_CR |
---|
168 | |
---|
169 | #if CPU_IN_KERNEL |
---|
170 | # First signal that we are entering the kernel |
---|
171 | mfc0 $4, $15, 1 # $4 <= cpu_id |
---|
172 | andi $4, $4, 0x3 # mask all but CPU_local_id |
---|
173 | mfc0 $5, $4, 2 # read current thread pointer |
---|
174 | jal cpu_kentry |
---|
175 | addiu $29, $29, -8 |
---|
176 | addiu $29, $29, 8 |
---|
177 | #endif |
---|
178 | |
---|
179 | # Second, depending on XCODE, call the apropriate function |
---|
180 | ori $8, $0, 0x20 # cause syscall |
---|
181 | beq $8, $1, cause_sys |
---|
182 | or $19, $0, $27 # for kentry_exit |
---|
183 | mfc0 $5, $15, 1 |
---|
184 | andi $5, $5, 0x1FF # $5 (arg1) <= CPU(X,Y,lid) |
---|
185 | or $4, $0, $26 # $4 (arg0) <= this thread |
---|
186 | beq $1, $0, cause_int |
---|
187 | or $6, $0, $27 # $6 (arg2) <= regs_tbl |
---|
188 | |
---|
189 | # Exceptions Handler |
---|
190 | # --------------------------------------------- |
---|
191 | la $1, cpu_do_exception |
---|
192 | jalr $1 |
---|
193 | addiu $29, $29, -3*4 |
---|
194 | j kentry_exit |
---|
195 | addiu $29, $29, 3*4 |
---|
196 | |
---|
197 | # System Call Handler |
---|
198 | # ------------------------------------------------ |
---|
199 | cause_sys: |
---|
200 | la $14, cpu_do_syscall |
---|
201 | addiu $29, $29, -4 |
---|
202 | jalr $14 |
---|
203 | or $4, $0, $27 |
---|
204 | j kentry_exit |
---|
205 | or $19, $0, $2 |
---|
206 | |
---|
207 | # Interrupts Handler |
---|
208 | # ---------------------------------------------- |
---|
209 | cause_int: |
---|
210 | la $1, cpu_do_interrupt |
---|
211 | srl $7, $17, 10 # extract IP state, 4th arg |
---|
212 | addiu $29, $29, -4*4 # cpu_interrupt has 4 arg |
---|
213 | jal $1 |
---|
214 | andi $7, $7, 0x3F # 6 HW IRQ LINES, 2th arg is irq_state |
---|
215 | |
---|
216 | # Kentry exit |
---|
217 | # ---------------------------------------------- |
---|
218 | kentry_exit: |
---|
219 | #if CPU_IN_KERNEL |
---|
220 | # First signal that we are exiting from the kernel |
---|
221 | mfc0 $4, $15, 1 # arg is cpu_id |
---|
222 | andi $4, $4, 0x3 # mask all but CPU_local_id |
---|
223 | mfc0 $5, $4, 2 # read current thread pointer |
---|
224 | jal cpu_kexit |
---|
225 | addiu $29, $29, -8 |
---|
226 | addiu $29, $29, 8 |
---|
227 | #endif |
---|
228 | # Then load context ... |
---|
229 | or $27, $0, $19 |
---|
230 | lw $1, (AT*4)($27) |
---|
231 | lw $2, (V0*4)($27) |
---|
232 | lw $3, (V1*4)($27) |
---|
233 | lw $4, (A0*4)($27) |
---|
234 | lw $5, (A1*4)($27) |
---|
235 | lw $6, (A2*4)($27) |
---|
236 | lw $7, (A3*4)($27) |
---|
237 | lw $8, (T0*4)($27) |
---|
238 | lw $9, (T1*4)($27) |
---|
239 | lw $10, (T2*4)($27) |
---|
240 | lw $11, (T3*4)($27) |
---|
241 | lw $12, (T4*4)($27) |
---|
242 | lw $13, (T5*4)($27) |
---|
243 | lw $14, (T6*4)($27) |
---|
244 | lw $15, (T7*4)($27) |
---|
245 | lw $24, (T8*4)($27) |
---|
246 | lw $25, (T9*4)($27) |
---|
247 | lw $18, (S2*4)($27) |
---|
248 | lw $19, (S3*4)($27) |
---|
249 | lw $20, (S4*4)($27) |
---|
250 | lw $21, (S5*4)($27) |
---|
251 | lw $22, (S6*4)($27) |
---|
252 | lw $23, (S7*4)($27) |
---|
253 | lw $30, (S8*4)($27) |
---|
254 | lw $28, (GP*4)($27) |
---|
255 | lw $31, (RA*4)($27) |
---|
256 | lw $16, (EPC*4)($27) # load EPC |
---|
257 | lw $29, (SP*4)($27) # restore SP |
---|
258 | lw $17, (SR*4)($27) # load SR |
---|
259 | mfc0 $26, $12 # Read current SR |
---|
260 | andi $17, $17, 0x1F |
---|
261 | mtc0 $16, $14 # restore EPC |
---|
262 | or $26, $26, $17 |
---|
263 | lw $16, (LO*4)($27) # load LO |
---|
264 | mtc0 $26, $12 # setup new SR |
---|
265 | lw $17, (HI*4)($27) # load HI |
---|
266 | mtlo $16 # restore LO |
---|
267 | mthi $17 # restore HI |
---|
268 | |
---|
269 | lw $16, (S0*4)($27) |
---|
270 | lw $17, (S1*4)($27) |
---|
271 | |
---|
272 | #TODO: optimize |
---|
273 | lw $26, (MMU_MD*4)($27) # load MMU MODE |
---|
274 | andi $26, $26, 0xc |
---|
275 | beq $26, $0, OUT_MMU_3 # both MSB are 0 (the first two LSB are always set) |
---|
276 | andi $26, $26, 0x8 |
---|
277 | beq $26, $0, OUT_MMU_7 # first MSB is 0 (bit 2 is set) |
---|
278 | lw $26, (DP_EXT*4)($27) # load DP_EXT |
---|
279 | |
---|
280 | # Possible value for MMU: |
---|
281 | #In kernel mode : 0x7/0x3 |
---|
282 | #In user mode : 0xF |
---|
283 | |
---|
284 | # DP_EXT can either be local or remote |
---|
285 | #Once these register set we can no longer |
---|
286 | #access global data |
---|
287 | |
---|
288 | #If MMU mode was 0xF |
---|
289 | lw $27, (TLS_K1*4)($27) |
---|
290 | mtc2 $26, $24 # restore DP EXT |
---|
291 | ori $26, $0, 0xF # MMU 0xF value |
---|
292 | mtc2 $26, $1 # set MMU MODE |
---|
293 | j OUT_KENTRY |
---|
294 | nop |
---|
295 | |
---|
296 | OUT_MMU_7: |
---|
297 | #If MMU mode was 0x7 (uspace) |
---|
298 | lw $27, (TLS_K1*4)($27) |
---|
299 | mtc2 $26, $24 # restore DP EXT |
---|
300 | ori $26, $0, 0x7 # MMU 0x7 value |
---|
301 | mtc2 $26, $1 # set MMU MODE |
---|
302 | j OUT_KENTRY |
---|
303 | nop |
---|
304 | |
---|
305 | OUT_MMU_3: |
---|
306 | #If MMU mode was 0x3 |
---|
307 | lw $26, (DP_EXT*4)($27) # load DP_EXT |
---|
308 | lw $27, (TLS_K1*4)($27) |
---|
309 | mtc2 $26, $24 # restore DP EXT |
---|
310 | ori $26, $0, 0x3 # MMU 0x3 value |
---|
311 | mtc2 $26, $1 # set MMU MODE |
---|
312 | nop |
---|
313 | |
---|
314 | OUT_KENTRY: |
---|
315 | nop |
---|
316 | eret |
---|
317 | |
---|
318 | |
---|
319 | .end kentry |
---|
320 | .set reorder |
---|
321 | .set at |
---|
322 | |
---|
323 | .ent kentry_load |
---|
324 | kentry_load: |
---|
325 | #theses nops are required to load the eret instruction |
---|
326 | #while we are in virtual mode (processor pipeline) ? |
---|
327 | mtc2 $26, $1 # set MMU MODE |
---|
328 | nop |
---|
329 | nop |
---|
330 | eret |
---|
331 | .end kentry_load |
---|
332 | |
---|
333 | #------------------------------------------------------------------------------- |
---|
334 | |
---|