From 9761569e061b74b122184c1a1742e46f4188dfca Mon Sep 17 00:00:00 2001 From: Rafal Kupiec Date: Wed, 6 May 2026 22:25:39 +0200 Subject: [PATCH] Implement SwitchContext() and SwitchThreadStack() routines --- sdk/xtdk/i686/ketypes.h | 8 +- xtoskrnl/CMakeLists.txt | 1 + xtoskrnl/ke/amd64/dispatch.cc | 177 ++++++++++++++++++++++++++++++++++ xtoskrnl/ke/i686/dispatch.cc | 134 +++++++++++++++++++++++++ 4 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 xtoskrnl/ke/amd64/dispatch.cc create mode 100644 xtoskrnl/ke/i686/dispatch.cc diff --git a/sdk/xtdk/i686/ketypes.h b/sdk/xtdk/i686/ketypes.h index 2264fc7..6ffd11f 100644 --- a/sdk/xtdk/i686/ketypes.h +++ b/sdk/xtdk/i686/ketypes.h @@ -343,10 +343,14 @@ typedef struct _KTSS UCHAR IntDirectionMap[IOPM_DIRECTION_MAP_SIZE]; } KTSS, *PKTSS; -/* Exception frame definition (not available on ia32) */ +/* Exception frame definition (not available on i686) */ typedef struct _KEXCEPTION_FRAME { - ULONG PlaceHolder; + ULONG Ebp; + ULONG Ebx; + ULONG Edi; + ULONG Esi; + ULONG Return; } KEXCEPTION_FRAME, *PKEXCEPTION_FRAME; /* Thread start frame definition */ diff --git a/xtoskrnl/CMakeLists.txt b/xtoskrnl/CMakeLists.txt index e942e8d..472400b 100644 --- a/xtoskrnl/CMakeLists.txt +++ b/xtoskrnl/CMakeLists.txt @@ -34,6 +34,7 @@ list(APPEND XTOSKRNL_SOURCE ${XTOSKRNL_SOURCE_DIR}/kd/data.cc ${XTOSKRNL_SOURCE_DIR}/kd/dbgio.cc ${XTOSKRNL_SOURCE_DIR}/kd/exports.cc + ${XTOSKRNL_SOURCE_DIR}/ke/${ARCH}/dispatch.cc ${XTOSKRNL_SOURCE_DIR}/ke/${ARCH}/krnlinit.cc ${XTOSKRNL_SOURCE_DIR}/ke/${ARCH}/kthread.cc ${XTOSKRNL_SOURCE_DIR}/ke/${ARCH}/proc.cc diff --git a/xtoskrnl/ke/amd64/dispatch.cc b/xtoskrnl/ke/amd64/dispatch.cc new file mode 100644 index 0000000..d9168da --- /dev/null +++ b/xtoskrnl/ke/amd64/dispatch.cc @@ -0,0 +1,177 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ke/amd64/dispatch.cc + * DESCRIPTION: Kernel Thread Dispatcher + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/** + * Entry point for thread context switching. + * + * @param CurrentThread + * Pointer to the KTHREAD structure of the current thread being suspended. + * + * @param RunLevel + * Supplies the running level at which the wait was initiated. + * + * @return This routine returns TRUE if a kernel APC is pending and can be delivered, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +KE::Dispatcher::SwitchContext(IN PKTHREAD CurrentThread, + IN KRUNLEVEL RunLevel) +{ + BOOLEAN PendingApc; + + /* Save non-volatile and XMM registers to the exception frame, align the stack and invoke the switch routine */ + __asm__ volatile("subq %[ExFrameSize], %%rsp\n" + "movq %%rbp, %c[ExRbp](%%rsp)\n" + "movq %%rbx, %c[ExRbx](%%rsp)\n" + "movq %%rdi, %c[ExRdi](%%rsp)\n" + "movq %%rsi, %c[ExRsi](%%rsp)\n" + "movq %%r12, %c[ExR12](%%rsp)\n" + "movq %%r13, %c[ExR13](%%rsp)\n" + "movq %%r14, %c[ExR14](%%rsp)\n" + "movq %%r15, %c[ExR15](%%rsp)\n" + "movdqa %%xmm6, %c[ExXmm6](%%rsp)\n" + "movdqa %%xmm7, %c[ExXmm7](%%rsp)\n" + "movdqa %%xmm8, %c[ExXmm8](%%rsp)\n" + "movdqa %%xmm9, %c[ExXmm9](%%rsp)\n" + "movdqa %%xmm10, %c[ExXmm10](%%rsp)\n" + "movdqa %%xmm11, %c[ExXmm11](%%rsp)\n" + "movdqa %%xmm12, %c[ExXmm12](%%rsp)\n" + "movdqa %%xmm13, %c[ExXmm13](%%rsp)\n" + "movdqa %%xmm14, %c[ExXmm14](%%rsp)\n" + "movdqa %%xmm15, %c[ExXmm15](%%rsp)\n" + "callq %P[SwitchRoutine]\n" + "movq %c[ExRbp](%%rsp), %%rbp\n" + "movq %c[ExRbx](%%rsp), %%rbx\n" + "movq %c[ExRdi](%%rsp), %%rdi\n" + "movq %c[ExRsi](%%rsp), %%rsi\n" + "movq %c[ExR12](%%rsp), %%r12\n" + "movq %c[ExR13](%%rsp), %%r13\n" + "movq %c[ExR14](%%rsp), %%r14\n" + "movq %c[ExR15](%%rsp), %%r15\n" + "movdqa %c[ExXmm6](%%rsp), %%xmm6\n" + "movdqa %c[ExXmm7](%%rsp), %%xmm7\n" + "movdqa %c[ExXmm8](%%rsp), %%xmm8\n" + "movdqa %c[ExXmm9](%%rsp), %%xmm9\n" + "movdqa %c[ExXmm10](%%rsp), %%xmm10\n" + "movdqa %c[ExXmm11](%%rsp), %%xmm11\n" + "movdqa %c[ExXmm12](%%rsp), %%xmm12\n" + "movdqa %c[ExXmm13](%%rsp), %%xmm13\n" + "movdqa %c[ExXmm14](%%rsp), %%xmm14\n" + "movdqa %c[ExXmm15](%%rsp), %%xmm15\n" + "addq %[ExFrameSize], %%rsp\n" + : "=a" (PendingApc) + : "c" (CurrentThread), + "d" (RunLevel), + [ExFrameSize] "i" (sizeof(KEXCEPTION_FRAME) - 8), + [ExR12] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, R12)), + [ExR13] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, R13)), + [ExR14] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, R14)), + [ExR15] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, R15)), + [ExRbp] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Rbp)), + [ExRbx] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Rbx)), + [ExRdi] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Rdi)), + [ExRsi] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Rsi)), + [ExXmm6] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm6)), + [ExXmm7] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm7)), + [ExXmm8] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm8)), + [ExXmm9] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm9)), + [ExXmm10] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm10)), + [ExXmm11] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm11)), + [ExXmm12] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm12)), + [ExXmm13] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm13)), + [ExXmm14] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm14)), + [ExXmm15] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Xmm15)), + [SwitchRoutine] "i" (SwitchThreadStack) + : "cc", "memory", "r8", "r9", "r10", "r11"); + + /* Return the APC status */ + return PendingApc; +} + +/** + * Switches context from current thread to the new thread. + * + * @param CurrentThread + * Pointer to the KTHREAD structure of the current thread being suspended. + * + * @param ApcBypass + * Indicates whether the APC delivery should be bypassed. + * + * @return This routine returns TRUE if a kernel APC is pending and can be delivered, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +KE::Dispatcher::SwitchThreadContext(IN PKTHREAD CurrentThread, + IN BOOLEAN ApcBypass) +{ + UNIMPLEMENTED; + + return FALSE; +} + +/** + * Switches the thread stack and performs necessary operations to prepare for context switching. + * + * @param CurrentThread + * Pointer to the KTHREAD structure of the current thread being suspended. + * + * @param RunLevel + * Supplies the running level at which the wait was initiated. + * + * @return This routine returns TRUE if a kernel APC is pending and can be delivered, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +KE::Dispatcher::SwitchThreadStack(IN PKTHREAD CurrentThread, + IN KRUNLEVEL RunLevel) +{ + BOOLEAN PendingApc; + + /* Preserve MXCSR, synchronize with CPUs, switch stack and call the switch routine */ + __asm__ volatile("pushq %%rbp\n" + "subq %[FrameSize], %%rsp\n" + "stmxcsr %c[SwMxCsr](%%rsp)\n" + "movq %%gs:%c[PrcbcCurrentThread], %%r8\n" + "BusyLoop:\n" + "cmpb $0, %c[ThrdSwapBusy](%%r8)\n" + "je ExitLoop\n" + "pause\n" + "jmp BusyLoop\n" + "ExitLoop:\n" + "movb %%dl, %c[SwApcBypass](%%rsp)\n" + "movq %%rsp, %c[ThrdStack](%%rcx)\n" + "movq %c[ThrdStack](%%r8), %%rsp\n" + "movzbl %c[SwApcBypass](%%rsp), %%edx\n" + "callq %P[SwitchRoutine]\n" + "ldmxcsr %c[SwMxCsr](%%rsp)\n" + "addq %[FrameSize], %%rsp\n" + "popq %%rbp\n" + : "=a" (PendingApc) + : "c" (CurrentThread), + "d" (RunLevel), + [FrameSize] "i" (FIELD_OFFSET(KSWITCH_FRAME, Rbp)), + [PrcbcCurrentThread] "i" (FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread)), + [SwApcBypass] "i" (FIELD_OFFSET(KSWITCH_FRAME, ApcBypass)), + [SwMxCsr] "i" (FIELD_OFFSET(KSWITCH_FRAME, MxCsr)), + [SwitchRoutine] "i" (SwitchThreadContext), + [ThrdStack] "i" (FIELD_OFFSET(KTHREAD, KernelStack)), + [ThrdSwapBusy] "i" (FIELD_OFFSET(KTHREAD, SwapBusy)) + : "cc", "memory", "r8", "r9", "r10", "r11"); + + /* Return the APC status */ + return PendingApc; +} diff --git a/xtoskrnl/ke/i686/dispatch.cc b/xtoskrnl/ke/i686/dispatch.cc new file mode 100644 index 0000000..b06e5cd --- /dev/null +++ b/xtoskrnl/ke/i686/dispatch.cc @@ -0,0 +1,134 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/ke/i686/dispatch.cc + * DESCRIPTION: Kernel Thread Dispatcher + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/** + * Entry point for thread context switching. + * + * @param CurrentThread + * Pointer to the KTHREAD structure of the current thread being suspended. + * + * @param RunLevel + * Supplies the running level at which the wait was initiated. + * + * @return This routine returns TRUE if a kernel APC is pending and can be delivered, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +KE::Dispatcher::SwitchContext(IN PKTHREAD CurrentThread, + IN KRUNLEVEL RunLevel) +{ + BOOLEAN PendingApc; + + /* Save registers to the exception frame and invoke the stack switch routine */ + __asm__ volatile("subl %[ExFrameSize], %%esp\n" + "movl %%esi, %c[ExEsi](%%esp)\n" + "movl %%edi, %c[ExEdi](%%esp)\n" + "movl %%ebx, %c[ExEbx](%%esp)\n" + "movl %%ebp, %c[ExEbp](%%esp)\n" + "call %P[SwitchRoutine]\n" + "movl %c[ExEbp](%%esp), %%ebp\n" + "movl %c[ExEbx](%%esp), %%ebx\n" + "movl %c[ExEdi](%%esp), %%edi\n" + "movl %c[ExEsi](%%esp), %%esi\n" + "addl %[ExFrameSize], %%esp\n" + : "=a" (PendingApc) + : "c" (CurrentThread), + "d" (RunLevel), + [ExFrameSize] "i" (sizeof(KEXCEPTION_FRAME) - 4), + [ExEbp] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Ebp)), + [ExEbx] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Ebx)), + [ExEdi] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Edi)), + [ExEsi] "i" (FIELD_OFFSET(KEXCEPTION_FRAME, Esi)), + [SwitchRoutine] "i" (SwitchThreadStack) + : "cc", "memory"); + + /* Return the APC status */ + return PendingApc; +} + +/** + * Switches context from current thread to the new thread. + * + * @param CurrentThread + * Pointer to the KTHREAD structure of the current thread being suspended. + * + * @param ApcBypass + * Indicates whether the APC delivery should be bypassed. + * + * @return This routine returns TRUE if a kernel APC is pending and can be delivered, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +KE::Dispatcher::SwitchThreadContext(IN PKTHREAD CurrentThread, + IN BOOLEAN ApcBypass) +{ + UNIMPLEMENTED; + + return FALSE; +} + +/** + * Switches the thread stack and performs necessary operations to prepare for context switching. + * + * @param CurrentThread + * Pointer to the KTHREAD structure of the current thread being suspended. + * + * @param RunLevel + * Supplies the running level at which the wait was initiated. + * + * @return This routine returns TRUE if a kernel APC is pending and can be delivered, or FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +KE::Dispatcher::SwitchThreadStack(IN PKTHREAD CurrentThread, + IN KRUNLEVEL RunLevel) +{ + BOOLEAN PendingApc; + + /* Save old state, synchronize with CPUs, switch stack and call the switch routine */ + __asm__ volatile("subl %[FrameSize], %%esp\n" + "movl %%fs:%c[PrcbcCurrentThread], %%ebx\n" + "BusyLoop:\n" + "cmpb $0, %c[ThrdSwapBusy](%%ebx)\n" + "je ExitLoop\n" + "pause\n" + "jmp BusyLoop\n" + "ExitLoop:\n" + "movl %%fs:%c[ThrdInfoExceptions], %%eax\n" + "movl %%eax, %c[SwExceptionList](%%esp)\n" + "movb %%dl, %c[SwApcBypass](%%esp)\n" + "movl %%esp, %c[ThrdStack](%%ecx)\n" + "movl %c[ThrdStack](%%ebx), %%esp\n" + "movzbl %c[SwApcBypass](%%esp), %%edx\n" + "call %P[SwitchRoutine]\n" + "addl %[FrameSize], %%esp\n" + : "=a" (PendingApc) + : "c" (CurrentThread), + "d" (RunLevel), + [FrameSize] "i" (sizeof(KSWITCH_FRAME) - 4), + [PrcbcCurrentThread] "i" (FIELD_OFFSET(KPROCESSOR_BLOCK, Prcb.CurrentThread)), + [SwApcBypass] "i" (FIELD_OFFSET(KSWITCH_FRAME, ApcBypassDisabled)), + [SwExceptionList] "i" (FIELD_OFFSET(KSWITCH_FRAME, ExceptionList)), + [SwitchRoutine] "i" (SwitchThreadContext), + [ThrdInfoExceptions] "i" (FIELD_OFFSET(THREAD_INFORMATION_BLOCK, ExceptionList)), + [ThrdStack] "i" (FIELD_OFFSET(KTHREAD, KernelStack)), + [ThrdSwapBusy] "i" (FIELD_OFFSET(KTHREAD, SwapBusy)) + : "cc", "memory"); + + /* Return the APC status */ + return PendingApc; +}