2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
6 #define __KERNEL_NOLIBBASE__
8 #include <aros/types/timespec_s.h>
9 #include <exec/lists.h>
10 #include <exec/tasks.h>
11 #include <exec/execbase.h>
12 #include <hardware/intbits.h>
13 #include <proto/exec.h>
14 #include <proto/kernel.h>
18 #include "kernel_base.h"
19 #include "kernel_intern.h"
20 #include "kernel_debug.h"
21 #include "kernel_globals.h"
22 #include "kernel_scheduler.h"
23 #include "kernel_intr.h"
26 #include "apic_ia32.h"
28 #define AROS_NO_ATOMIC_OPERATIONS
29 #include <exec_platform.h>
32 * NB - Enabling DSCHED() with safedebug enabled CAN cause
47 void cpu_Dispatch(struct ExceptionContext
*regs
)
50 struct ExceptionContext
*ctx
;
51 #if defined(__AROSEXEC_SMP__) || (DEBUG > 0)
52 apicid_t cpunum
= KrnGetCPUNumber();
56 bug("[Kernel:%03u] cpu_Dispatch()\n", cpunum
);
60 * Is the list of ready tasks empty? Well, increment the idle switch count and halt CPU.
62 while (!(task
= core_Dispatch()))
64 /* Sleep until we receive an interupt....*/
66 bug("[Kernel:%03u] cpu_Dispatch: Nothing to do .. sleeping...\n", cpunum
);
69 __asm__
__volatile__("sti; hlt; cli");
71 if (SysBase
->SysFlags
& SFF_SoftInt
)
72 core_Cause(INTB_SOFTINT
, 1l << INTB_SOFTINT
);
76 bug("[Kernel:%03u] cpu_Dispatch: Task to Run @ 0x%p\n", cpunum
, task
);
79 /* Get task's context */
80 ctx
= task
->tc_UnionETask
.tc_ETask
->et_RegFrame
;
83 * Restore the fpu, mmx, xmm state
84 * TODO: Change to the lazy saving of the XMM state!!!!
86 if (ctx
->Flags
& ECF_FPX
)
87 asm volatile("fxrstor (%0)"::"r"(ctx
->FXData
));
89 #if defined(__AROSEXEC_SMP__)
90 IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuNumber
= cpunum
;
93 /* TODO: Handle exception
94 if (task->tc_Flags & TF_EXCEPT)
97 /* Store the launch time */
98 IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_private1
= RDTSC();
101 bug("[Kernel:%03u] cpu_Dispatch: Leaving...\n", cpunum
);
104 * Leave interrupt and jump to the new task.
105 * We will restore CPU state right from this buffer,
106 * so no need to copy anything.
108 core_LeaveInterrupt(ctx
);
111 void cpu_Switch(struct ExceptionContext
*regs
)
114 struct ExceptionContext
*ctx
;
116 struct timespec timeSpec
;
117 apicid_t cpunum
= KrnGetCPUNumber();
118 struct APICData
*apicData
;
119 apicData
= KernelBase
->kb_PlatformData
->kb_APIC
;
121 DSCHED(bug("[Kernel:%03u] cpu_Switch()\n", cpunum
);)
123 task
= GET_THIS_TASK
;
129 ctx
= task
->tc_UnionETask
.tc_ETask
->et_RegFrame
;
132 * Copy current task's context into the ETask structure. Note that context on stack
133 * misses SSE data pointer.
135 CopyMemQuick(regs
, ctx
, sizeof(struct ExceptionContext
) - sizeof(struct FPXContext
*));
138 * Copy the fpu, mmx, xmm state
139 * TODO: Change to the lazy saving of the XMM state!!!!
141 asm volatile("fxsave (%0)"::"r"(ctx
->FXData
));
143 /* We have the complete data now */
144 ctx
->Flags
= ECF_SEGMENTS
| ECF_FPX
;
146 /* Set task's tc_SPReg */
147 task
->tc_SPReg
= (APTR
)regs
->rsp
;
149 if (apicData
&& apicData
->cores
[cpunum
].cpu_TimerFreq
&& timeCur
)
152 if (timeCur < IntETask(task->tc_UnionETask.tc_ETask)->iet_private1)
153 timeCur = IntETask(task->tc_UnionETask.tc_ETask)->iet_private1 - timeCur;
155 timeCur = IntETask(task->tc_UnionETask.tc_ETask)->iet_private1 + apicData->cores[cpunum].cpu_TimerFreq - timeCur;
157 timeCur
-= IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_private1
;
159 /* Increase CPU Usage cycles */
160 IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_private2
+= timeCur
;
162 // Convert TSC cycles into nanoseconds
163 timeCur
= (timeCur
* 1000000000) / apicData
->cores
[cpunum
].cpu_TSCFreq
;
165 /* Update the task's CPU time */
166 timeSpec
.tv_sec
= timeCur
/ 1000000000;
167 timeSpec
.tv_nsec
= timeCur
% 1000000000;
169 IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuTime
.tv_nsec
+= timeSpec
.tv_nsec
;
170 IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuTime
.tv_sec
+= timeSpec
.tv_sec
;
171 while(IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuTime
.tv_nsec
>= 1000000000)
173 IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuTime
.tv_nsec
-= 1000000000;
174 IntETask(task
->tc_UnionETask
.tc_ETask
)->iet_CpuTime
.tv_sec
++;