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