revert between 56095 -> 55830 in arch
[AROS.git] / arch / x86_64-pc / kernel / kernel_cpu.c
blobf60facf5313dca95b7215f383a30e64a097fd0ad
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
4 */
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>
16 #include "etask.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"
25 #include "apic.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
33 * lockups!
35 #ifdef DEBUG
36 #undef DEBUG
37 #endif
39 #define DEBUG 0
41 #if (DEBUG > 0)
42 #define DSCHED(x) x
43 #else
44 #define DSCHED(x)
45 #endif
47 void cpu_Dispatch(struct ExceptionContext *regs)
49 struct Task *task;
50 struct ExceptionContext *ctx;
51 #if defined(__AROSEXEC_SMP__) || (DEBUG > 0)
52 apicid_t cpunum = KrnGetCPUNumber();
53 #endif
55 DSCHED(
56 bug("[Kernel:%03u] cpu_Dispatch()\n", cpunum);
59 /*
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....*/
65 DSCHED(
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);
75 DSCHED(
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;
82 /*
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;
91 #endif
93 /* TODO: Handle exception
94 if (task->tc_Flags & TF_EXCEPT)
95 Exception(); */
97 /* Store the launch time */
98 IntETask(task->tc_UnionETask.tc_ETask)->iet_private1 = RDTSC();
100 DSCHED(
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)
113 struct Task *task;
114 struct ExceptionContext *ctx;
115 UQUAD timeCur = 0;
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;
125 if (task)
127 timeCur = RDTSC();
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;
154 else
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++;
178 core_Switch();