Added support for compiling C++ files. It isn't included for all
[AROS.git] / arch / all-mingw32 / kernel / kernel_cpu.c
blob9f7eeeef150dcb042ba3980106dbfcf6d18f886d
1 /*
2 Copyright © 2008-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: CPU-specific add-ons for Windows-hosted scheduler.
6 Context save, restore, and task exception handling.
7 Lang: english
8 */
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"
18 #define D(x)
19 #define DEXCEPT(x)
20 #define DSLEEP(x)
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 */
57 Exception();
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 */
75 SAVEREGS(regs, ctx);
76 ctx->LastError = *LastErrorPtr;
78 /* Update tc_SPReg */
79 t->tc_SPReg = GET_SP(ctx);
81 core_Switch();
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;
93 if (!task)
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
110 * for us).
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;
120 return;
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;