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