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?r…
==============================================================================
--- 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.…
==============================================================================
--- 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/ctxswitc…
==============================================================================
--- 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(a)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/interrup…
==============================================================================
--- 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(a)web.de)
+ * PROGRAMMERS: Timo Kreuzer (timo.kreuzer(a)reactos.org)
+ * Alex Ionescu (alex.ionescu(a)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?…
==============================================================================
--- 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.…
==============================================================================
--- 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(a)relsoft.net)
+ * PURPOSE: amd64 Thread Context Creation
+ * PROGRAMMER: Timo Kreuzer (timo.kreuzer(a)reactos.org)
+ * Alex Ionescu (alex(a)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?r…
==============================================================================
--- 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