2 Copyright © 2008-2011, The AROS Development Team. All rights reserved.
5 Desc: CPU-specific add-ons for Windows-hosted scheduler.
6 Context save, restore, and task exception handling.
10 #include <exec/execbase.h>
11 #include <proto/exec.h>
13 #include "kernel_base.h"
14 #include "kernel_debug.h"
15 #include "kernel_mingw32.h"
16 #include "kernel_scheduler.h"
23 * User-mode part of exception handling. Save context, call
24 * exec handler, then resume task.
25 * Note that interrupts are disabled and SysBase->IDNestCnt contains 0
26 * upon entry. Real IDNestCnt count for the task is stored in its tc_IDNestCnt.
28 * We have to do this complex trick with disabling interrupts because
29 * in Windows exception handler operates on thread's stack, this means
30 * we can't modify the stack inside exception handler, i.e. we can't save
31 * the context on task's stack.
33 * In order to overcome this we forcibly disable interrupts in core_Dispatch()
34 * and make the task to jump here. After this et_RegFrame still contains
35 * unmodified saved task context. Since we're running normally on our stack,
36 * we can save the context on the stack here.
37 * Inside Exception() interrupts and task switching will be enabled, so original
38 * IDNestCnt will be lost. In order to prevent it we save it on the stack too.
40 * When we're done we pick up saved IDNestCnt from stack and raise
41 * AROS_EXCEPTION_RESUME in order to jump back to the saved context.
43 static void cpu_Exception()
45 /* Save return context and IDNestCnt on stack */
46 struct Task
*task
= SysBase
->ThisTask
;
47 struct ExceptionContext
*ctx
= task
->tc_UnionETask
.tc_ETask
->et_RegFrame
;
48 char nestCnt
= task
->tc_IDNestCnt
;
49 char ContextSave
[KernelBase
->kb_ContextSize
];
51 DEXCEPT(bug("[KRN] Entered exception, task 0x%p, IDNestCnt %d\n", task
, SysBase
->IDNestCnt
));
52 /* Save original context */
53 CopyMem(ctx
, ContextSave
, sizeof(struct AROSCPUContext
));
54 COPY_FPU(ctx
, (struct ExceptionContext
*)ContextSave
);
56 /* Call exec exception processing */
59 /* Restore saved task state and resume it. Note that interrupts are
60 disabled again here */
61 task
->tc_IDNestCnt
= nestCnt
;
62 SysBase
->IDNestCnt
= nestCnt
;
64 D(bug("[KRN] Leaving exception, IDNestCnt %d\n", SysBase
->IDNestCnt
));
65 KernelIFace
.core_raise(AROS_EXCEPTION_RESUME
, (IPTR
)ContextSave
);
68 /* CPU-specific Switch() bits. Actually just context save. */
69 void cpu_Switch(CONTEXT
*regs
)
71 struct Task
*t
= SysBase
->ThisTask
;
72 struct AROSCPUContext
*ctx
= t
->tc_UnionETask
.tc_ETask
->et_RegFrame
;
74 /* Actually save the context */
76 ctx
->LastError
= *LastErrorPtr
;
79 t
->tc_SPReg
= GET_SP(ctx
);
85 * CPU-dependent wrapper around core_Dispatch(). Implements
86 * context restore, CPU idle loop, and task exceptions.
88 void cpu_Dispatch(CONTEXT
*regs
)
90 struct Task
*task
= core_Dispatch();
91 struct AROSCPUContext
*ctx
;
96 * There are no ready tasks and we need to go idle.
97 * Because of the way how our emulation works, we do not
98 * have a real loop here, unlike most ports. Instead we
99 * signal idle state and exit. Then there can be two possibilities:
100 * a) we are called by our virtual machine's supervisor thread.
101 * In this case it will just not resume usermode thread, and
102 * will go on with interrupts processing.
103 * b) we are called by usermode thread using core_Rise(). In this
104 * case we will continue execution of the code and hit while(Sleep_Mode);
105 * spinlock in core_Rise(). We will spin until supervisor thread interrupts
106 * us and actually puts asleep.
107 * We can't implement idle loop similar to other ports here because of (b)
108 * case. We would just deadlock then since interrupt processing is actually
109 * disabled during Windows exception processing (which is also an interrupt
112 DSLEEP(if (!Sleep_Mode
) bug("[KRN] TaskReady list empty. Sleeping for a while...\n"));
114 /* This will enable interrupts in core_LeaveInterrupt() */
115 SysBase
->IDNestCnt
= -1;
117 /* We are entering sleep mode */
118 Sleep_Mode
= SLEEP_MODE_PENDING
;
123 DSLEEP(if (Sleep_Mode
) bug("[KRN] Exiting idle state\n");)
124 Sleep_Mode
= SLEEP_MODE_OFF
;
126 D(bug("[KRN] Dispatched task 0x%p (%s)\n", task
, task
->tc_Node
.ln_Name
));
127 /* Restore the task's context */
128 ctx
= task
->tc_UnionETask
.tc_ETask
->et_RegFrame
;
129 RESTOREREGS(regs
, ctx
);
130 *LastErrorPtr
= ctx
->LastError
;
132 /* Handle exception if requested */
133 if (task
->tc_Flags
& TF_EXCEPT
)
135 DEXCEPT(bug("[KRN] Exception requested for task 0x%p, return PC = 0x%p\n", task
, PC(regs
)));
137 /* Disable interrupts, otherwise we may lose saved context */
138 SysBase
->IDNestCnt
= 0;
140 /* Make the task to jump to exception handler */
141 PC(regs
) = (IPTR
)cpu_Exception
;