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