2 Copyright © 2017, The AROS Development Team. All rights reserved.
6 #include <aros/config.h>
9 #include <aros/debug.h>
11 #include <proto/exec.h>
13 #include <exec/memory.h>
14 #include <exec/tasks.h>
15 #include <exec/interrupts.h>
16 #include <exec/rawfmt.h>
18 #define __AROS_KERNEL__
20 #include "exec_intern.h"
22 extern void IdleTask(struct ExecBase
*);
23 extern AROS_INTP(Exec_X86ShutdownHandler
);
24 extern AROS_INTP(Exec_X86WarmResetHandler
);
25 extern AROS_INTP(Exec_X86ColdResetHandler
);
28 #define EXCX_REGA regs->rax
29 #define EXCX_REGB regs->rbx
30 #define EXCX_REGC regs->rcx
32 #define EXCX_REGA regs->eax
33 #define EXCX_REGB regs->ebx
34 #define EXCX_REGC regs->ecx
39 #if defined(__AROSEXEC_SMP__)
40 struct Hook Exec_TaskSpinLockFailHook
;
41 struct Hook Exec_TaskSpinLockForbidHook
;
42 struct Hook Exec_TaskSpinLockDisableHook
;
44 AROS_UFH3(void, Exec_TaskSpinLockFailFunc
,
45 AROS_UFHA(struct Hook
*, h
, A0
),
46 AROS_UFHA(spinlock_t
*, spinLock
, A1
),
47 AROS_UFHA(void *, unused
, A2
))
51 struct Task
*spinTask
= GET_THIS_TASK
;
52 struct IntETask
*thisET
;
54 DSPIN(bug("[Exec:X86] %s()\n", __func__
));
57 thisET
= GetIntETask(spinTask
);
60 DSPIN(bug("[Exec:X86] %s: Setting task @ 0x%p to spinning...\n", __func__
, spinTask
));
62 /* tell the scheduler that the task is waiting on a spinlock */
63 spinTask
->tc_State
= TS_SPIN
;
65 thisET
->iet_SpinLock
= spinLock
;
69 DSPIN(bug("[Exec:X86] %s: Forcing Reschedule...\n", __func__
));
71 /* schedule us away for now .. */
77 AROS_UFH3(void, Exec_TaskSpinLockForbidFunc
,
78 AROS_UFHA(struct Hook
*, h
, A0
),
79 AROS_UFHA(spinlock_t
*, spinLock
, A1
),
80 AROS_UFHA(void *, unused
, A2
))
85 struct Task
*spinTask
= GET_THIS_TASK
;
86 bug("[Exec:X86] %s(0x%p)\n", __func__
, spinTask
);
91 DSPIN(bug("[Exec:X86] %s: done\n", __func__
));
96 AROS_UFH3(void, Exec_TaskSpinLockDisableFunc
,
97 AROS_UFHA(struct Hook
*, h
, A0
),
98 AROS_UFHA(spinlock_t
*, spinLock
, A1
),
99 AROS_UFHA(void *, unused
, A2
))
104 struct Task
*spinTask
= GET_THIS_TASK
;
105 bug("[Exec:X86] %s(0x%p)\n", __func__
, spinTask
);
110 DSPIN(bug("[Exec:X86] %s: done\n", __func__
));
115 void Exec_TaskSpinUnlock(spinlock_t
*spinLock
)
118 struct Task
*spinTask
, *nxtTask
;
119 struct IntETask
*thisET
;
121 DSPIN(bug("\n[Exec:X86] %s(0x%p)\n", __func__
, spinLock
));
124 EXEC_SPINLOCK_LOCK(&PrivExecBase(SysBase
)->TaskSpinningLock
, NULL
, SPINLOCK_MODE_WRITE
);
125 ForeachNodeSafe(&PrivExecBase(SysBase
)->TaskSpinning
, spinTask
, nxtTask
)
127 thisET
= GetIntETask(spinTask
);
128 if ((thisET
) && (thisET
->iet_SpinLock
== spinLock
))
130 EXEC_SPINLOCK_LOCK(&PrivExecBase(SysBase
)->TaskReadySpinLock
, NULL
, SPINLOCK_MODE_WRITE
);
132 Remove(&spinTask
->tc_Node
);
133 Enqueue(&SysBase
->TaskReady
, &spinTask
->tc_Node
);
134 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase
)->TaskReadySpinLock
);
138 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase
)->TaskSpinningLock
);
141 DSPIN(bug("[Exec:X86] %s: done\n\n", __func__
));
144 void X86_HandleSpinLock(struct ExceptionContext
*regs
)
146 struct ExecSpinSCData
*spinData
= (struct ExecSpinSCData
*)EXCX_REGB
;
148 DSPIN(bug("[Exec:X86] %s(0x%p, 0x%p, %08x)\n", __func__
, spinData
->lock_ptr
, spinData
->lock_failhook
, spinData
->lock_mode
));
150 EXEC_SPINLOCK_LOCK(spinData
->lock_ptr
, spinData
->lock_failhook
, spinData
->lock_mode
);
152 if (spinData
->lock_obtainhook
)
154 DSPIN(bug("[Exec:X86] %s: calling lock-obtained hook @ 0x%p ...\n", __func__
, spinData
->lock_obtainhook
);)
155 CALLHOOKPKT(spinData
->lock_obtainhook
, (APTR
)spinData
->lock_ptr
, 0);
158 EXCX_REGA
= (IPTR
)spinData
->lock_ptr
;
160 DSPIN(bug("[Exec:X86] %s: done\n", __func__
));
165 struct syscallx86_Handler x86_SCSpinLockHandler
=
168 .ln_Name
= (APTR
)SC_X86CPUSPINLOCK
170 (APTR
)X86_HandleSpinLock
173 spinlock_t
*ExecSpinLockCall(spinlock_t
*spinLock
, struct Hook
*hookObtained
, struct Hook
*hookFailed
, ULONG spinMode
)
175 struct ExecSpinSCData __spinData
=
182 spinlock_t
*__retval
;
183 DSPIN(bug("\n[Exec:X86] %s: attempting to lock 0x%p\n", __func__
, spinLock
));
184 __retval
= krnSysCallSpinLock(&__spinData
);
185 DSPIN(bug("[Exec:X86] %s: returning 0x%p\n\n", __func__
, __retval
));
190 #if defined(EXEC_REMTASK_NEEDSSWITCH)
191 void X86_HandleSwitch(struct ExceptionContext
*regs
)
193 D(bug("[Exec:X86] %s()\n", __func__
));
200 struct syscallx86_Handler x86_SCSwitchHandler
=
203 .ln_Name
= (APTR
)SC_X86SWITCH
205 (APTR
)X86_HandleSwitch
208 void X86_SetTaskState(struct Task
*changeTask
, ULONG newState
, BOOL dolock
)
210 #if defined(__AROSEXEC_SMP__)
211 spinlock_t
*task_listlock
= NULL
;
213 struct List
*task_list
= NULL
;
214 D(bug("[Exec:X86] %s(0x%p,%08x)\n", __func__
, changeTask
, newState
));
216 changeTask
->tc_State
= newState
;
221 #if defined(__AROSEXEC_SMP__)
222 task_listlock
= &PrivExecBase(SysBase
)->TaskRunningSpinLock
;
223 task_list
= &PrivExecBase(SysBase
)->TaskRunning
;
227 #if defined(__AROSEXEC_SMP__)
228 task_listlock
= &PrivExecBase(SysBase
)->TaskReadySpinLock
;
230 task_list
= &SysBase
->TaskReady
;
233 #if defined(__AROSEXEC_SMP__)
234 task_listlock
= &PrivExecBase(SysBase
)->TaskWaitSpinLock
;
236 task_list
= &SysBase
->TaskWait
;
238 #if defined(__AROSEXEC_SMP__)
240 task_listlock
= &PrivExecBase(SysBase
)->TaskSpinningLock
;
241 task_list
= &PrivExecBase(SysBase
)->TaskSpinning
;
249 #if defined(__AROSEXEC_SMP__)
250 if (dolock
&& task_listlock
) EXEC_SPINLOCK_LOCK(task_listlock
, NULL
, SPINLOCK_MODE_WRITE
);
252 Enqueue(task_list
, &changeTask
->tc_Node
);
253 #if defined(__AROSEXEC_SMP__)
254 if (dolock
&& task_listlock
) EXEC_SPINLOCK_UNLOCK(task_listlock
);
259 /* change a specified task's state */
260 void X86_HandleReschedTask(struct ExceptionContext
*regs
)
262 struct Task
*reschTask
= (struct Task
*)EXCX_REGB
;
263 ULONG reschState
= (ULONG
)EXCX_REGC
;
264 #if defined(__AROSEXEC_SMP__)
265 spinlock_t
*task_listlock
= NULL
;
268 D(bug("[Exec:X86] %s(0x%p,%08x)\n", __func__
, reschTask
, reschState
));
270 /* Move to the ready list... */
271 #if defined(__AROSEXEC_SMP__)
272 switch (reschTask
->tc_State
)
275 task_listlock
= &PrivExecBase(SysBase
)->TaskRunningSpinLock
;
278 task_listlock
= &PrivExecBase(SysBase
)->TaskReadySpinLock
;
281 task_listlock
= &PrivExecBase(SysBase
)->TaskWaitSpinLock
;
284 task_listlock
= &PrivExecBase(SysBase
)->TaskSpinningLock
;
290 EXEC_SPINLOCK_LOCK(task_listlock
, NULL
, SPINLOCK_MODE_WRITE
);
292 if ((reschTask
->tc_State
!= TS_INVALID
) && (reschTask
->tc_State
!= TS_TOMBSTONED
))
294 if ((reschTask
->tc_State
!= TS_INVALID
) && (reschTask
->tc_State
!= TS_RUN
))
296 Remove(&reschTask
->tc_Node
);
297 #if defined(__AROSEXEC_SMP__)
303 struct Task
*spinTask
, *tmpTask
;
304 struct IntETask
*reschTaskIntET
, *spinTaskIntET
;
306 reschState
= TS_READY
;
308 reschTaskIntET
= GetIntETask(reschTask
);
310 EXEC_SPINLOCK_LOCK(&PrivExecBase(SysBase
)->TaskSpinningLock
, NULL
, SPINLOCK_MODE_WRITE
);
311 ForeachNodeSafe(&PrivExecBase(SysBase
)->TaskSpinning
, spinTask
, tmpTask
)
313 spinTaskIntET
= GetIntETask(spinTask
);
314 if ((spinTaskIntET
) && (spinTaskIntET
->iet_SpinLock
== reschTaskIntET
->iet_SpinLock
))
316 bug("[Exec:X86] %s: enabling spinning task @ 0x%p\n", __func__
, spinTask
);
317 spinTaskIntET
->iet_SpinLock
=NULL
;
318 X86_SetTaskState(spinTask
, TS_READY
, TRUE
);
321 EXEC_SPINLOCK_UNLOCK(&PrivExecBase(SysBase
)->TaskSpinningLock
);
327 X86_SetTaskState(reschTask
, reschState
, (BOOL
)(reschTask
->tc_State
!= reschState
));
328 #if defined(__AROSEXEC_SMP__)
331 reschTask
->tc_State
= TS_TOMBSTONED
;
336 EXEC_SPINLOCK_UNLOCK(task_listlock
);
342 struct syscallx86_Handler x86_SCReschedTaskHandler
=
345 .ln_Name
= (APTR
)SC_X86RESCHEDTASK
347 (APTR
)X86_HandleReschedTask
351 struct Task
*Exec_X86CreateIdleTask(APTR sysBase
)
353 struct ExecBase
*SysBase
= (struct ExecBase
*)sysBase
;
354 struct Task
*CPUIdleTask
;
356 #if defined(__AROSEXEC_SMP__)
357 struct KernelBase
*KernelBase
= __kernelBase
;
358 int cpuNo
= KrnGetCPUNumber();
366 cpuMask
= KrnAllocCPUMask();
368 if ((ml
= AllocMem(sizeof(struct MemList
), MEMF_PUBLIC
|MEMF_CLEAR
)) == NULL
)
370 bug("[Exec:X86.%03u] FATAL : Failed to allocate memory for idle task name info", cpuNo
);
374 ml
->ml_NumEntries
= 1;
376 ml
->ml_ME
[0].me_Length
= 15;
377 if ((ml
->ml_ME
[0].me_Addr
= AllocMem(15, MEMF_PUBLIC
|MEMF_CLEAR
)) == NULL
)
379 bug("[Exec:X86.%03u] FATAL : Failed to allocate memory for task idle name", cpuNo
);
380 FreeMem(ml
, sizeof(struct MemList
));
383 taskName
= ml
->ml_ME
[0].me_Addr
;
384 RawDoFmt("CPU #%03u Idle", (RAWARG
)idleNameArg
, RAWFMTFUNC_STRING
, taskName
);
386 KrnGetCPUMask(cpuNo
, cpuMask
);
389 taskName
= "CPU Idle";
391 CPUIdleTask
= NewCreateTask(TASKTAG_NAME
, taskName
,
392 #if defined(__AROSEXEC_SMP__)
393 TASKTAG_AFFINITY
, cpuMask
,
396 TASKTAG_PC
, IdleTask
,
397 TASKTAG_ARG1
, SysBase
,
403 bug("[Exec:X86] %s: '%s' Task created @ 0x%p\n", __func__
, CPUIdleTask
->tc_Node
.ln_Name
, CPUIdleTask
);
404 #if defined(__AROSEXEC_SMP__)
405 bug("[Exec:X86] %s: CPU Affinity : %08x\n", __func__
, IntETask(CPUIdleTask
->tc_UnionETask
.tc_ETask
)->iet_CpuAffinity
);
408 #if defined(__AROSEXEC_SMP__)
409 AddTail(&CPUIdleTask
->tc_MemEntry
, &ml
->ml_Node
);
412 #if defined(__AROSEXEC_SMP__)
415 FreeMem(ml
->ml_ME
[0].me_Addr
, 15);
416 FreeMem(ml
, sizeof(struct MemList
));
422 int Exec_X86Init(struct ExecBase
*SysBase
)
424 struct IntExecBase
*sysBase
= (struct IntExecBase
*)SysBase
;
425 #if defined(__AROSEXEC_SMP__) || defined(EXEC_REMTASK_NEEDSSWITCH)
426 struct KernelBase
*KernelBase
= __kernelBase
;
429 D(bug("[Exec:X86] %s()\n", __func__
));
430 D(bug("[Exec:X86] %s: KernelBase @ 0x%p\n", __func__
, __kernelBase
));
431 D(bug("[Exec:X86] %s: PlatformData @ 0x%p\n", __func__
, &sysBase
->PlatformData
));
433 /* Install The default Power Management handlers */
434 sysBase
->ColdResetHandler
.is_Node
.ln_Pri
= -64;
435 sysBase
->ColdResetHandler
.is_Node
.ln_Name
= "Keyboard Controller Reset";
436 sysBase
->ColdResetHandler
.is_Code
= (VOID_FUNC
)Exec_X86ColdResetHandler
;
437 sysBase
->ColdResetHandler
.is_Data
= &sysBase
->ColdResetHandler
;
438 AddResetCallback(&sysBase
->ColdResetHandler
);
440 sysBase
->WarmResetHandler
.is_Node
.ln_Pri
= -64;
441 sysBase
->WarmResetHandler
.is_Node
.ln_Name
= "System Reset";
442 sysBase
->WarmResetHandler
.is_Code
= (VOID_FUNC
)Exec_X86WarmResetHandler
;
443 sysBase
->WarmResetHandler
.is_Data
= &sysBase
->WarmResetHandler
;
444 AddResetCallback(&sysBase
->WarmResetHandler
);
446 sysBase
->ShutdownHandler
.is_Node
.ln_Pri
= -128;
447 sysBase
->ShutdownHandler
.is_Node
.ln_Name
= "System Shutdown";
448 sysBase
->ShutdownHandler
.is_Code
= (VOID_FUNC
)Exec_X86ShutdownHandler
;
449 sysBase
->ShutdownHandler
.is_Data
= &sysBase
->ShutdownHandler
;
450 AddResetCallback(&sysBase
->ShutdownHandler
);
452 D(bug("[Exec:X86] %s: Default Handlers Registered\n", __func__
));
454 #if defined(EXEC_REMTASK_NEEDSSWITCH)
455 krnAddSysCallHandler(KernelBase
->kb_PlatformData
, &x86_SCSwitchHandler
, TRUE
, TRUE
);
456 krnAddSysCallHandler(KernelBase
->kb_PlatformData
, &x86_SCReschedTaskHandler
, TRUE
, TRUE
);
458 #if defined(__AROSEXEC_SMP__)
459 /* register the task spinlock syscall */
460 krnAddSysCallHandler(KernelBase
->kb_PlatformData
, &x86_SCSpinLockHandler
, TRUE
, TRUE
);
461 sysBase
->PlatformData
.SpinLockCall
= ExecSpinLockCall
;
463 /* set up the task spinning hooks */
464 Exec_TaskSpinLockForbidHook
.h_Entry
= (HOOKFUNC
)Exec_TaskSpinLockForbidFunc
;
465 Exec_TaskSpinLockDisableHook
.h_Entry
= (HOOKFUNC
)Exec_TaskSpinLockDisableFunc
;
466 Exec_TaskSpinLockFailHook
.h_Entry
= (HOOKFUNC
)Exec_TaskSpinLockFailFunc
;
467 D(bug("[Exec:X86] %s: SpinLock Fail Hook @ 0x%p, Handler @ 0x%p\n", __func__
, &Exec_TaskSpinLockFailHook
, Exec_TaskSpinLockFailFunc
));
468 D(bug("[Exec:X86] %s: SpinLock Forbid Hook @ 0x%p, Handler @ 0x%p\n", __func__
, &Exec_TaskSpinLockForbidHook
, Exec_TaskSpinLockForbidFunc
));
471 Exec_X86CreateIdleTask(SysBase
);
476 ADD2INITLIB(Exec_X86Init
, -127)