1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - OS
3 File: os_exception.c
4
5 Copyright 2003-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2009-06-19#$
14 $Rev: 10786 $
15 $Author: okajima_manabu $
16 *---------------------------------------------------------------------------*/
17 #include <nitro/hw/common/armArch.h>
18 #include <nitro/memorymap.h>
19 #include <nitro/os.h>
20
21 //#define OSiDEBUG
22
23 //---- Displaying function OSi_ExPrintf
24 #ifdef SDK_ARM9
25 #define OSi_ExPrintf( ... ) OS_FPrintf(OS_PRINT_OUTPUT_ERROR, __VA_ARGS__)
26 #else /* SDK_ARM7 */
27 #define OSi_ExPrintf( ... ) OS_TPrintf(__VA_ARGS__)
28 #endif
29
30 static asm void OSi_ExceptionHandler( void );
31 static asm void OSi_GetAndDisplayContext( void );
32 static asm void OSi_SetExContext( void );
33 static void OSi_DisplayExContext( void );
34
35
36 //---- Context for exception display
37 typedef struct
38 {
39 OSContext context;
40 u32 cp15;
41 u32 spsr;
42 u32 exinfo;
43 #ifdef OSiDEBUG
44 u32 debug[4];
45 #endif
46 } OSiExContext;
47
48 static OSiExContext OSi_ExContext;
49
50 //---- User's exception handler
51 static OSExceptionHandler OSi_UserExceptionHandler;
52 static void *OSi_UserExceptionHandlerArg;
53
54 //---- Debugger's exception handler
55 static void *OSi_DebuggerHandler = NULL;
56
57 //================================================================================
58 // Exception vector
59 //================================================================================
60 /*---------------------------------------------------------------------------*
61 Name: OS_SetExceptionVectorUpper
62
63 Description: Sets exception vector to high address.
64
65 Arguments: None.
66
67 Returns: None.
68 *---------------------------------------------------------------------------*/
69 #include <nitro/code32.h>
OS_SetExceptionVectorUpper(void)70 asm void OS_SetExceptionVectorUpper( void )
71 {
72 mrc p15, 0, r0, c1, c0, 0
73 orr r0, r0, #HW_C1_EXCEPT_VEC_UPPER
74 mcr p15, 0, r0, c1, c0, 0
75 bx lr
76 }
77
78 /*---------------------------------------------------------------------------*
79 Name: OS_SetExceptionVectorLower
80
81 Description: Sets exception vector to low address.
82
83 Arguments: None.
84
85 Returns: None.
86 *---------------------------------------------------------------------------*/
OS_SetExceptionVectorLower(void)87 asm void OS_SetExceptionVectorLower( void )
88 {
89 mrc p15, 0, r0, c1, c0, 0
90 bic r0, r0, #HW_C1_EXCEPT_VEC_UPPER
91 mcr p15, 0, r0, c1, c0, 0
92 bx lr
93 }
94 #include <nitro/codereset.h>
95
96
97 //================================================================================
98 // Exception handling
99 //================================================================================
100 /*---------------------------------------------------------------------------*
101 Name: OS_InitException
102
103 Description: Initializes exception-handling system.
104
105 Arguments: None.
106
107 Returns: None.
108 *---------------------------------------------------------------------------*/
OS_InitException(void)109 void OS_InitException(void)
110 {
111 #ifdef SDK_ARM9
112 u32* excpPtr = (u32*)HW_EXCP_VECTOR_MAIN;
113 #else
114 u32* excpPtr = (u32*)HW_EXCP_VECTOR_BUF;
115 #endif
116 u32 ex = *(u32*)HW_EXCP_VECTOR_MAIN;
117
118 //---- Consider for IS-NITRO-DEBUGGER exception handler
119 OSi_DebuggerHandler = (void*)( (0x2600000 <= ex && ex < 0x2800000)? ex: NULL );
120
121 if ( OSi_DebuggerHandler == NULL )
122 {
123 *excpPtr = (u32)OSi_ExceptionHandler;
124 #ifdef SDK_ARM9
125 if ( ! OS_IsRunOnTwl() )
126 {
127 *(u32*)((u32)excpPtr & ~0x800000) = (u32)OSi_ExceptionHandler;
128 }
129 #endif
130 }
131
132 //---- User's handler
133 OSi_UserExceptionHandler = NULL;
134 }
135
136 #if defined(SDK_ARM9)
137 /*
138 * Make a self-determination and call a user handler before passing a control to the debugger.
139 * However, the following undefined commands are breakpoints and will be ignored.
140 * +-------------------+------------+--------+
141 * | debugger | ARM | THUMB |
142 * +-------------------+------------+--------+
143 * | CodeWarrior -1.1 | 0xE6000010 | 0xBE00 |
144 * | CodeWarrior 1.2- | 0xE7FDDEFE | 0xDEFE |
145 * | IS-NITRO-DEBUGGER | 0xE7FFFFFF | 0xEFFF |
146 * +-------------------+------------+--------+
147 */
148 /*---------------------------------------------------------------------------*
149 Name: OSi_DebuggerExceptionHook
150
151 Description: Exception hook that calls user handler before debugger handler.
152
153 Arguments: None.
154
155 Returns: None.
156 *---------------------------------------------------------------------------*/
157 #include <nitro/code32.h>
158 static u32 OSi_ExceptionHookStack[8];
OSi_DebuggerExceptionHook(void)159 asm static void OSi_DebuggerExceptionHook(void)
160 {
161 /* Carefully save the work register such that sp is not changed */
162 ldr r12, =OSi_ExceptionHookStack
163 stmia r12, {r0-r4,sp,lr}
164 mrs r4, CPSR
165 /*
166 * Determine whether there is an exception that the user should be notified of.
167 * - Exceptions the user should be notified of are either ABT (abort) or UND (undefined command).
168 * - UND may occur as a result of a breakpoint.
169 * - No notification should be made to the user for UND and breakpoint commands.
170 */
171 mrs r0, CPSR
172 and r0, r0, #0x1f
173 teq r0, #0x17
174 beq user_exception
175 teq r0, #0x1b
176 bne user_exception_end
177 is_und:
178 /* Determinations for both ARM/THUMB and IS-NITRO-DEBUGGER/CodeWarrior */
179 bic r0, sp, #1
180 ldr r1, [r0, #4]
181 ldr r0, [r0, #12]
182 tst r1, #0x20
183 beq is_und_arm
184 is_und_thumb:
185 bic r0, r0, #1
186 ldrh r0, [r0, #-2]
187 ldr r1, =0x0000EFFF
188 cmp r0, r1
189 beq user_exception_end
190 ldr r1, =0x0000DEFE
191 cmp r0, r1
192 beq user_exception_end
193 ldr r1, =0x0000BE00
194 cmp r0, r1
195 beq user_exception_end
196 b user_exception
197 is_und_arm:
198 bic r0, r0, #3
199 ldr r0, [r0, #-4]
200 ldr r1, =0xE7FFFFFF
201 cmp r0, r1
202 beq user_exception_end
203 ldr r1, =0xE7FDDEFE
204 cmp r0, r1
205 beq user_exception_end
206 ldr r1, =0xE6000010
207 cmp r0, r1
208 beq user_exception_end
209 b user_exception
210 user_exception:
211 /* Notification to the user's exception handler */
212 ldmia r12, {r0-r1}
213 ldr r12, =HW_ITCM_END
214 stmfd r12!, {r0-r3,sp,lr}
215 and r0, sp, #1
216 mov sp, r12
217 bl OSi_GetAndDisplayContext
218 ldmfd sp!, {r0-r3,r12,lr}
219 mov sp, r12
220 user_exception_end:
221 /* Restore the saved work register and pass the original control to the debugger */
222 msr CPSR_cxsf, r4
223 ldr r12, =OSi_ExceptionHookStack
224 ldmia r12, {r0-r4,sp,lr}
225 ldr r12, =OSi_DebuggerHandler
226 ldr r12, [r12]
227 cmp r12, #0
228 bxne r12
229 bx lr
230 }
231 #include <nitro/codereset.h>
232
233 /*---------------------------------------------------------------------------*
234 Name: OS_EnableUserExceptionHandlerOnDebugger
235
236 Description: Enables user exception handler even if running on the debugger.
237
238 Arguments: None.
239
240 Returns: None.
241 *---------------------------------------------------------------------------*/
OS_EnableUserExceptionHandlerOnDebugger(void)242 void OS_EnableUserExceptionHandlerOnDebugger(void)
243 {
244 if (OSi_DebuggerHandler)
245 {
246 *(u32*)(HW_EXCP_VECTOR_MAIN) = (u32)OSi_DebuggerExceptionHook;
247 }
248 }
249 #endif /* defined(SDK_ARM9) */
250
251 /*---------------------------------------------------------------------------*
252 Name: OS_SetUserExceptionHandler
253
254 Description: Sets user exception handler and its argument.
255
256 Arguments: handler: Exception hander
257 arg: Its argument
258
259 Returns: None.
260 *---------------------------------------------------------------------------*/
OS_SetUserExceptionHandler(OSExceptionHandler handler,void * arg)261 void OS_SetUserExceptionHandler(OSExceptionHandler handler, void *arg)
262 {
263 OSi_UserExceptionHandler = handler;
264 OSi_UserExceptionHandlerArg = arg;
265 }
266
267 /*---------------------------------------------------------------------------*
268 Name: OSi_ExceptionHandler
269
270 Description: System exception handler.
271 User handler is called from here.
272
273 Arguments: None.
274
275 Returns: None.
276 *---------------------------------------------------------------------------*/
277 //
278 // Status of stack is {cp15,spsr,r12,lr}
279 // LSB = 1 means coming by reset
280 //
281 #include <nitro/code32.h>
OSi_ExceptionHandler(void)282 asm void OSi_ExceptionHandler( void )
283 {
284 //---- Call debugger monitor handler (if exists)
285 ldr r12, =OSi_DebuggerHandler // Only r12 can be destructed
286 ldr r12, [r12]
287 cmp r12, #0
288 movne lr, pc
289 bxne r12
290
291 //---- Setting stack pointer <------------------------- consider later
292 #ifdef SDK_ARM9
293 //---- ARM9 stack
294 ldr r12, =HW_ITCM_END
295 #else
296 //---- ARM7 stack
297 ldr r12, =0x3806000
298 #endif
299 stmfd r12!, {r0-r3,sp,lr}
300
301 and r0, sp, #1
302 mov sp, r12
303
304 mrs r1, CPSR
305 and r1, r1, #0x1f
306
307 //---- If ABORT exception, stop
308 teq r1, #0x17
309 bne @10
310 bl OSi_GetAndDisplayContext
311 b usr_return
312
313 @10:
314 //---- If UNDEF exception, stop
315 teq r1, #0x1b
316 bne usr_return
317 bl OSi_GetAndDisplayContext
318
319 usr_return:
320 ldr r12, =OSi_DebuggerHandler
321 ldr r12, [r12]
322 cmp r12, #0
323 @1: beq @1
324
325 //(Stop now even if debugger)
326 @2:
327 mov r0,r0 // Nop
328 b @2
329
330 ldmfd sp!, {r0-r3, r12, lr}
331 mov sp, r12
332 bx lr
333 }
334
335 /*---------------------------------------------------------------------------*
336 Name: OSi_GetAndDisplayContext
337
338 Description: Stops after displaying registers.
339
340 Arguments: None.
341
342 Returns: None.
343 *---------------------------------------------------------------------------*/
OSi_GetAndDisplayContext(void)344 static asm void OSi_GetAndDisplayContext( void )
345 {
346 stmfd sp!, {r0, lr} /* 8-byte alignment of the call stack */
347
348 //---- Set exception context
349 bl OSi_SetExContext
350 //---- Display exception context (and call user callback)
351 bl OSi_DisplayExContext
352
353 ldmfd sp!, {r0, lr} /* 8-byte alignment of the call stack */
354 bx lr
355 }
356
357 /*---------------------------------------------------------------------------*
358 Name: OSi_SetExContext
359
360 Description: Sets context when exception occurred.
361
362 Arguments: None.
363
364 Returns: None.
365 *---------------------------------------------------------------------------*/
366 // Explanation registers at the top of this function.
367 //
368 // In r12, {r0-r3,sp} (sp is exception sp) stored.
369 // In this sp, {cp15,spsr,r12,lr} (cp15,spsr,r12,lr is registers when exception occurred) stored.
370 // r4-r11 is registers then exception occurred.
371 // If you want to know spsr,sp,lr, please switch bank and read.
372 //
OSi_SetExContext(void)373 static asm void OSi_SetExContext( void )
374 {
375 //---- Pointer ExContext structure
376 ldr r1, =OSi_ExContext;
377
378 #ifdef OSiDEBUG
379 //---- (For debug)
380 mrs r2, CPSR
381 str r2, [r1, #OSiExContext.debug[1] ]
382 #endif
383
384 //---- Store bit which means which is the reason, reset or exception
385 str r0, [r1, #OSiExContext.exinfo ]
386
387 //---- Store r0 - r3
388 ldr r0, [r12,#0]
389 str r0, [r1, #OS_CONTEXT_R0]
390 ldr r0, [r12,#4]
391 str r0, [r1, #OS_CONTEXT_R1]
392 ldr r0, [r12,#8]
393 str r0, [r1, #OS_CONTEXT_R2]
394 ldr r0, [r12, #12]
395 str r0, [r1, #OS_CONTEXT_R3]
396 ldr r2, [r12, #16]
397 bic r2, r2, #1
398
399 //---- Store r4 - r11
400 add r0, r1, #OS_CONTEXT_R4
401 stmia r0, {r4-r11}
402
403 #ifdef OSiDEBUG
404 //---- (For debug)
405 str r12, [r1, #OSiExContext.debug[0] ]
406 #endif
407
408 #ifdef SDK_ARM9
409 //---- Get {cp15,cpsr,r12,pc} from stack
410 ldr r0, [r2, #0]
411 str r0, [r1, #OSiExContext.cp15 ]
412 ldr r3, [r2, #4]
413 str r3, [r1, #OS_CONTEXT_CPSR]
414 ldr r0, [r2, #8]
415 str r0, [r1, #OS_CONTEXT_R12]
416 ldr r0, [r2, #12]
417 str r0, [r1, #OS_CONTEXT_PC_PLUS4]
418 #else // ifdef SDK_ARM9
419 //---- Get {cpsr,r12,pc} from stack
420 mov r0, #0
421 str r0, [r1, #OSiExContext.cp15]
422 ldr r3, [r2, #0]
423 str r3, [r1, #OS_CONTEXT_CPSR]
424 ldr r0, [r2, #4]
425 str r0, [r1, #OS_CONTEXT_R12]
426 ldr r0, [r2, #8]
427 str r0, [r1, #OS_CONTEXT_PC_PLUS4]
428 #endif // ifdef SDK_ARM9
429
430 //---- Set mode to one which exception occurred,
431 // but disable IRQ
432 mrs r0, CPSR
433 orr r3, r3, #0x80
434 bic r3, r3, #0x20
435 msr CPSR_cxsf, r3
436
437 //---- Get sp, lr, spsr
438 str sp, [r1, #OS_CONTEXT_R13]
439 str lr, [r1, #OS_CONTEXT_R14]
440 mrs r2, SPSR
441
442 #ifdef OSiDEBUG
443 //---- (For debug)
444 str r2, [r1, #OSiExContext.debug[3] ]
445 #endif
446
447 //---- Restore mode
448 msr CPSR_cxsf, r0
449 bx lr
450 }
451
452 /*---------------------------------------------------------------------------*
453 Name: OSi_DisplayExContext
454
455 Description: Stops after display exception context.
456
457 Arguments: None.
458
459 Returns: None.
460 *---------------------------------------------------------------------------*/
OSi_DisplayExContext()461 static void OSi_DisplayExContext()
462 {
463 #ifndef SDK_FINALROM
464 int i;
465
466 OSi_ExPrintf("**** Exception Occurred ****\n");
467
468 //---------------- Displaying registers
469 //---- For R0-15 Registers
470 for (i = 0; i < 13; i++)
471 {
472 OSi_ExPrintf("R%02d=%08X %c", i, OSi_ExContext.context.r[i], ((i & 3) == 3) ? '\n' : ' ');
473 }
474 OSi_ExPrintf("SP =%08X ", OSi_ExContext.context.sp);
475 OSi_ExPrintf("LR =%08X ", OSi_ExContext.context.lr);
476 OSi_ExPrintf("PC =%08X\n", OSi_ExContext.context.pc_plus4);
477
478 //---- For status Registers
479 #ifdef SDK_ARM9
480 OSi_ExPrintf(" CPSR=%08X SPSR=%08X CP15=%08X\n",
481 OSi_ExContext.context.cpsr, OSi_ExContext.spsr, OSi_ExContext.cp15);
482 #else
483 OSi_ExPrintf(" CPSR=%08X SPSR=%08X\n", OSi_ExContext.context.cpsr, OSi_ExContext.spsr);
484 #endif
485
486 #ifdef OSiDEBUG
487 //---- (For debug)
488 for (i = 0; i < 4; i++)
489 {
490 OSi_ExPrintf("DEBUG%02d=%08X ", i, OSi_ExContext.debug[i]);
491 }
492 #endif
493 OSi_ExPrintf("\n\n");
494 #endif
495
496 //---------------- User's callback
497 if (OSi_UserExceptionHandler)
498 {
499 //---- Force to become SYS mode,
500 // but use current stack not SYS mode stack
501 asm
502 {
503 /* *INDENT-OFF* */
504
505 //---- Save cpsr and sp
506 mrs r2, CPSR
507 mov r0, sp
508 ldr r1, =0x9f
509 msr CPSR_cxsf, r1
510 mov r1, sp
511 mov sp, r0
512 stmfd sp!, {r1,r2}
513 #ifdef SDK_ARM9
514 bl OS_EnableProtectionUnit
515 #endif
516 //---- Context
517 ldr r0, =OSi_ExContext
518
519 //---- Arg
520 ldr r1, =OSi_UserExceptionHandlerArg
521 ldr r1, [r1]
522
523 //---- User handler
524 ldr r12, =OSi_UserExceptionHandler
525 ldr r12, [r12]
526 ldr lr, =@1
527 bx r12
528 @1:
529 #ifdef SDK_ARM9
530 bl OS_DisableProtectionUnit
531 #endif
532
533 //---- Restore cpsr and sp
534 ldmfd sp!, {r1,r2}
535 mov sp, r1
536 msr CPSR_cxsf, r2
537 /* *INDENT-ON* */
538 }
539 }
540
541 }
542
543 #include <nitro/codereset.h>
544