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