2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
6 #include <exec/alerts.h>
7 #include <exec/execbase.h>
8 #include <hardware/intbits.h>
9 #include <proto/exec.h>
13 #include "../exec/etask.h"
15 #include "kernel_base.h"
16 #include "kernel_debug.h"
17 #include "kernel_intern.h"
18 #include "kernel_intr.h"
19 #include "kernel_scheduler.h"
24 * Task exception handler.
25 * Exceptions work in a way similar to MinGW32 port. We can't manipulate stack inside
26 * UNIX signal handler, because context's SP is set to a point where it was at the moment
27 * when signal was caught. Signal handler uses some processes' stack space by itself, and
28 * if we try to use some space below SP, we will clobber signal handler's stack.
29 * In order to overcome this we disable interrupts and jump to exception handler. Since
30 * interrupts are disabled, iet_Context of our task still contains original context (saved
31 * at the moment of task switch). In our exception handler we already left the signal handler,
32 * so we can allocate some storage on stack and place our context there. After this we call
34 * When we return, we place our saved context back into iet_Context and cause a SysCall (SIGUSR1)
35 * with a special TS_EXCEPT state. SysCall handler will know then that it needs just to dispatch
36 * the same task with the saved context (see cpu_DispatchContext() routine).
38 static void cpu_Exception(void)
40 /* Save return context and IDNestCnt on stack */
41 struct Task
*task
= SysBase
->ThisTask
;
42 char nestCnt
= task
->tc_IDNestCnt
;
43 char save
[KernelBase
->kb_ContextSize
];
46 /* Save original context */
47 CopyMem(GetIntETask(task
)->iet_Context
, save
, KernelBase
->kb_ContextSize
);
48 savesp
= task
->tc_SPReg
;
52 /* Restore saved task state and resume it. Note that interrupts are
53 disabled again here */
54 task
->tc_IDNestCnt
= nestCnt
;
55 SysBase
->IDNestCnt
= nestCnt
;
57 /* Restore saved context */
58 CopyMem(&save
, GetIntETask(task
)->iet_Context
, KernelBase
->kb_ContextSize
);
59 task
->tc_SPReg
= savesp
;
61 /* This tells task switcher that we are returning from the exception */
62 SysBase
->ThisTask
->tc_State
= TS_EXCEPT
;
65 KernelIFace
.raise(SIGUSR1
);
69 void cpu_Switch(regs_t
*regs
)
71 struct Task
*task
= SysBase
->ThisTask
;
72 struct AROSCPUContext
*ctx
= GetIntETask(task
)->iet_Context
;
74 D(bug("[KRN] cpu_Switch(), task %p (%s)\n", task
, task
->tc_Node
.ln_Name
));
78 ctx
->errno_backup
= *KernelBase
->kb_PlatformData
->errnoPtr
;
79 task
->tc_SPReg
= (APTR
)SP(regs
);
83 void cpu_Dispatch(regs_t
*regs
)
90 while (!(task
= core_Dispatch()))
92 /* Sleep almost forever ;) */
93 KernelIFace
.sigsuspend(&sigs
);
96 if (SysBase
->SysFlags
& SFF_SoftInt
)
97 core_Cause(INTB_SOFTINT
, 1L << INTB_SOFTINT
);
100 D(bug("[KRN] cpu_Dispatch(), task %p (%s)\n", task
, task
->tc_Node
.ln_Name
));
101 cpu_DispatchContext(task
, regs
);
104 void cpu_DispatchContext(struct Task
*task
, regs_t
*regs
)
106 struct AROSCPUContext
*ctx
= GetIntETask(task
)->iet_Context
;
108 RESTOREREGS(ctx
, regs
);
109 *KernelBase
->kb_PlatformData
->errnoPtr
= ctx
->errno_backup
;
113 if (task
->tc_Flags
& TF_EXCEPT
)
115 /* Disable interrupts, otherwise we may lose saved context */
116 SysBase
->IDNestCnt
= 0;
118 /* Manipulate the current cpu context so Exec_Exception gets
119 excecuted after we leave the kernel resp. the signal handler. */
120 PC(regs
) = (IPTR
)cpu_Exception
;
123 /* Adjust user mode interrupts state */
124 if (SysBase
->IDNestCnt
< 0) {