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 "kernel_base.h"
14 #include "kernel_debug.h"
15 #include "kernel_globals.h"
16 #include "kernel_intern.h"
17 #include "kernel_intr.h"
18 #include "kernel_scheduler.h"
23 * Task exception handler.
24 * Exceptions work in a way similar to MinGW32 port. We can't manipulate stack inside
25 * UNIX signal handler, because context's SP is set to a point where it was at the moment
26 * when signal was caught. Signal handler uses some processes' stack space by itself, and
27 * if we try to use some space below SP, we will clobber signal handler's stack.
28 * In order to overcome this we disable interrupts and jump to exception handler. Since
29 * interrupts are disabled, et_RegFrame of our task still contains original context (saved
30 * at the moment of task switch). In our exception handler we already left the signal handler,
31 * so we can allocate some storage on stack and place our context there. After this we call
33 * When we return, we place our saved context back into et_RegFrame and cause a SysCall (SIGUSR1)
34 * with a special TS_EXCEPT state. SysCall handler will know then that it needs just to dispatch
35 * the same task with the saved context (see cpu_DispatchContext() routine).
37 static void cpu_Exception(void)
39 struct KernelBase
*KernelBase
= getKernelBase();
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(task
->tc_UnionETask
.tc_ETask
->et_RegFrame
, 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
, task
->tc_UnionETask
.tc_ETask
->et_RegFrame
, 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 KernelBase
->kb_PlatformData
->iface
->raise(SIGUSR1
);
69 void cpu_Switch(regs_t
*regs
)
71 struct KernelBase
*KernelBase
= getKernelBase();
72 struct Task
*task
= SysBase
->ThisTask
;
73 struct AROSCPUContext
*ctx
= task
->tc_UnionETask
.tc_ETask
->et_RegFrame
;
75 D(bug("[KRN] cpu_Switch(), task %p (%s)\n", task
, task
->tc_Node
.ln_Name
));
79 ctx
->errno_backup
= *KernelBase
->kb_PlatformData
->errnoPtr
;
80 task
->tc_SPReg
= (APTR
)SP(regs
);
84 void cpu_Dispatch(regs_t
*regs
)
86 struct KernelBase
*KernelBase
= getKernelBase();
87 struct PlatformData
*pd
= KernelBase
->kb_PlatformData
;
91 /* This macro relies on 'pd' being present */
94 while (!(task
= core_Dispatch()))
96 /* Sleep almost forever ;) */
97 KernelBase
->kb_PlatformData
->iface
->sigsuspend(&sigs
);
100 if (SysBase
->SysFlags
& SFF_SoftInt
)
101 core_Cause(INTB_SOFTINT
, 1L << INTB_SOFTINT
);
104 D(bug("[KRN] cpu_Dispatch(), task %p (%s)\n", task
, task
->tc_Node
.ln_Name
));
105 cpu_DispatchContext(task
, regs
, pd
);
108 void cpu_DispatchContext(struct Task
*task
, regs_t
*regs
, struct PlatformData
*pd
)
110 struct AROSCPUContext
*ctx
= task
->tc_UnionETask
.tc_ETask
->et_RegFrame
;
112 RESTOREREGS(ctx
, regs
);
113 *pd
->errnoPtr
= ctx
->errno_backup
;
117 if (task
->tc_Flags
& TF_EXCEPT
)
119 /* Disable interrupts, otherwise we may lose saved context */
120 SysBase
->IDNestCnt
= 0;
122 /* Manipulate the current cpu context so Exec_Exception gets
123 excecuted after we leave the kernel resp. the signal handler. */
124 PC(regs
) = (IPTR
)cpu_Exception
;
128 * Adjust user mode interrupts state.
129 * Brackets MUST present, these are complex macros.
131 if (SysBase
->IDNestCnt
< 0)