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