nouveau.hidd: disable warnings about not initialized variables
[AROS.git] / arch / all-mingw32 / kernel / kernel_cpu.c
blob74e539e965fe2fe70bfada925b45aa5e6cc6eb34
1 /*
2 Copyright © 2008-2012, 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];
50 struct ExceptionContext *csPtr = (struct ExceptionContext *)ContextSave;
52 DEXCEPT(bug("[KRN] Entered exception, task 0x%p, IDNestCnt %d\n", task, SysBase->IDNestCnt));
53 /* Save original context */
54 CopyMem(ctx, ContextSave, sizeof(struct AROSCPUContext));
55 COPY_FPU(ctx, csPtr);
57 /* Call exec exception processing */
58 Exception();
60 /* Restore saved task state and resume it. Note that interrupts are
61 disabled again here */
62 task->tc_IDNestCnt = nestCnt;
63 SysBase->IDNestCnt = nestCnt;
65 D(bug("[KRN] Leaving exception, IDNestCnt %d\n", SysBase->IDNestCnt));
66 KernelIFace.core_raise(AROS_EXCEPTION_RESUME, (IPTR)ContextSave);
69 /* CPU-specific Switch() bits. Actually just context save. */
70 void cpu_Switch(CONTEXT *regs)
72 struct Task *t = SysBase->ThisTask;
73 struct AROSCPUContext *ctx = t->tc_UnionETask.tc_ETask->et_RegFrame;
75 /* Actually save the context */
76 SAVEREGS(regs, ctx);
77 ctx->LastError = **KernelIFace.LastError;
79 /* Update tc_SPReg */
80 t->tc_SPReg = GET_SP(ctx);
82 core_Switch();
86 * CPU-dependent wrapper around core_Dispatch(). Implements
87 * context restore, CPU idle loop, and task exceptions.
89 void cpu_Dispatch(CONTEXT *regs)
91 struct Task *task = core_Dispatch();
92 struct AROSCPUContext *ctx;
94 if (!task)
97 * There are no ready tasks and we need to go idle.
98 * Because of the way how our emulation works, we do not
99 * have a real loop here, unlike most ports. Instead we
100 * signal idle state and exit. Then there can be two possibilities:
101 * a) we are called by our virtual machine's supervisor thread.
102 * In this case it will just not resume usermode thread, and
103 * will go on with interrupts processing.
104 * b) we are called by usermode thread using core_Rise(). In this
105 * case we will continue execution of the code and hit while(Sleep_Mode);
106 * spinlock in core_Rise(). We will spin until supervisor thread interrupts
107 * us and actually puts asleep.
108 * We can't implement idle loop similar to other ports here because of (b)
109 * case. We would just deadlock then since interrupt processing is actually
110 * disabled during Windows exception processing (which is also an interrupt
111 * for us).
113 DSLEEP(if (!Get_Sleep_Mode()) bug("[KRN] TaskReady list empty. Sleeping for a while...\n"));
115 /* This will enable interrupts in core_LeaveInterrupt() */
116 SysBase->IDNestCnt = -1;
118 /* We are entering sleep mode */
119 *KernelIFace.SleepState = SLEEP_MODE_PENDING;
121 return;
124 *KernelIFace.SleepState = 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 **KernelIFace.LastError = 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;