Author: tkreuzer Date: Sat Feb 4 11:32:13 2012 New Revision: 55405
URL: http://svn.reactos.org/svn/reactos?rev=55405&view=rev Log: [NTOSKRNL/KE/AMD64] - Fix stack alignment in KiSwitchToBootStack - Handle ExceptionFrame == NULL in KeContextToTrapFrame and KeTrapFrameToContext - Implement KiSwapContextInternal - Fix KiSwapContext and KiThreadStartup - Implement dispatching of user mode exceptions including in-paging of module data used by the kernel-debugger - Implement KeInitializeInterrupt, KeConnectInterrupt, KeSynchronizeExecution - Don't zero more than the actual PCR size in KiInitializePcr - Add asm function KiInitializeSegments to initialize the segment selectors to proper values - Initialize system call entrypoints in KiInitializeCpu - Implement KiDpcInterruptHandler, KiIdleLoop, KiInitializeUserApc, KiSwapProcess, KiSystemCallHandler, KiInitializeContextThread, KiSwapContextResume - Implement asm functions KiRetireDpcList, KiInterruptDispatch, KiSystemCallEntry64, KiZwSystemService
Modified: trunk/reactos/ntoskrnl/ke/amd64/boot.S trunk/reactos/ntoskrnl/ke/amd64/context.c trunk/reactos/ntoskrnl/ke/amd64/ctxswitch.S trunk/reactos/ntoskrnl/ke/amd64/except.c trunk/reactos/ntoskrnl/ke/amd64/interrupt.c trunk/reactos/ntoskrnl/ke/amd64/kiinit.c trunk/reactos/ntoskrnl/ke/amd64/stubs.c trunk/reactos/ntoskrnl/ke/amd64/thrdini.c trunk/reactos/ntoskrnl/ke/amd64/trap.S
Modified: trunk/reactos/ntoskrnl/ke/amd64/boot.S URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/boot.S?re... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/boot.S [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/boot.S [iso-8859-1] Sat Feb 4 11:32:13 2012 @@ -31,7 +31,9 @@ mov ax, HEX(18) mov ss, ax mov rsp, rcx - sub rsp, HEX(300) // FIXME + // Note: 8 bytes extra to compensate for the missing return address on + // the stack. On function entry the stack is unaligned by 8!! + sub rsp, HEX(308) // FIXME .ENDPROLOG
jmp KiSystemStartupBootStack
Modified: trunk/reactos/ntoskrnl/ke/amd64/context.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/context.c... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/context.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/context.c [iso-8859-1] Sat Feb 4 11:32:13 2012 @@ -24,12 +24,16 @@ { KIRQL OldIrql;
+ /* Make sure we have an amd64 context, then remove the flag */ + ASSERT(ContextFlags & CONTEXT_AMD64); + ContextFlags &= ~CONTEXT_AMD64; + /* Do this at APC_LEVEL */ OldIrql = KeGetCurrentIrql(); if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
/* Handle integer registers */ - if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) + if (ContextFlags & CONTEXT_INTEGER) { TrapFrame->Rax = Context->Rax; TrapFrame->Rbx = Context->Rbx; @@ -42,15 +46,18 @@ TrapFrame->R9 = Context->R9; TrapFrame->R10 = Context->R10; TrapFrame->R11 = Context->R11; - ExceptionFrame->R12 = Context->R12; - ExceptionFrame->R13 = Context->R13; - ExceptionFrame->R14 = Context->R14; - ExceptionFrame->R15 = Context->R15; + if (ExceptionFrame) + { + ExceptionFrame->R12 = Context->R12; + ExceptionFrame->R13 = Context->R13; + ExceptionFrame->R14 = Context->R14; + ExceptionFrame->R15 = Context->R15; + } }
/* Handle floating point registers */ - if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) == - CONTEXT_FLOATING_POINT) && (Context->SegCs & MODE_MASK)) + if ((ContextFlags & CONTEXT_FLOATING_POINT) && + (Context->SegCs & MODE_MASK)) { TrapFrame->Xmm0 = Context->Xmm0; TrapFrame->Xmm1 = Context->Xmm1; @@ -58,20 +65,23 @@ TrapFrame->Xmm3 = Context->Xmm3; TrapFrame->Xmm4 = Context->Xmm4; TrapFrame->Xmm5 = Context->Xmm5; - ExceptionFrame->Xmm6 = Context->Xmm6; - ExceptionFrame->Xmm7 = Context->Xmm7; - ExceptionFrame->Xmm8 = Context->Xmm8; - ExceptionFrame->Xmm9 = Context->Xmm9; - ExceptionFrame->Xmm10 = Context->Xmm10; - ExceptionFrame->Xmm11 = Context->Xmm11; - ExceptionFrame->Xmm12 = Context->Xmm12; - ExceptionFrame->Xmm13 = Context->Xmm13; - ExceptionFrame->Xmm14 = Context->Xmm14; - ExceptionFrame->Xmm15 = Context->Xmm15; + if (ExceptionFrame) + { + ExceptionFrame->Xmm6 = Context->Xmm6; + ExceptionFrame->Xmm7 = Context->Xmm7; + ExceptionFrame->Xmm8 = Context->Xmm8; + ExceptionFrame->Xmm9 = Context->Xmm9; + ExceptionFrame->Xmm10 = Context->Xmm10; + ExceptionFrame->Xmm11 = Context->Xmm11; + ExceptionFrame->Xmm12 = Context->Xmm12; + ExceptionFrame->Xmm13 = Context->Xmm13; + ExceptionFrame->Xmm14 = Context->Xmm14; + ExceptionFrame->Xmm15 = Context->Xmm15; + } }
/* Handle control registers */ - if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) + if (ContextFlags & CONTEXT_CONTROL) { /* Check if this was a Kernel Trap */ if (Context->SegCs == KGDT64_R0_CODE) @@ -94,7 +104,7 @@ }
/* Handle segment selectors */ - if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) + if (ContextFlags & CONTEXT_SEGMENTS) { /* Check if this was a Kernel Trap */ if (Context->SegCs == KGDT64_R0_CODE) @@ -116,8 +126,7 @@ }
/* Handle debug registers */ - if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == - CONTEXT_DEBUG_REGISTERS) + if (ContextFlags & CONTEXT_DEBUG_REGISTERS) { /* Copy the debug registers */ TrapFrame->Dr0 = Context->Dr0; @@ -158,10 +167,14 @@ Context->R9 = TrapFrame->R9; Context->R10 = TrapFrame->R10; Context->R11 = TrapFrame->R11; - Context->R12 = ExceptionFrame->R12; - Context->R13 = ExceptionFrame->R13; - Context->R14 = ExceptionFrame->R14; - Context->R15 = ExceptionFrame->R15; + + if (ExceptionFrame) + { + Context->R12 = ExceptionFrame->R12; + Context->R13 = ExceptionFrame->R13; + Context->R14 = ExceptionFrame->R14; + Context->R15 = ExceptionFrame->R15; + } }
/* Handle floating point registers */ @@ -174,16 +187,19 @@ Context->Xmm3 = TrapFrame->Xmm3; Context->Xmm4 = TrapFrame->Xmm4; Context->Xmm5 = TrapFrame->Xmm5; - Context->Xmm6 = ExceptionFrame->Xmm6; - Context->Xmm7 = ExceptionFrame->Xmm7; - Context->Xmm8 = ExceptionFrame->Xmm8; - Context->Xmm9 = ExceptionFrame->Xmm9; - Context->Xmm10 = ExceptionFrame->Xmm10; - Context->Xmm11 = ExceptionFrame->Xmm11; - Context->Xmm12 = ExceptionFrame->Xmm12; - Context->Xmm13 = ExceptionFrame->Xmm13; - Context->Xmm14 = ExceptionFrame->Xmm14; - Context->Xmm15 = ExceptionFrame->Xmm15; + if (ExceptionFrame) + { + Context->Xmm6 = ExceptionFrame->Xmm6; + Context->Xmm7 = ExceptionFrame->Xmm7; + Context->Xmm8 = ExceptionFrame->Xmm8; + Context->Xmm9 = ExceptionFrame->Xmm9; + Context->Xmm10 = ExceptionFrame->Xmm10; + Context->Xmm11 = ExceptionFrame->Xmm11; + Context->Xmm12 = ExceptionFrame->Xmm12; + Context->Xmm13 = ExceptionFrame->Xmm13; + Context->Xmm14 = ExceptionFrame->Xmm14; + Context->Xmm15 = ExceptionFrame->Xmm15; + } }
/* Handle control registers */
Modified: trunk/reactos/ntoskrnl/ke/amd64/ctxswitch.S URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/ctxswitch... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/ctxswitch.S [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/ctxswitch.S [iso-8859-1] Sat Feb 4 11:32:13 2012 @@ -3,7 +3,7 @@ * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/amd64/ctxswitch.S * PURPOSE: Thread Context Switching - * + * * PROGRAMMER: Timo kreuzer (timo.kreuzer@reactos.org) */
@@ -12,46 +12,66 @@ #include <asm.inc> #include <ksamd64.inc>
+EXTERN KiSwapContextResume:PROC + /* FUNCTIONS ****************************************************************/
.code64
-/*++ - * KiThreadStartup - * +/*! + * \name KiThreadStartup + * + * \brief * The KiThreadStartup routine is the beginning of any thread. * - * Params: - * SystemRoutine - Pointer to the System Startup Routine. Either - * PspUserThreadStartup or PspSystemThreadStartup - * - * StartRoutine - For Kernel Threads only, specifies the starting execution - * point of the new thread. - * - * StartContext - For Kernel Threads only, specifies a pointer to variable - * context data to be sent to the StartRoutine above. - * - * UserThread - Indicates whether or not this is a user thread. This tells - * us if the thread has a context or not. - * - * TrapFrame - Pointer to the KTHREAD to which the caller wishes to - * switch from. - * - * Returns: + * VOID + * KiThreadStartup( + * IN PKSTART_ROUTINE StartRoutine<rcx>, + * IN PVOID StartContext<rdx>, + * IN PVOID P3<r8>, + * IN PVOID P4<r9>, + * IN PVOID SystemRoutine); + * + * \param StartRoutine + * For Kernel Threads only, specifies the starting execution point + * of the new thread. + * + * \param StartContext + * For Kernel Threads only, specifies a pointer to variable + * context data to be sent to the StartRoutine above. + * + * \param P3, P4 - not used atm + * + * \param SystemRoutine + * Pointer to the System Startup Routine. + * Either PspUserThreadStartup or PspSystemThreadStartup + * + * \return * Should never return for a system thread. Returns through the System Call * Exit Dispatcher for a user thread. * - * Remarks: + * \remarks * If a return from a system thread is detected, a bug check will occur. * *--*/ PUBLIC KiThreadStartup -KiThreadStartup: - - /* - * Clear all the non-volatile registers, so the thread won't be tempted to - * expect any static data (like some badly coded usermode/win9x apps do) +.PROC KiThreadStartup + /* KSTART_FRAME is already on the stack when we enter here. + * The virtual prolog looks like this: + * sub rsp, 5 * 8 + * mov [rsp + SfP1Home], rcx + * mov [rsp + SfP2Home], rdx + * mov [rsp + SfP3Home], r8 + * mov [rsp + SfP4Home], r9 */ + + /* Terminate the unwind chain, by setting rbp as frame pointer, + which contains 0 */ + .setframe rbp, 0 + .endprolog + + /* Clear all the non-volatile registers, so the thread won't be tempted to + * expect any static data (like some badly coded usermode/win9x apps do) */ xor rbx, rbx xor rsi, rsi xor rdi, rdi @@ -67,73 +87,107 @@ mov rax, APC_LEVEL mov cr8, rax
- /* - * Call the System Routine which is right on our stack now. - * After we pop the pointer, the Start Routine/Context is on the - * stack, we pop it as parameters to the System Routine into rcx - */ - pop rax - pop rcx - call rax - - /* The thread returned... was it a user-thread? */ - pop rcx + /* We have the KSTART_FRAME on the stack, P1Home and P2Home are preloaded + * with the parameters for the system routine. The address of the system + * routine is stored in P4Home. */ + mov rcx, [rsp + SfP1Home] /* StartRoutine */ + mov rdx, [rsp + SfP2Home] /* StartContext */ + mov r8, [rsp + SfP3Home] /* ? */ + call qword ptr [rsp + SfP4Home] /* SystemRoutine */ + + /* The thread returned. If it was a user-thread, we have a return address + and all is well, otherwise this is very bad. */ + mov rcx, [rsp + SfReturn] or rcx, rcx - jz BadThread - - /* Yes it was, set our trapframe for the System Call Exit Dispatcher */ - mov ebp, esp - - /* Exit back to user-mode */ -// jmp _KiServiceExit2 -UNIMPLEMENTED KiThreadStartup_KiServiceExit2 - -BadThread: + jnz .leave
/* A system thread returned...this is very bad! */ int 3
- -/*++ - * KiSwapContextInternal - * +.leave: + /* It was a user thread, set our trapframe for the System Call Exit Dispatcher */ + lea rcx, [rsp + 6 * 8 + KEXCEPTION_FRAME_LENGTH] + + /* Return to the trap exit code */ + add rsp, 5 * 8 + ret +.ENDP + +/*! + * \name KiSwapContextInternal + * + * \brief * The KiSwapContextInternal routine switches context to another thread. * - * Params: - * ESI - Pointer to the KTHREAD to which the caller wishes to - * switch to. - * EDI - Pointer to the KTHREAD to which the caller wishes to - * switch from. - * - * Returns: + * \param rcx + * Pointer to the KTHREAD to which the caller wishes to switch to. + * + * \param rdx + * Pointer to the KTHREAD to which the caller wishes to switch from. + * + * \param r8b + * APC bypass + * + * \return * None. * - * Remarks: - * Absolutely all registers except ESP can be trampled here for maximum code flexibility. + * \remarks + * ... * *--*/ PUBLIC KiSwapContextInternal -KiSwapContextInternal: - UNIMPLEMENTED KiSwapContextInternal +.PROC KiSwapContextInternal + + push rbp + .pushreg rbp + sub rsp, 6 * 8 + .allocstack 6 * 8 + .endprolog + + /* Save APC bypass */ + mov [rsp + SwApcBypass], r8b + + /* Save kernel stack of old thread */ + mov [rdx + KTHREAD_KernelStack], rsp + + /* Save new thread in rbp */ + mov rbp, rcx + + //call KiSwapContextSuspend + + /* Load stack of new thread */ + mov rsp, [rbp + KTHREAD_KernelStack] + + /* Reload APC bypass */ + mov r8b, [rsp + SwApcBypass] + + call KiSwapContextResume + + /* Cleanup and return */ + add rsp, 6 * 8 + pop rbp ret
- -/** +.ENDP + + + +/*! * KiSwapContext * * \brief * The KiSwapContext routine switches context to another thread. * * BOOLEAN - * KiSwapContext(PKTHREAD CurrentThread, PKTHREAD TargetThread); - * - * \param CurrentThread + * KiSwapContext(KIRQL WaitIrql, PKTHREAD CurrentThread); + * + * \param WaitIrql <rcx> + * ... + * + * \param CurrentThread <rdx> * Pointer to the KTHREAD of the current thread. - * - * \param TargetThread - * Pointer to the KTHREAD to which the caller wishes to switch to. - * - * \returns + * + * \return * The WaitStatus of the Target Thread. * * \remarks @@ -141,59 +195,74 @@ * non-volatile registers so that the Internal function can use all of * them. It will also save the old current thread and set the new one. * - * The calling thread does not return after KiSwapContextInternal until + * The calling thread does not return after KiSwapContextInternal until * another thread switches to IT. * *--*/ PUBLIC KiSwapContext -KiSwapContext: - - /* Save 10 registers */ - sub rsp, 10 * 8 - - /* Save all the non-volatile ones */ - mov [rsp+72], r15 - mov [rsp+64], r14 - mov [rsp+56], r13 - mov [rsp+48], r12 - mov [rsp+40], r11 - mov [rsp+32], r10 - - mov [rsp+24], rbx - mov [rsp+16], rsi - mov [rsp+8], rdi - mov [rsp+0], rbp - - /* Get the PCR */ - mov rbx, gs:[PcSelf] - - /* Get the current thread */ - mov rdi, rcx - - /* Get the New Thread */ - mov rsi, rdx - - /* Get the wait IRQL */ - movzx ecx, byte ptr [edi+KTHREAD_WAIT_IRQL] +.PROC KiSwapContext + + /* Allocate a KEXCEPTION_FRAME on the stack (+8 for proper alignment) */ + sub rsp, KEXCEPTION_FRAME_LENGTH + 8 + .allocstack KEXCEPTION_FRAME_LENGTH + 8 + + /* save non-volatiles in KEXCEPTION_FRAME */ + mov [rsp + KEXCEPTION_FRAME_Rbp], rbp + .savereg rbp, KEXCEPTION_FRAME_Rbp + mov [rsp + KEXCEPTION_FRAME_Rbx], rbx + .savereg rbx, KEXCEPTION_FRAME_Rbx + mov [rsp + KEXCEPTION_FRAME_Rdi], rdi + .savereg rdi, KEXCEPTION_FRAME_Rdi + mov [rsp + KEXCEPTION_FRAME_Rsi], rsi + .savereg rsi, KEXCEPTION_FRAME_Rsi + mov [rsp + KEXCEPTION_FRAME_R12], r12 + .savereg r12, KEXCEPTION_FRAME_R12 + mov [rsp + KEXCEPTION_FRAME_R13], r13 + .savereg r13, KEXCEPTION_FRAME_R13 + mov [rsp + KEXCEPTION_FRAME_R14], r14 + .savereg r14, KEXCEPTION_FRAME_R14 + mov [rsp + KEXCEPTION_FRAME_R15], r15 + .savereg r15, KEXCEPTION_FRAME_R15 + movdqa [rsp + KEXCEPTION_FRAME_Xmm6], xmm6 + movdqa [rsp + KEXCEPTION_FRAME_Xmm7], xmm7 + movdqa [rsp + KEXCEPTION_FRAME_Xmm8], xmm8 + movdqa [rsp + KEXCEPTION_FRAME_Xmm9], xmm9 + movdqa [rsp + KEXCEPTION_FRAME_Xmm10], xmm10 + movdqa [rsp + KEXCEPTION_FRAME_Xmm11], xmm11 + movdqa [rsp + KEXCEPTION_FRAME_Xmm12], xmm12 + movdqa [rsp + KEXCEPTION_FRAME_Xmm13], xmm13 + movdqa [rsp + KEXCEPTION_FRAME_Xmm14], xmm14 + movdqa [rsp + KEXCEPTION_FRAME_Xmm15], xmm15 + // KEXCEPTION_FRAME_MxCsr + .endprolog
/* Do the swap with the registers correctly setup */ + mov rcx, gs:[PcCurrentThread] /* Pointer to the new thread */ call KiSwapContextInternal
- /* Restore the registers */ - mov rbp, [rsp+0] - mov rdi, [rsp+8] - mov rsi, [rsp+16] - mov rbx, [rsp+24] - - mov r10, [rsp+32] - mov r11, [rsp+40] - mov r12, [rsp+48] - mov r13, [rsp+56] - mov r14, [rsp+64] - mov r15, [rsp+72] - - /* Clean stack */ - add esp, 10 * 8 + /* restore non-volatile registers */ + mov rbp, [rsp + KEXCEPTION_FRAME_Rbp] + mov rbx, [rsp + KEXCEPTION_FRAME_Rbx] + mov rdi, [rsp + KEXCEPTION_FRAME_Rdi] + mov rsi, [rsp + KEXCEPTION_FRAME_Rsi] + mov r12, [rsp + KEXCEPTION_FRAME_R12] + mov r13, [rsp + KEXCEPTION_FRAME_R13] + mov r14, [rsp + KEXCEPTION_FRAME_R14] + mov r15, [rsp + KEXCEPTION_FRAME_R15] + movdqa xmm6, [rsp + KEXCEPTION_FRAME_Xmm6] + movdqa xmm7, [rsp + KEXCEPTION_FRAME_Xmm7] + movdqa xmm8, [rsp + KEXCEPTION_FRAME_Xmm8] + movdqa xmm9, [rsp + KEXCEPTION_FRAME_Xmm9] + movdqa xmm10, [rsp + KEXCEPTION_FRAME_Xmm10] + movdqa xmm11, [rsp + KEXCEPTION_FRAME_Xmm11] + movdqa xmm12, [rsp + KEXCEPTION_FRAME_Xmm12] + movdqa xmm13, [rsp + KEXCEPTION_FRAME_Xmm13] + movdqa xmm14, [rsp + KEXCEPTION_FRAME_Xmm14] + movdqa xmm15, [rsp + KEXCEPTION_FRAME_Xmm15] + + /* Clean stack and return */ + add rsp, KEXCEPTION_FRAME_LENGTH + 8 ret +.ENDP
END
Modified: trunk/reactos/ntoskrnl/ke/amd64/except.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/except.c?... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/except.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/except.c [iso-8859-1] Sat Feb 4 11:32:13 2012 @@ -13,7 +13,7 @@ #define NDEBUG #include <debug.h>
-extern ULONG64 InterruptDispatchTable[256]; +extern KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRange[256];
/* GLOBALS *******************************************************************/
@@ -74,7 +74,7 @@ } else { - Offset = (ULONG64)&InterruptDispatchTable[i]; + Offset = (ULONG64)&KiUnexpectedRange[i]._Op_push; KiIdt[i].Dpl = 0; KiIdt[i].IstIndex = 0; } @@ -92,6 +92,146 @@ __lidt(&KiIdtDescriptor.Limit); }
+static +VOID +KiDispatchExceptionToUser( + IN PKTRAP_FRAME TrapFrame, + IN PCONTEXT Context, + IN PEXCEPTION_RECORD ExceptionRecord) +{ + EXCEPTION_RECORD LocalExceptRecord; + ULONG Size; + ULONG64 UserRsp; + PCONTEXT UserContext; + PEXCEPTION_RECORD UserExceptionRecord; + + /* Make sure we have a valid SS */ + if (TrapFrame->SegSs != (KGDT64_R3_DATA | RPL_MASK)) + { + /* Raise an access violation instead */ + LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION; + LocalExceptRecord.ExceptionFlags = 0; + LocalExceptRecord.NumberParameters = 0; + ExceptionRecord = &LocalExceptRecord; + } + + /* Calculate the size of the exception record */ + Size = FIELD_OFFSET(EXCEPTION_RECORD, ExceptionInformation) + + ExceptionRecord->NumberParameters * sizeof(ULONG64); + + /* Get new stack pointer and align it to 16 bytes */ + UserRsp = (Context->Rsp - Size - sizeof(CONTEXT)) & ~15; + + /* Get pointers to the usermode context and exception record */ + UserContext = (PVOID)UserRsp; + UserExceptionRecord = (PVOID)(UserRsp + sizeof(CONTEXT)); + + /* Set up the user-stack */ + _SEH2_TRY + { + /* Probe stack and copy Context */ + ProbeForWrite(UserContext, sizeof(CONTEXT), sizeof(ULONG64)); + *UserContext = *Context; + + /* Probe stack and copy exception record */ + ProbeForWrite(UserExceptionRecord, Size, sizeof(ULONG64)); + *UserExceptionRecord = *ExceptionRecord; + } + _SEH2_EXCEPT((LocalExceptRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord), + EXCEPTION_EXECUTE_HANDLER) + { + // FIXNE: handle stack overflow + + /* Nothing we can do here */ + _SEH2_YIELD(return); + } + _SEH2_END; + + /* Now set the two params for the user-mode dispatcher */ + TrapFrame->Rcx = (ULONG64)UserContext; + TrapFrame->Rdx = (ULONG64)UserExceptionRecord; + + /* Set new Stack Pointer */ + TrapFrame->Rsp = UserRsp; + + /* Force correct segments */ + TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK; + TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK; + TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK; + TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK; + TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK; + TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK; + + /* Set RIP to the User-mode Dispatcher */ + TrapFrame->Rip = (ULONG64)KeUserExceptionDispatcher; + + /* Exit to usermode */ + KiServiceExit2(TrapFrame); +} + +static +VOID +KiPageInDirectory(PVOID ImageBase, USHORT Directory) +{ + volatile CHAR *Pointer; + ULONG Size; + + /* Get a pointer to the debug directory */ + Pointer = RtlImageDirectoryEntryToData(ImageBase, 1, Directory, &Size); + if (!Pointer) return; + + /* Loop all pages */ + while ((LONG)Size > 0) + { + /* Touch it, to page it in */ + (void)*Pointer; + Pointer += PAGE_SIZE; + Size -= PAGE_SIZE; + } +} + +VOID +KiPrepareUserDebugData(void) +{ + PLDR_DATA_TABLE_ENTRY LdrEntry; + PPEB_LDR_DATA PebLdr; + PLIST_ENTRY ListEntry; + PTEB Teb; + + /* Get the Teb for this process */ + Teb = KeGetCurrentThread()->Teb; + if (!Teb) return; + + _SEH2_TRY + { + /* Get a pointer to the loader data */ + PebLdr = Teb->ProcessEnvironmentBlock->Ldr; + if (!PebLdr) _SEH2_YIELD(return); + + /* Now loop all entries in the module list */ + for (ListEntry = PebLdr->InLoadOrderModuleList.Flink; + ListEntry != &PebLdr->InLoadOrderModuleList; + ListEntry = ListEntry->Flink) + { + /* Get the loader entry */ + LdrEntry = CONTAINING_RECORD(ListEntry, + LDR_DATA_TABLE_ENTRY, + InLoadOrderLinks); + + KiPageInDirectory((PVOID)LdrEntry->DllBase, + IMAGE_DIRECTORY_ENTRY_DEBUG); + + KiPageInDirectory((PVOID)LdrEntry->DllBase, + IMAGE_DIRECTORY_ENTRY_EXCEPTION); + } + + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + } + _SEH2_END +} + VOID NTAPI KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, @@ -101,9 +241,6 @@ IN BOOLEAN FirstChance) { CONTEXT Context; - -// FrLdrDbgPrint("KiDispatchException(%p, %p, %p, %d, %d)\n", -// ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode, FirstChance);
/* Increase number of Exception Dispatches */ KeGetCurrentPrcb()->KeExceptionDispatchCount++; @@ -179,8 +316,66 @@ } else { - /* FIXME: user-mode exception handling unimplemented */ - ASSERT(FALSE); + /* User mode exception, was it first-chance? */ + if (FirstChance) + { + /* + * Break into the kernel debugger unless a user mode debugger + * is present or user mode exceptions are ignored, except if this + * is a debug service which we must always pass to KD + */ + if ((!(PsGetCurrentProcess()->DebugPort) && + !(KdIgnoreUmExceptions)) || + (KdIsThisAKdTrap(ExceptionRecord, &Context, PreviousMode))) + { + /* Make sure the debugger can access debug directories */ + KiPrepareUserDebugData(); + + /* Call the kernel debugger */ + if (KiDebugRoutine(TrapFrame, + ExceptionFrame, + ExceptionRecord, + &Context, + PreviousMode, + FALSE)) + { + /* Exception was handled */ + goto Handled; + } + } + + /* Forward exception to user mode debugger */ + if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return; + + //KiDispatchExceptionToUser() + __debugbreak(); + } + + /* Try second chance */ + if (DbgkForwardException(ExceptionRecord, TRUE, TRUE)) + { + /* Handled, get out */ + return; + } + else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE)) + { + /* Handled, get out */ + return; + } + + /* 3rd strike, kill the process */ + DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx, BaseAddress: %lx\n", + PsGetCurrentProcess()->ImageFileName, + ExceptionRecord->ExceptionCode, + ExceptionRecord->ExceptionAddress, + PsGetCurrentProcess()->SectionBaseAddress); + + ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode); + KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED, + ExceptionRecord->ExceptionCode, + (ULONG_PTR)ExceptionRecord->ExceptionAddress, + (ULONG_PTR)TrapFrame, + 0); }
Handled:
Modified: trunk/reactos/ntoskrnl/ke/amd64/interrupt.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/interrupt... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/interrupt.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/interrupt.c [iso-8859-1] Sat Feb 4 11:32:13 2012 @@ -6,7 +6,8 @@ * for the purpopses of connecting, disconnecting and setting * up ISRs for drivers. The backend behind the Io* Interrupt * routines. - * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@web.de) + * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) + * Alex Ionescu (alex.ionescu@reactos.org) */
/* INCLUDES *****************************************************************/ @@ -15,30 +16,151 @@ #define NDEBUG #include <debug.h>
+extern UCHAR KiInterruptDispatchTemplate[16]; +extern UCHAR KiUnexpectedRange[]; +extern UCHAR KiUnexpectedRangeEnd[]; +void KiInterruptDispatch(void); + + /* FUNCTIONS ****************************************************************/ + +VOID +NTAPI +KeInitializeInterrupt( + IN PKINTERRUPT Interrupt, + IN PKSERVICE_ROUTINE ServiceRoutine, + IN PVOID ServiceContext, + IN PKSPIN_LOCK SpinLock, + IN ULONG Vector, + IN KIRQL Irql, + IN KIRQL SynchronizeIrql, + IN KINTERRUPT_MODE InterruptMode, + IN BOOLEAN ShareVector, + IN CHAR ProcessorNumber, + IN BOOLEAN FloatingSave) +{ + + /* Initialize the header */ + Interrupt->Type = InterruptObject; + Interrupt->Size = sizeof(KINTERRUPT); + + /* If no Spinlock is given, use the internal */ + if (!SpinLock) SpinLock = &Interrupt->SpinLock; + KeInitializeSpinLock(&Interrupt->SpinLock); + + /* Set the given parameters */ + Interrupt->ServiceRoutine = ServiceRoutine; + Interrupt->ServiceContext = ServiceContext; + Interrupt->ActualLock = SpinLock; + Interrupt->Vector = Vector; + Interrupt->Irql = Irql; + Interrupt->SynchronizeIrql = SynchronizeIrql; + Interrupt->Mode = InterruptMode; + Interrupt->ShareVector = ShareVector; + Interrupt->Number = ProcessorNumber; + Interrupt->FloatingSave = FloatingSave; + + /* Set initial values */ + Interrupt->TickCount = 0; + Interrupt->Connected = FALSE; + Interrupt->ServiceCount = 0; + Interrupt->DispatchCount = 0; + Interrupt->TrapFrame = NULL; + Interrupt->Reserved = 0; + + /* Copy the dispatch code (its location independent, no need to patch it) */ + RtlCopyMemory(Interrupt->DispatchCode, + KiInterruptDispatchTemplate, + sizeof(Interrupt->DispatchCode)); + + Interrupt->DispatchAddress = 0; +} + +BOOLEAN +NTAPI +KeConnectInterrupt(IN PKINTERRUPT Interrupt) +{ + PVOID CurrentHandler; + + ASSERT(Interrupt->Vector <= MAXIMUM_IDTVECTOR); + ASSERT(Interrupt->Number < KeNumberProcessors); + ASSERT(Interrupt->Irql <= HIGH_LEVEL); + + /* Check if its already connected */ + if (Interrupt->Connected) return TRUE; + + /* Query the current handler */ + CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector); + + /* Check if the vector is already unused */ + if ((CurrentHandler >= (PVOID)KiUnexpectedRange) && + (CurrentHandler <= (PVOID)KiUnexpectedRangeEnd)) + { + /* Initialize the list for chained interrupts */ + InitializeListHead(&Interrupt->InterruptListEntry); + + /* Set normal dispatch address */ + Interrupt->DispatchAddress = KiInterruptDispatch; + + /* Set the new handler */ + KeRegisterInterruptHandler(Interrupt->Vector, + Interrupt->DispatchCode); + + if (!HalEnableSystemInterrupt(Interrupt->Vector, + Interrupt->Irql, + Interrupt->Mode)) + { + /* Didn't work, restore old handler */ + DPRINT1("HalEnableSystemInterrupt failed\n"); + KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler); + return FALSE; + } + + /* Mark as connected */ + Interrupt->Connected = TRUE; + } + else + { + // later + __debugbreak(); + } + + return TRUE; +}
BOOLEAN NTAPI KeDisconnectInterrupt(IN PKINTERRUPT Interrupt) { UNIMPLEMENTED; + __debugbreak(); return FALSE; }
-VOID +BOOLEAN NTAPI -KeInitializeInterrupt(IN PKINTERRUPT Interrupt, - IN PKSERVICE_ROUTINE ServiceRoutine, - IN PVOID ServiceContext, - IN PKSPIN_LOCK SpinLock, - IN ULONG Vector, - IN KIRQL Irql, - IN KIRQL SynchronizeIrql, - IN KINTERRUPT_MODE InterruptMode, - IN BOOLEAN ShareVector, - IN CHAR ProcessorNumber, - IN BOOLEAN FloatingSave) +KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt, + IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, + IN PVOID SynchronizeContext OPTIONAL) { - UNIMPLEMENTED; + BOOLEAN Success; + KIRQL OldIrql; + + /* Raise IRQL */ + OldIrql = KfRaiseIrql(Interrupt->SynchronizeIrql); + + /* Acquire interrupt spinlock */ + KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock); + + /* Call the routine */ + Success = SynchronizeRoutine(SynchronizeContext); + + /* Release lock */ + KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock); + + /* Lower IRQL */ + KeLowerIrql(OldIrql); + + /* Return status */ + return Success; } -
Modified: trunk/reactos/ntoskrnl/ke/amd64/kiinit.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/kiinit.c?... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/kiinit.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/kiinit.c [iso-8859-1] Sat Feb 4 11:32:13 2012 @@ -32,6 +32,10 @@ UCHAR DECLSPEC_ALIGN(16) KiDoubleFaultStackData[KERNEL_STACK_SIZE] = {0}; ULONG_PTR P0BootStack = (ULONG_PTR)&P0BootStackData[KERNEL_STACK_SIZE]; ULONG_PTR KiDoubleFaultStack = (ULONG_PTR)&KiDoubleFaultStackData[KERNEL_STACK_SIZE]; + +void KiInitializeSegments(); +void KiSystemCallEntry64(); +void KiSystemCallEntry32();
/* FUNCTIONS *****************************************************************/
@@ -91,7 +95,7 @@ USHORT Tr = 0;
/* Zero out the PCR */ - RtlZeroMemory(Pcr, PAGE_SIZE); + RtlZeroMemory(Pcr, sizeof(KIPCR));
/* Set pointers to ourselves */ Pcr->Self = (PKPCR)Pcr; @@ -152,17 +156,20 @@ /* Start us out at PASSIVE_LEVEL */ Pcr->Irql = PASSIVE_LEVEL; KeSetCurrentIrql(PASSIVE_LEVEL); +} + +VOID +NTAPI +KiInitializeCpu(PKIPCR Pcr) +{ + ULONG FeatureBits; + + /* Initialize gs */ + KiInitializeSegments();
/* Set GS base */ - __writemsr(X86_MSR_GSBASE, (ULONG64)Pcr); - __writemsr(X86_MSR_KERNEL_GSBASE, (ULONG64)Pcr); -} - -VOID -NTAPI -KiInitializeCpu(PKPRCB Prcb) -{ - ULONG FeatureBits; + __writemsr(MSR_GS_BASE, (ULONG64)Pcr); + __writemsr(MSR_GS_SWAP, (ULONG64)Pcr);
/* Detect and set the CPU Type */ KiSetProcessorType(); @@ -184,7 +191,7 @@ FeatureBits |= KF_NX_ENABLED;
/* Save feature bits */ - Prcb->FeatureBits = FeatureBits; + Pcr->Prcb.FeatureBits = FeatureBits;
/* Enable fx save restore support */ __writecr4(__readcr4() | CR4_FXSR); @@ -203,6 +210,19 @@
/* LDT is unused */ __lldt(0); + + /* Set the systemcall entry points */ + __writemsr(MSR_LSTAR, (ULONG64)KiSystemCallEntry64); + __writemsr(MSR_CSTAR, (ULONG64)KiSystemCallEntry32); + + __writemsr(MSR_STAR, ((ULONG64)KGDT64_R0_CODE << 32) | + ((ULONG64)(KGDT64_R3_CMCODE|RPL_MASK) << 48)); + + /* Set the flags to be cleared when doing a syscall */ + __writemsr(MSR_SYSCALL_MASK, EFLAGS_IF_MASK | EFLAGS_TF | EFLAGS_DF); + + /* Enable syscall instruction */ + __writemsr(MSR_EFER, __readmsr(MSR_EFER) | MSR_SCE); }
VOID @@ -339,7 +359,7 @@
/* HACK */ FrLdrDbgPrint = LoaderBlock->u.I386.CommonDataArea; - FrLdrDbgPrint("Hello from KiSystemStartup!!!\n"); + //FrLdrDbgPrint("Hello from KiSystemStartup!!!\n");
/* Save the loader block */ KeLoaderBlock = LoaderBlock; @@ -350,7 +370,6 @@ /* LoaderBlock initialization for Cpu 0 */ if (Cpu == 0) { - FrLdrDbgPrint("LoaderBlock->Prcb=%p\n", LoaderBlock->Prcb); /* Set the initial stack, idle thread and process */ LoaderBlock->KernelStack = (ULONG_PTR)P0BootStack; LoaderBlock->Thread = (ULONG_PTR)&KiInitialThread; @@ -378,7 +397,7 @@ KiInitializePcr(Pcr, Cpu, InitialThread, (PVOID)KiDoubleFaultStack);
/* Initialize the CPU features */ - KiInitializeCpu(&Pcr->Prcb); + KiInitializeCpu(Pcr);
/* Initial setup for the boot CPU */ if (Cpu == 0)
Modified: trunk/reactos/ntoskrnl/ke/amd64/stubs.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/stubs.c?r... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/stubs.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/stubs.c [iso-8859-1] Sat Feb 4 11:32:13 2012 @@ -13,12 +13,69 @@ #include <debug.h>
VOID -NTAPI -KiDispatchInterrupt(VOID) -{ - UNIMPLEMENTED; - __debugbreak(); -} +KiRetireDpcListInDpcStack( + PKPRCB Prcb, + PVOID DpcStack); + +VOID +NTAPI +KiDpcInterruptHandler(VOID) +{ + PKPRCB Prcb = KeGetCurrentPrcb(); + PKTHREAD NewThread, OldThread; + KIRQL OldIrql; + + /* Raise to DISPATCH_LEVEL */ + OldIrql = KfRaiseIrql(DISPATCH_LEVEL); + + /* Send an EOI */ + KiSendEOI(); + + /* Check for pending timers, pending DPCs, or pending ready threads */ + if ((Prcb->DpcData[0].DpcQueueDepth) || + (Prcb->TimerRequest) || + (Prcb->DeferredReadyListHead.Next)) + { + /* Retire DPCs while under the DPC stack */ + KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack); + } + + /* Enable interrupts */ + _enable(); + + /* Check for quantum end */ + if (Prcb->QuantumEnd) + { + /* Handle quantum end */ + Prcb->QuantumEnd = FALSE; + KiQuantumEnd(); + } + else if (Prcb->NextThread) + { + /* Capture current thread data */ + OldThread = Prcb->CurrentThread; + NewThread = Prcb->NextThread; + + /* Set new thread data */ + Prcb->NextThread = NULL; + Prcb->CurrentThread = NewThread; + + /* The thread is now running */ + NewThread->State = Running; + OldThread->WaitReason = WrDispatchInt; + + /* Make the old thread ready */ + KxQueueReadyThread(OldThread, Prcb); + + /* Swap to the new thread */ + KiSwapContext(APC_LEVEL, OldThread); + } + + /* Go back to old irql and disable interrupts */ + KeLowerIrql(OldIrql); + _disable(); +} +
VOID FASTCALL @@ -29,52 +86,13 @@ RtlZeroMemory(Address, Size); }
-VOID -FASTCALL -DECLSPEC_NORETURN -KiServiceExit(IN PKTRAP_FRAME TrapFrame, - IN NTSTATUS Status) -{ - UNIMPLEMENTED; - __debugbreak(); -} - -VOID -FASTCALL -DECLSPEC_NORETURN -KiServiceExit2(IN PKTRAP_FRAME TrapFrame) -{ - UNIMPLEMENTED; - __debugbreak(); -} - -BOOLEAN -NTAPI -KeConnectInterrupt(IN PKINTERRUPT Interrupt) -{ - UNIMPLEMENTED; - __debugbreak(); - return FALSE; -} - PVOID NTAPI KeSwitchKernelStack(PVOID StackBase, PVOID StackLimit) { UNIMPLEMENTED; + __debugbreak(); return NULL; -} - -BOOLEAN -NTAPI -KeSynchronizeExecution( - IN OUT PKINTERRUPT Interrupt, - IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, - IN PVOID SynchronizeContext) -{ - UNIMPLEMENTED; - __debugbreak(); - return FALSE; }
NTSTATUS @@ -91,12 +109,101 @@ }
VOID -KiIdleLoop() -{ - UNIMPLEMENTED; - for(;;); -} - +FASTCALL +KiIdleLoop(VOID) +{ + PKPRCB Prcb = KeGetCurrentPrcb(); + PKTHREAD OldThread, NewThread; + + /* Initialize the idle loop: disable interrupts */ + _enable(); + YieldProcessor(); + YieldProcessor(); + _disable(); + + /* Now loop forever */ + while (TRUE) + { + /* Check for pending timers, pending DPCs, or pending ready threads */ + if ((Prcb->DpcData[0].DpcQueueDepth) || + (Prcb->TimerRequest) || + (Prcb->DeferredReadyListHead.Next)) + { + /* Quiesce the DPC software interrupt */ + HalClearSoftwareInterrupt(DISPATCH_LEVEL); + + /* Handle it */ + KiRetireDpcList(Prcb); + } + + /* Check if a new thread is scheduled for execution */ + if (Prcb->NextThread) + { + /* Enable interupts */ + _enable(); + + /* Capture current thread data */ + OldThread = Prcb->CurrentThread; + NewThread = Prcb->NextThread; + + /* Set new thread data */ + Prcb->NextThread = NULL; + Prcb->CurrentThread = NewThread; + + /* The thread is now running */ + NewThread->State = Running; + + /* Do the swap at SYNCH_LEVEL */ + KfRaiseIrql(SYNCH_LEVEL); + + /* Switch away from the idle thread */ + KiSwapContext(APC_LEVEL, OldThread); + + /* Go back to DISPATCH_LEVEL */ + KeLowerIrql(DISPATCH_LEVEL); + + /* We are back in the idle thread -- disable interrupts again */ + _enable(); + YieldProcessor(); + YieldProcessor(); + _disable(); + } + else + { + /* Continue staying idle. Note the HAL returns with interrupts on */ + Prcb->PowerState.IdleFunction(&Prcb->PowerState); + } + } +} + + +/*! \name KiInitializeUserApc + * + * \brief + * Prepares the current trap frame (which must have come from user mode) + * with the ntdll.KiUserApcDispatcher entrypoint, copying a CONTEXT + * record with the context from the old trap frame to the threads user + * mode stack. + * + * \param ExceptionFrame + * \param TrapFrame + * \param NormalRoutine + * \param NormalContext + * \param SystemArgument1 + * \param SystemArgument2 + * + * \remarks + * This function is called from KiDeliverApc, when the trap frame came + * from user mode. This happens before a systemcall or interrupt exits back + * to usermode or when a thread is started from PspUserThreadstartup. + * The trap exit code will then leave to KiUserApcDispatcher which in turn + * calls the NormalRoutine, passing NormalContext, SystemArgument1 and + * SystemArgument2 as parameters. When that function returns, it calls + * NtContinue to return back to the kernel, where the old context that was + * saved on the usermode stack is restored and execution is transferred + * back to usermode, where the original trap originated from. + * + *--*/ VOID NTAPI KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame, @@ -106,8 +213,69 @@ IN PVOID SystemArgument1, IN PVOID SystemArgument2) { - UNIMPLEMENTED; - __debugbreak(); + CONTEXT Context; + ULONG64 AlignedRsp, Stack; + EXCEPTION_RECORD SehExceptRecord; + + /* Sanity check, that the trap frame is from user mode */ + ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode); + + /* Convert the current trap frame to a context */ + Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; + KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context); + + /* We jump to KiUserApcDispatcher in ntdll */ + TrapFrame->Rip = (ULONG64)KeUserApcDispatcher; + + /* Setup Ring 3 segments */ + TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK; + TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK; + TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK; + TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK; + TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK; + TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK; + + /* Sanitize EFLAGS, enable interrupts */ + TrapFrame->EFlags = (Context.EFlags & EFLAGS_USER_SANITIZE); + TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK; + + /* Set parameters for KiUserApcDispatcher */ + Context.P1Home = (ULONG64)NormalContext; + Context.P2Home = (ULONG64)SystemArgument1; + Context.P3Home = (ULONG64)SystemArgument2; + Context.P4Home = (ULONG64)NormalRoutine; + + /* Check if thread has IOPL and force it enabled if so */ + //if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL; + + /* Align Stack to 16 bytes and allocate space */ + AlignedRsp = Context.Rsp & ~15; + Stack = AlignedRsp - sizeof(CONTEXT); + TrapFrame->Rsp = Stack; + + /* The stack must be 16 byte aligned for KiUserApcDispatcher */ + ASSERT((Stack & 15) == 0); + + /* Protect with SEH */ + _SEH2_TRY + { + /* Probe the stack */ + ProbeForWrite((PCONTEXT)Stack, sizeof(CONTEXT), 8); + + /* Copy the context */ + RtlCopyMemory((PCONTEXT)Stack, &Context, sizeof(CONTEXT)); + } + _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER)) + { + /* Dispatch the exception */ + SehExceptRecord.ExceptionAddress = (PVOID)TrapFrame->Rip; + KiDispatchException(&SehExceptRecord, + ExceptionFrame, + TrapFrame, + UserMode, + TRUE); + } + _SEH2_END; }
VOID @@ -115,10 +283,126 @@ KiSwapProcess(IN PKPROCESS NewProcess, IN PKPROCESS OldProcess) { - UNIMPLEMENTED; - __debugbreak(); -} - + PKIPCR Pcr = (PKIPCR)KeGetPcr(); +#ifdef CONFIG_SMP + LONG SetMember; + + /* Update active processor mask */ + SetMember = (LONG)Pcr->SetMember; + InterlockedXor((PLONG)&NewProcess->ActiveProcessors, SetMember); + InterlockedXor((PLONG)&OldProcess->ActiveProcessors, SetMember); +#endif + + /* Update CR3 */ + __writecr3(NewProcess->DirectoryTableBase[0]); + + /* Update IOPM offset */ + Pcr->TssBase->IoMapBase = NewProcess->IopmOffset; +} + +#define MAX_SYSCALL_PARAMS 16 + +NTSTATUS +NtSyscallFailure(void) +{ + /* This is the failure function */ + return STATUS_ACCESS_VIOLATION; +} + +PVOID +KiSystemCallHandler( + IN PKTRAP_FRAME TrapFrame, + IN ULONG64 P2, + IN ULONG64 P3, + IN ULONG64 P4) +{ + PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; + PKTHREAD Thread; + PULONG64 KernelParams, UserParams; + ULONG ServiceNumber, Offset, Count; + ULONG64 UserRsp; + + DPRINT("Syscall #%ld\n", TrapFrame->Rax); + //__debugbreak(); + + /* Increase system call count */ + __addgsdword(FIELD_OFFSET(KIPCR, Prcb.KeSystemCalls), 1); + + /* Get the current thread */ + Thread = KeGetCurrentThread(); + + /* Set previous mode */ + Thread->PreviousMode = TrapFrame->PreviousMode = UserMode; + + /* Save the old trap frame and set the new */ + TrapFrame->TrapFrame = (ULONG64)Thread->TrapFrame; + Thread->TrapFrame = TrapFrame; + + /* Before enabling interrupts get the user rsp from the KPCR */ + UserRsp = __readgsqword(FIELD_OFFSET(KIPCR, UserRsp)); + TrapFrame->Rsp = UserRsp; + + /* Enable interrupts */ + _enable(); + + /* If the usermode rsp was not a usermode address, prepare an exception */ + if (UserRsp > MmUserProbeAddress) UserRsp = MmUserProbeAddress; + + /* Get the address of the usermode and kernelmode parameters */ + UserParams = (PULONG64)UserRsp + 1; + KernelParams = (PULONG64)TrapFrame - MAX_SYSCALL_PARAMS; + + /* Get the system call number from the trap frame and decode it */ + ServiceNumber = (ULONG)TrapFrame->Rax; + Offset = (ServiceNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; + ServiceNumber &= SERVICE_NUMBER_MASK; + + /* Get descriptor table */ + DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); + + /* Get stack bytes and calculate argument count */ + Count = DescriptorTable->Number[ServiceNumber] / 8; + + __try + { + switch (Count) + { + case 16: KernelParams[15] = UserParams[15]; + case 15: KernelParams[14] = UserParams[14]; + case 14: KernelParams[13] = UserParams[13]; + case 13: KernelParams[12] = UserParams[12]; + case 12: KernelParams[11] = UserParams[11]; + case 11: KernelParams[10] = UserParams[10]; + case 10: KernelParams[9] = UserParams[9]; + case 9: KernelParams[8] = UserParams[8]; + case 8: KernelParams[7] = UserParams[7]; + case 7: KernelParams[6] = UserParams[6]; + case 6: KernelParams[5] = UserParams[5]; + case 5: KernelParams[4] = UserParams[4]; + case 4: KernelParams[3] = P4; + case 3: KernelParams[2] = P3; + case 2: KernelParams[1] = P2; + case 1: KernelParams[0] = TrapFrame->R10; + case 0: + break; + + default: + __debugbreak(); + break; + } + } + __except(1) + { + TrapFrame->Rax = _SEH2_GetExceptionCode(); + return (PVOID)NtSyscallFailure; + } + + + return (PVOID)DescriptorTable->Base[ServiceNumber]; +} + + +// FIXME: we need to VOID KiSystemService(IN PKTHREAD Thread, IN PKTRAP_FRAME TrapFrame, @@ -145,6 +429,7 @@ (ULONG Selector1, LDT_ENTRY LdtEntry1, ULONG Selector2, LDT_ENTRY LdtEntry2) { UNIMPLEMENTED; + __debugbreak(); return STATUS_UNSUCCESSFUL; }
@@ -153,9 +438,8 @@ NtVdmControl(IN ULONG ControlCode, IN PVOID ControlData) { - UNIMPLEMENTED; - __debugbreak(); - return STATUS_UNSUCCESSFUL; + /* Not supported */ + return STATUS_NOT_IMPLEMENTED; }
NTSTATUS
Modified: trunk/reactos/ntoskrnl/ke/amd64/thrdini.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/thrdini.c... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/thrdini.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/thrdini.c [iso-8859-1] Sat Feb 4 11:32:13 2012 @@ -2,8 +2,9 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/i386/thread.c - * PURPOSE: i386 Thread Context Creation - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * PURPOSE: amd64 Thread Context Creation + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + * Alex Ionescu (alex@relsoft.net) */
/* INCLUDES ******************************************************************/ @@ -16,6 +17,7 @@ { KSWITCH_FRAME CtxSwitchFrame; KSTART_FRAME StartFrame; + KEXCEPTION_FRAME ExceptionFrame; KTRAP_FRAME TrapFrame; //FX_SAVE_AREA FxSaveArea; } KUINIT_FRAME, *PKUINIT_FRAME; @@ -35,74 +37,52 @@ IN PKSYSTEM_ROUTINE SystemRoutine, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext, - IN PCONTEXT ContextPointer) + IN PCONTEXT Context) { //PFX_SAVE_AREA FxSaveArea; //PFXSAVE_FORMAT FxSaveFormat; PKSTART_FRAME StartFrame; PKSWITCH_FRAME CtxSwitchFrame; PKTRAP_FRAME TrapFrame; - CONTEXT LocalContext; - PCONTEXT Context = NULL; ULONG ContextFlags;
/* Check if this is a With-Context Thread */ - if (ContextPointer) - { + if (Context) + { + PKUINIT_FRAME InitFrame; + /* Set up the Initial Frame */ - PKUINIT_FRAME InitFrame; - InitFrame = (PKUINIT_FRAME)((ULONG_PTR)Thread->InitialStack - - sizeof(KUINIT_FRAME)); - - /* Copy over the context we got */ - RtlCopyMemory(&LocalContext, ContextPointer, sizeof(CONTEXT)); - Context = &LocalContext; - ContextFlags = CONTEXT_CONTROL; - - /* Zero out the trap frame and save area */ - RtlZeroMemory(&InitFrame->TrapFrame, - KTRAP_FRAME_LENGTH); - - /* Setup the Fx Area */ - //FxSaveArea = &InitFrame->FxSaveArea; - -// /* Get the FX Save Format Area */ -// FxSaveFormat = (PFXSAVE_FORMAT)Context->ExtendedRegisters; -// -// /* Set an initial state */ -// FxSaveFormat->ControlWord = 0x27F; -// FxSaveFormat->StatusWord = 0; -// FxSaveFormat->TagWord = 0; -// FxSaveFormat->ErrorOffset = 0; -// FxSaveFormat->ErrorSelector = 0; -// FxSaveFormat->DataOffset = 0; -// FxSaveFormat->DataSelector = 0; -// FxSaveFormat->MXCsr = 0x1F80; - - /* Set an intial NPX State */ - //Context->FloatSave.Cr0NpxState = 0; - //FxSaveArea->Cr0NpxState = 0; - //FxSaveArea->NpxSavedCpu = 0; - - /* Now set the context flags depending on XMM support */ - //ContextFlags |= (KeI386FxsrPresent) ? CONTEXT_EXTENDED_REGISTERS : - // CONTEXT_FLOATING_POINT; + InitFrame = ((PKUINIT_FRAME)Thread->InitialStack) - 1; + StartFrame = &InitFrame->StartFrame; + CtxSwitchFrame = &InitFrame->CtxSwitchFrame; + + /* Save back the new value of the kernel stack. */ + Thread->KernelStack = (PVOID)InitFrame; + + /* Tell the thread it will run in User Mode */ + Thread->PreviousMode = UserMode; + + // FIXME Setup the Fx Area
/* Set the Thread's NPX State */ Thread->NpxState = 0xA; Thread->Header.NpxIrql = PASSIVE_LEVEL;
- /* Disable any debug regiseters */ - Context->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS; + /* Make sure, we have control registers, disable debug registers */ + ASSERT((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL); + ContextFlags = Context->ContextFlags & ~CONTEXT_DEBUG_REGISTERS;
/* Setup the Trap Frame */ TrapFrame = &InitFrame->TrapFrame; + + /* Zero out the trap frame */ + RtlZeroMemory(TrapFrame, sizeof(KTRAP_FRAME));
/* Set up a trap frame from the context. */ KeContextToTrapFrame(Context, NULL, TrapFrame, - Context->ContextFlags | ContextFlags, + CONTEXT_AMD64 | ContextFlags, UserMode);
/* Set SS, DS, ES's RPL Mask properly */ @@ -117,62 +97,111 @@ /* Terminate the Exception Handler List */ TrapFrame->ExceptionFrame = 0;
- /* Setup the Stack for KiThreadStartup and Context Switching */ + /* We return to ... */ + StartFrame->Return = (ULONG64)KiServiceExit2; + } + else + { + PKKINIT_FRAME InitFrame; + + /* Set up the Initial Frame for the system thread */ + InitFrame = ((PKKINIT_FRAME)Thread->InitialStack) - 1; StartFrame = &InitFrame->StartFrame; CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
- /* Tell the thread it will run in User Mode */ - Thread->PreviousMode = UserMode; - - /* Tell KiThreadStartup of that too */ -// StartFrame->UserThread = TRUE; - } - else - { - /* Set up the Initial Frame for the system thread */ - PKKINIT_FRAME InitFrame; - InitFrame = (PKKINIT_FRAME)((ULONG_PTR)Thread->InitialStack - - sizeof(KKINIT_FRAME)); - - /* Setup the Fx Area */ - //FxSaveArea = &InitFrame->FxSaveArea; - //RtlZeroMemory(FxSaveArea, sizeof(FX_SAVE_AREA)); - - /* Check if we have Fxsr support */ - DPRINT1("FxsrPresent but did nothing\n"); -// /* Set the stub FX area */ -// FxSaveArea->U.FxArea.ControlWord = 0x27F; -// FxSaveArea->U.FxArea.MXCsr = 0x1F80; + /* Save back the new value of the kernel stack. */ + Thread->KernelStack = (PVOID)InitFrame; + + /* Tell the thread it will run in Kernel Mode */ + Thread->PreviousMode = KernelMode; + + // FIXME Setup the Fx Area
/* No NPX State */ Thread->NpxState = 0xA;
- /* Setup the Stack for KiThreadStartup and Context Switching */ - StartFrame = &InitFrame->StartFrame; - CtxSwitchFrame = &InitFrame->CtxSwitchFrame; - - /* Tell the thread it will run in Kernel Mode */ - Thread->PreviousMode = KernelMode; - - /* Tell KiThreadStartup of that too */ -// StartFrame->UserThread = FALSE; - } - - /* Now setup the remaining data for KiThreadStartup */ -// StartFrame->StartContext = StartContext; -// StartFrame->StartRoutine = StartRoutine; -// StartFrame->SystemRoutine = SystemRoutine; - - /* And set up the Context Switch Frame */ -// CtxSwitchFrame->RetAddr = KiThreadStartup; -// CtxSwitchFrame->ApcBypassDisable = TRUE; -// CtxSwitchFrame->ExceptionList = EXCEPTION_CHAIN_END;; - - /* Save back the new value of the kernel stack. */ - Thread->KernelStack = (PVOID)CtxSwitchFrame; + /* We have no return address! */ + StartFrame->Return = 0; + } + + /* Set up the Context Switch Frame */ + CtxSwitchFrame->Return = (ULONG64)KiThreadStartup; + CtxSwitchFrame->ApcBypass = FALSE; + + StartFrame->P1Home = (ULONG64)StartRoutine; + StartFrame->P2Home = (ULONG64)StartContext; + StartFrame->P3Home = 0; + StartFrame->P4Home = (ULONG64)SystemRoutine; + StartFrame->P5Home = 0;
}
+BOOLEAN +KiSwapContextResume( + IN PKTHREAD NewThread, + IN PKTHREAD OldThread, + IN BOOLEAN ApcBypass) +{ + PKIPCR Pcr = (PKIPCR)KeGetPcr(); + PKPROCESS OldProcess, NewProcess; + + /* Setup ring 0 stack pointer */ + Pcr->TssBase->Rsp0 = (ULONG64)NewThread->InitialStack; // FIXME: NPX save area? + Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0; + + /* Now we are the new thread. Check if it's in a new process */ + OldProcess = OldThread->ApcState.Process; + NewProcess = NewThread->ApcState.Process; + if (OldProcess != NewProcess) + { + /* Switch address space and flush TLB */ + __writecr3(NewProcess->DirectoryTableBase[0]); + + /* Set new TSS fields */ + //Pcr->TssBase->IoMapBase = NewProcess->IopmOffset; + } + + /* Set TEB pointer and GS base */ + Pcr->NtTib.Self = (PVOID)NewThread->Teb; + if (NewThread->Teb) + { + /* This will switch the usermode gs */ + __writemsr(MSR_GS_SWAP, (ULONG64)NewThread->Teb); + } + + /* Increase context switch count */ + Pcr->ContextSwitches++; + NewThread->ContextSwitches++; + + /* DPCs shouldn't be active */ + if (Pcr->Prcb.DpcRoutineActive) + { + /* Crash the machine */ + KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC, + (ULONG_PTR)OldThread, + (ULONG_PTR)NewThread, + (ULONG_PTR)OldThread->InitialStack, + 0); + } + + /* Kernel APCs may be pending */ + if (NewThread->ApcState.KernelApcPending) + { + /* Are APCs enabled? */ + if (!NewThread->SpecialApcDisable) + { + /* Request APC delivery */ + if (!ApcBypass) + HalRequestSoftwareInterrupt(APC_LEVEL); + else + return TRUE; + } + } + + /* Return stating that no kernel APCs are pending*/ + return FALSE; +} + /* EOF */
Modified: trunk/reactos/ntoskrnl/ke/amd64/trap.S URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/amd64/trap.S?re... ============================================================================== --- trunk/reactos/ntoskrnl/ke/amd64/trap.S [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/ke/amd64/trap.S [iso-8859-1] Sat Feb 4 11:32:13 2012 @@ -20,7 +20,7 @@ EXTERN KiGeneralProtectionFaultHandler:PROC EXTERN KiXmmExceptionHandler:PROC EXTERN KiDeliverApc:PROC -EXTERN KiDispatchInterrupt:PROC +EXTERN KiDpcInterruptHandler:PROC
/* GLOBALS *******************************************************************/
@@ -56,15 +56,35 @@
ALIGN 8
-PUBLIC InterruptDispatchTable -InterruptDispatchTable: +MACRO(UnexpectedVectorStub, Vector) + /* This nop is to make the relative jmp address 4 bytes aligned and to + make the whole code 8 bytes long */ + nop + /* This is a push instruction with 8bit operand. Since the instruction + sign extends the value to 32 bits, we need to offset it */ +PUBLIC KxUnexpectedInterrupt&Vector +KxUnexpectedInterrupt&Vector: + push (Vector - 128) + jmp KiUnexpectedInterrupt +ENDM + +PUBLIC KiUnexpectedRange +KiUnexpectedRange: Vector = 0 REPEAT 256 - push Vector - jmp KiUnexpectedInterrupt - ALIGN 8 + UnexpectedVectorStub %Vector Vector = Vector+1 ENDR +PUBLIC KiUnexpectedRangeEnd +KiUnexpectedRangeEnd: + +PUBLIC KiInterruptDispatchTemplate +KiInterruptDispatchTemplate: + /* This instruction pushes the return address on the stack, which is the + address of the interrupt object's DispatchCode member, then jumps + to the address stored in the interrupt object's DispatchAddress member */ + call qword ptr KiInterruptDispatchTemplate[rip - KINTERRUPT_DispatchCode + KINTERRUPT_DispatchAddress] +
// rbp = TrapFrame, eax = ExceptionCode, edx = NumParams, r9,r10,r11 = params .PROC InternalDispatchException @@ -138,7 +158,7 @@ .ENDP
-/* SOFTWARE INTERRUPT SERVICES ***********************************************/ +/* CPU EXCEPTION HANDLERS ****************************************************/
PUBLIC KiDivideErrorFault FUNC KiDivideErrorFault @@ -195,6 +215,14 @@ /* Push pseudo error code */ EnterTrap TF_SAVE_ALL
+ /* Check if the frame was from kernelmode */ + test word ptr [rbp + KTRAP_FRAME_SegCs], 3 + jz KiBreakpointTrapKMode + + /* Enable interrupts for user-mode */ + sti + +KiBreakpointTrapKMode: /* Dispatch the exception */ DispatchException STATUS_BREAKPOINT, 3, 0, 0, 0
@@ -434,7 +462,7 @@
PageFaultReturn: /* Return */ - ExitTrap TF_SAVE_ALL + ExitTrap (TF_SAVE_ALL or TF_CHECKUSERAPC) ENDFUNC
@@ -494,6 +522,8 @@ ExitTrap TF_SAVE_ALL ENDFUNC
+ +/* SOFTWARE INTERRUPT SERVICES ***********************************************/
PUBLIC KiRaiseAssertion FUNC KiRaiseAssertion @@ -552,29 +582,43 @@ /* Disable interrupts */ cli
+ /* Lower IRQL back to PASSIVE */ + mov rax, PASSIVE_LEVEL + mov cr8, rax + /* Return */ ExitTrap (TF_VOLATILES or TF_IRQL) .ENDP
+EXTERN KiRetireDpcList:PROC +PUBLIC KiRetireDpcListInDpcStack +.PROC KiRetireDpcListInDpcStack + push rbp + .pushreg rbp + mov rbp, rsp + .setframe rbp, 0 + .endprolog + + /* Switch stack and call the function */ + mov rsp, rdx + sub rsp, 40 + call KiRetireDpcList + + /* Restore stack, cleanup and return */ + mov rsp, rbp + pop rbp + ret +.ENDP
PUBLIC KiDpcInterrupt .PROC KiDpcInterrupt /* No error code */ EnterTrap (TF_VOLATILES or TF_IRQL)
- /* Raise to DISPATCH_LEVEL */ - mov rax, DISPATCH_LEVEL - mov cr8, rax - - /* End the interrupt */ - mov dword ptr [APIC_EOI], 0 - /* Call the worker routine */ - sti - call KiDispatchInterrupt - cli - - /* Return */ + call KiDpcInterruptHandler + + /* Return, but don't send an EOI! */ ExitTrap (TF_VOLATILES or TF_IRQL) .ENDP
@@ -618,6 +662,253 @@ ExitTrap TF_SAVE_ALL ENDFUNC
+PUBLIC KiInterruptDispatch +FUNC KiInterruptDispatch + /* The error code is a pointer to the interrupt object's code */ + EnterTrap (TF_HAS_ERROR_CODE or TF_SAVE_ALL or TF_IRQL) + + /* Increase interrupt count */ + inc dword ptr gs:[PcInterruptCount]; + + /* Load the address of the interrupt object into rcx */ + mov rcx, [rbp + KTRAP_FRAME_ErrorCode] + + /* Substract offset of the DispatchCode member plus 6 for the call instruction */ + sub rcx, KINTERRUPT_DispatchCode + 6 + + /* Raise IRQL to SynchronizeIrql */ + movzx rax, byte ptr [rcx + KINTERRUPT_SynchronizeIrql] + mov cr8, rax + +#ifdef CONFIG_SMP + /* Acquire interrupt lock */ + mov r8, [rcx + KINTERRUPT_ActualLock] + + //KxAcquireSpinLock(Interrupt->ActualLock); +#endif + + /* Call the ISR */ + mov rdx, [rcx + KINTERRUPT_ServiceContext] + call qword ptr [rcx + KINTERRUPT_ServiceRoutine] + +#ifdef CONFIG_SMP + /* Release interrupt lock */ + //KxReleaseSpinLock(Interrupt->ActualLock); +#endif + + /* Go back to old irql */ + movzx rax, byte ptr [rbp + KTRAP_FRAME_PreviousIrql] + mov cr8, rax + + /* Return */ + ExitTrap (TF_SAVE_ALL or TF_SEND_EOI) +ENDFUNC + + +#define MAX_SYSCALL_PARAM_SIZE (16 * 8) +#define HOME_SIZE 6*8 +#define SYSCALL_ALLOCATION (MAX_SYSCALL_PARAM_SIZE + HOME_SIZE) + +EXTERN KiSystemCallHandler:PROC + +/*! \name KiSystemCallEntry64 + * + * \brief This is the entrypoint for syscalls from 64bit user mode + * + * \param rax - The system call number + * \param rcx - User mode return address, set by the syscall instruction + * \param rdx,r8,r9 - Parameters 2-4 to the service function + * \param r10 - Parameter 1 to the service function + * \param r11 - RFLAGS saved by the syscall instruction + *--*/ +PUBLIC KiSystemCallEntry64 +.PROC KiSystemCallEntry64 + + /* Old stack pointer is in rcx, lie and say we saved it in rbp */ + .setframe rbp, 0 + .endprolog + + /* Swap gs to kernel, so we can access the PCR */ + swapgs + + /* Save the user mode rsp in the PCR */ + mov gs:[PcUserRsp], rsp + + /* Get the kernel stack from the PCR */ + mov rsp, gs:[PcRspBase] + + /* Allocate a TRAP_FRAME and space for parameters */ + sub rsp, (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE + HOME_SIZE) +#if DBG + /* Save rbp and load it with the old stack pointer */ + mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + HOME_SIZE + KTRAP_FRAME_Rbp], rbp + mov rbp, gs:[PcUserRsp] +#endif + + /* Save important volatiles in the trap frame */ + mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rax], rax + mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx], rcx + mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R10], r10 + mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R11], r11 + + /* Set sane segments */ + mov ax, (KGDT64_R3_DATA or RPL_MASK) + mov ds, ax + mov es, ax + + /* Call the C-handler (will enable interrupts) */ + lea rcx, [rsp + SYSCALL_ALLOCATION] + call KiSystemCallHandler + + /* Deallocate the handlers home stack frame */ + add rsp, HOME_SIZE + + /* The return value is the address of the Nt-function */ + mov rcx, [rsp + 0] + mov rdx, [rsp + 8] + mov r8, [rsp + 16] + mov r9, [rsp + 24] + call rax + +#if DBG + /* Restore rbp */ + mov rbp, [rsp + SYSCALL_ALLOCATION + KTRAP_FRAME_Rbp] +#endif + + /* Disable interrupts for return */ + cli + + /* Restore old trap frame */ + mov rcx, gs:[PcCurrentThread] + mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame] + mov [rcx + KTHREAD_TrapFrame], rdx + + /* Prepare user mode return address (rcx) and eflags (r11) for sysret */ + mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx] + mov r11, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R11] + + /* Load user mode stack (It was copied to the trap frame) */ + mov rsp, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp] + + /* Swap gs back to user */ + swapgs + + /* return to user mode */ + .byte HEX(48) // REX prefix to return to long mode + sysret +.ENDP + + +PUBLIC KiSystemCallEntry32 +KiSystemCallEntry32: + swapgs + int 3 + + +PUBLIC KiZwSystemService +FUNC KiZwSystemService + push rbp + .pushreg rbp + sub rsp, KTRAP_FRAME_LENGTH + .allocstack KTRAP_FRAME_LENGTH + mov [rsp + KTRAP_FRAME_Rsi], rsi + .savereg rsi, KTRAP_FRAME_Rsi + mov [rsp + KTRAP_FRAME_Rdi], rdi + .savereg rdi, KTRAP_FRAME_Rdi + mov rbp, rsp + .setframe rbp, 0 + .endprolog + + /* Get current thread */ + mov r11, gs:[PcCurrentThread] + + /* Save the old trap frame in TrapFrame.Rdx */ + mov rdi, [r11 + KTHREAD_TrapFrame] + mov [rbp + KTRAP_FRAME_Rdx], rdi + + /* Set the new trap frame and previous mode */ + mov [r11 + ThTrapFrame], rbp + mov byte ptr [r11 + KTHREAD_PreviousMode], 0 + + /* allocate space for parameters */ + sub rsp, r10 + and rsp, HEX(0fffffffffffffff0) + + /* Save rcx */ + mov [rbp + KTRAP_FRAME_Rcx], rcx + + /* copy parameters to the new location */ + lea rsi, [rbp + KTRAP_FRAME_LENGTH + 16] + lea rdi, [rsp] + mov rcx, r10 + shr rcx, 3 + rep movsq + + /* Restore rcx */ + mov rcx, [rbp + KTRAP_FRAME_Rcx] + + /* Call the service function */ + call rax + + /* Restore the old trap frame */ + mov r11, gs:[PcCurrentThread] + mov rsi, [rsp + KTRAP_FRAME_Rdx] + mov [r11 + KTHREAD_TrapFrame], rsi + + /* Restore rdi and rsi */ + mov rsi, [rbp + KTRAP_FRAME_Rsi] + mov rdi, [rbp + KTRAP_FRAME_Rdi] + + /* Cleanup the stack and return */ + lea rsp, [rbp + KTRAP_FRAME_LENGTH] + pop rbp + ret + +ENDFUNC + + +KiExitToUserApc: + int 3 + +/*! + * VOID + * DECLSPEC_NORETURN + * KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status)); + */ +PUBLIC KiServiceExit +KiServiceExit: + mov [rcx + KTRAP_FRAME_Rax], rdx + mov rbp, rcx + mov rsp, rcx + + /* Return */ + //ExitTrap TF_SAVE_ALL + +/*! + * VOID + * DECLSPEC_NORETURN + * KiServiceExit2(IN PKTRAP_FRAME TrapFrame); + */ +PUBLIC KiServiceExit2 +.PROC KiServiceExit2 + .ENDPROLOG + + mov rbp, rcx + mov rsp, rcx + + /* Return */ + ExitTrap TF_SAVE_ALL +.ENDP + +PUBLIC KiInitializeSegments +KiInitializeSegments: + mov ax, KGDT64_R3_DATA or RPL_MASK + mov gs, ax + swapgs + mov gs, ax + ret + + #ifdef _MSC_VER #undef lgdt #undef lidt @@ -658,6 +949,11 @@ str word ptr [rcx] ret
+PUBLIC __swapgs +__swapgs: + swapgs + ret + #endif
END