Some work-in-progress improvements and rethought of system-level code...notable improvemnts till now are: -The KTHREAD alterted flag is now properly set to FALSE during APC delivery during traps, -More support for PKEXCEPTION_FRAME has been added for future PPC/IA64/etc compatibility -Context to/from TrapFrame functions have been greatly fixed to allow for edited frames, special cases, exceptions and also have the necessary support for supporting sanitation based on PreviousMode - KDBG now shows the proper CS/SS at all times, previous hack was removed. - Systemcall code was optimized a bit and the trap code was made a lot more generic so that in can be made into macros (it currently isn't, for debugging purposes). - V86 Mode trap frame bias has now been added to make trap code a lot more generic and shareable in the future. -More support and fixes for future Debugging capabilities have been added. - Random other scalability and stability code. This is still being worked on, syscall.S looks nasty for now (visually) Modified: trunk/reactos/lib/ntdll/ldr/startup.c Modified: trunk/reactos/lib/rtl/i386/exception.c Modified: trunk/reactos/ntoskrnl/ex/init.c Modified: trunk/reactos/ntoskrnl/include/internal/i386/ke.h Modified: trunk/reactos/ntoskrnl/include/internal/ke.h Modified: trunk/reactos/ntoskrnl/kd/wrappers/gdbstub.c Modified: trunk/reactos/ntoskrnl/kdbg/kdb.c Modified: trunk/reactos/ntoskrnl/kdbg/kdb_cli.c Modified: trunk/reactos/ntoskrnl/ke/apc.c Modified: trunk/reactos/ntoskrnl/ke/exception.c Modified: trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S Modified: trunk/reactos/ntoskrnl/ke/i386/exp.c Modified: trunk/reactos/ntoskrnl/ke/i386/fpu.c Modified: trunk/reactos/ntoskrnl/ke/i386/syscall.S Modified: trunk/reactos/ntoskrnl/ke/i386/thread.c Modified: trunk/reactos/ntoskrnl/ke/i386/trap.s Modified: trunk/reactos/ntoskrnl/mm/i386/pfault.c Modified: trunk/reactos/ntoskrnl/ps/debug.c _____
Modified: trunk/reactos/lib/ntdll/ldr/startup.c --- trunk/reactos/lib/ntdll/ldr/startup.c 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/lib/ntdll/ldr/startup.c 2005-09-13 19:33:49 UTC (rev 17838) @@ -256,13 +256,13 @@
SYSTEM_BASIC_INFORMATION SystemInformation; NTSTATUS Status;
- DPRINT("LdrpInit()\n"); + DPRINT1("LdrpInit()\n"); if (NtCurrentPeb()->Ldr == NULL || NtCurrentPeb()->Ldr->Initialized == FALSE) { Peb = (PPEB)(PEB_BASE); - DPRINT("Peb %x\n", Peb); + DPRINT1("Peb %x\n", Peb); ImageBase = Peb->ImageBaseAddress; - DPRINT("ImageBase %x\n", ImageBase); + DPRINT1("ImageBase %x\n", ImageBase); if (ImageBase <= (PVOID)0x1000) { DPRINT("ImageBase is null\n"); @@ -271,7 +271,7 @@
/* If MZ header exists */ PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase; - DPRINT("PEDosHeader %x\n", PEDosHeader); + DPRINT1("PEDosHeader %x\n", PEDosHeader);
if (PEDosHeader->e_magic != IMAGE_DOS_SIGNATURE || PEDosHeader->e_lfanew == 0L || @@ -294,10 +294,12 @@ NTHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)ImageBase + PEDosHeader->e_lfanew);
/* Get number of processors */ + DPRINT1("Here\n"); Status = ZwQuerySystemInformation(SystemBasicInformation, &SystemInformation,
sizeof(SYSTEM_BASIC_INFORMATION), NULL); + DPRINT1("Here2\n"); if (!NT_SUCCESS(Status)) { ZwTerminateProcess(NtCurrentProcess(), Status); _____
Modified: trunk/reactos/lib/rtl/i386/exception.c --- trunk/reactos/lib/rtl/i386/exception.c 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/lib/rtl/i386/exception.c 2005-09-13 19:33:49 UTC (rev 17838) @@ -165,7 +165,7 @@
}
/* Unhandled, return false */ - DPRINT1("FALSE:(\n"); + DPRINT1("FALSE\n"); return FALSE; }
_____
Modified: trunk/reactos/ntoskrnl/ex/init.c --- trunk/reactos/ntoskrnl/ex/init.c 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/ex/init.c 2005-09-13 19:33:49 UTC (rev 17838) @@ -241,7 +241,6 @@
ASSERT(FIELD_OFFSET(KPROCESS, DirectoryTableBase) == KPROCESS_DIRECTORY_TABLE_BASE); ASSERT(FIELD_OFFSET(KPROCESS, IopmOffset) == KPROCESS_IOPM_OFFSET); ASSERT(FIELD_OFFSET(KPROCESS, LdtDescriptor) == KPROCESS_LDT_DESCRIPTOR0); - ASSERT(FIELD_OFFSET(KTRAP_FRAME, Reserved9) == KTRAP_FRAME_RESERVED9); ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, SavedExceptionStack) == TF_SAVED_EXCEPTION_STACK); ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, regs) == TF_REGS); ASSERT(FIELD_OFFSET(KV86M_TRAP_FRAME, orig_ebp) == TF_ORIG_EBP); _____
Modified: trunk/reactos/ntoskrnl/include/internal/i386/ke.h --- trunk/reactos/ntoskrnl/include/internal/i386/ke.h 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/include/internal/i386/ke.h 2005-09-13 19:33:49 UTC (rev 17838) @@ -40,11 +40,15 @@
#define X86_EXT_FEATURE_SSE3 0x00000001 /* SSE3 extension present */ #define X86_EXT_FEATURE_3DNOW 0x40000000 /* 3DNOW! extension present */
+#define DR7_ACTIVE 0x00000055 /* If any of these bits are set, a Dr is active */ + /* Possible values for KTHREAD's NpxState */ #define NPX_STATE_INVALID 0x01 #define NPX_STATE_VALID 0x02 #define NPX_STATE_DIRTY 0x04
+#define FRAME_EDITED 0xFFF8 + #ifndef __ASM__
typedef struct _KIRQ_TRAPFRAME _____
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h --- trunk/reactos/ntoskrnl/include/internal/ke.h 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/include/internal/ke.h 2005-09-13 19:33:49 UTC (rev 17838) @@ -287,7 +287,10 @@
VOID FASTCALL KiWaitTest(PDISPATCHER_HEADER Object, KPRIORITY Increment);
PULONG KeGetStackTopThread(struct _ETHREAD* Thread); -BOOLEAN STDCALL KeContextToTrapFrame(PCONTEXT Context, PKEXCEPTION_FRAME ExeptionFrame, PKTRAP_FRAME TrapFrame); +BOOLEAN STDCALL KeContextToTrapFrame(PCONTEXT Context, + PKEXCEPTION_FRAME ExeptionFrame, + PKTRAP_FRAME TrapFrame, + KPROCESSOR_MODE PreviousMode); VOID STDCALL KiDeliverApc(KPROCESSOR_MODE PreviousMode, PVOID Reserved, PKTRAP_FRAME TrapFrame); @@ -368,9 +371,12 @@ PKTRAP_FRAME Tf, KPROCESSOR_MODE PreviousMode, BOOLEAN SearchFrames); -VOID KeTrapFrameToContext(PKTRAP_FRAME TrapFrame, - PCONTEXT Context); VOID +NTAPI +KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN OUT PCONTEXT Context); +VOID KeApplicationProcessorInit(VOID); VOID KePrepareForApplicationProcessorInit(ULONG id); _____
Modified: trunk/reactos/ntoskrnl/kd/wrappers/gdbstub.c --- trunk/reactos/ntoskrnl/kd/wrappers/gdbstub.c 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/kd/wrappers/gdbstub.c 2005-09-13 19:33:49 UTC (rev 17838) @@ -1321,7 +1321,7 @@
#error Unknown compiler for inline assembler #endif
- KeContextToTrapFrame(Context, NULL, TrapFrame); + KeContextToTrapFrame(Context, NULL, TrapFrame, KernelMode); return ((SigVal == 5) ? (kdContinue) : (kdHandleException)); break; } @@ -1430,11 +1430,11 @@
TrapFrame = PsGetCurrentThread()->Tcb.TrapFrame;
- KeTrapFrameToContext (TrapFrame, &Context); + KeTrapFrameToContext (TrapFrame, NULL, &Context);
KdpGdbEnterDebuggerException (NULL, &Context, TrapFrame);
- KeContextToTrapFrame (&Context, NULL, TrapFrame); + KeContextToTrapFrame (&Context, NULL, TrapFrame, KernelMode);
KeLowerIrql (OldIrql);
_____
Modified: trunk/reactos/ntoskrnl/kdbg/kdb.c --- trunk/reactos/ntoskrnl/kdbg/kdb.c 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/kdbg/kdb.c 2005-09-13 19:33:49 UTC (rev 17838) @@ -15,10 +15,6 @@
/* TYPES *********************************************************************/
-/* FIXME: NDK headers */ -#define TempEsp TempEip -#define TempSegSs TempCs - /* DEFINES *******************************************************************/
#define KDB_STACK_SIZE (4096*3) @@ -108,6 +104,24 @@ "SIMD Fault" };
+ULONG +NTAPI +KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame); + +ULONG +NTAPI +KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame); + +VOID +NTAPI +KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame, + IN ULONG Ss); + +VOID +NTAPI +KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame, + IN ULONG Esp); + /* FUNCTIONS *****************************************************************/
STATIC VOID @@ -124,22 +138,11 @@ "movl %%cr4, %3" "\n\t" : "=r"(KdbTrapFrame->Cr0), "=r"(KdbTrapFrame->Cr2), "=r"(KdbTrapFrame->Cr3), "=r"(KdbTrapFrame->Cr4)); - - if (TrapFrame->PreviousMode == KernelMode) - { - /* If the trapframe is a kmode one use the temp ss:esp */ - KdbTrapFrame->Tf.Esp = (ULONG)TrapFrame->TempEsp; - KdbTrapFrame->Tf.Ss = (USHORT)((ULONG)TrapFrame->TempSegSs & 0xFFFF); - } - else - { - /* Otherwise use ss:esp pushed by the CPU */ - /* FIXME: maybe change all trapframes to always put ss:esp into tempss:tempesp so we - * can handle umode and kmode the same way */ - KdbTrapFrame->Tf.Esp = TrapFrame->Esp; - KdbTrapFrame->Tf.Ss = TrapFrame->Ss; - } - + + KdbTrapFrame->Tf.Esp = KiEspFromTrapFrame(TrapFrame); + KdbTrapFrame->Tf.Ss = (USHORT)(KiSsFromTrapFrame(TrapFrame) & 0xFFFF); + + /* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */ }
@@ -151,20 +154,8 @@
/* FIXME: write cr0, cr2, cr3 and cr4 (not needed atm) */
- if (TrapFrame->PreviousMode == KernelMode) - { - /* If the trapframe is a kmode one write to the temp ss:esp */ - TrapFrame->TempEsp = (PVOID)KdbTrapFrame->Tf.Esp; - TrapFrame->TempSegSs = (PVOID)(((ULONG)TrapFrame->TempSegSs & ~0xffff) | KdbTrapFrame->Tf.Ss); - } - else - { - /* Otherwise write to ss:esp pushed by the CPU */ - /* FIXME: maybe change all trap-epilogs to always put temp ss:esp into ss:esp so we - * can handle umode and kmode the same way */ - TrapFrame->Esp = KdbTrapFrame->Tf.Esp; - TrapFrame->Ss = KdbTrapFrame->Tf.Ss; - } + KiSsToTrapFrame(TrapFrame, KdbTrapFrame->Tf.Ss); + KiEspToTrapFrame(TrapFrame, KdbTrapFrame->Tf.Esp);
/* FIXME: copy v86 registers if TrapFrame is a V86 trapframe */ } _____
Modified: trunk/reactos/ntoskrnl/kdbg/kdb_cli.c --- trunk/reactos/ntoskrnl/kdbg/kdb_cli.c 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/kdbg/kdb_cli.c 2005-09-13 19:33:49 UTC (rev 17838) @@ -35,10 +35,6 @@
/* DEFINES *******************************************************************/
-/* FIXME: NDK headers */ -#define TempEsp TempEip -#define TempSegSs TempCs - #define KEY_BS 8 #define KEY_ESC 27 #define KEY_DEL 127 _____
Modified: trunk/reactos/ntoskrnl/ke/apc.c --- trunk/reactos/ntoskrnl/ke/apc.c 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/ke/apc.c 2005-09-13 19:33:49 UTC (rev 17838) @@ -812,7 +812,7 @@
/* Save the full context */ Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; - KeTrapFrameToContext(TrapFrame, &Context); + KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
/* Protect with SEH */ _SEH_TRY _____
Modified: trunk/reactos/ntoskrnl/ke/exception.c --- trunk/reactos/ntoskrnl/ke/exception.c 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/ke/exception.c 2005-09-13 19:33:49 UTC (rev 17838) @@ -28,7 +28,7 @@
Context = &LocalContext;
/* Convert the context into Exception/Trap Frames */ - KeContextToTrapFrame(&LocalContext, ExceptionFrame, TrapFrame); + KeContextToTrapFrame(&LocalContext, ExceptionFrame, TrapFrame, UserMode); }
NTSTATUS @@ -62,7 +62,7 @@ else { /* Convert the context into Exception/Trap Frames */ - KeContextToTrapFrame(Context, ExceptionFrame, TrapFrame); + KeContextToTrapFrame(Context, ExceptionFrame, TrapFrame, KernelMode); } } _SEH_HANDLE @@ -142,7 +142,7 @@ if (NT_SUCCESS(Status)) { /* Convert the context record */ - KeContextToTrapFrame(Context, ExceptionFrame, TrapFrame); + KeContextToTrapFrame(Context, ExceptionFrame, TrapFrame, PreviousMode);
/* Dispatch the exception */ KiDispatchException(ExceptionRecord, _____
Modified: trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S --- trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S 2005-09-13 19:33:49 UTC (rev 17838) @@ -114,7 +114,7 @@
.globl @KiSwapContextInternal@0 @KiSwapContextInternal@0: #ifdef KDBG - jmp SaveTrapFrameForKDB + //jmp SaveTrapFrameForKDB SaveTrapFrameForKDB_Return: #endif
@@ -130,12 +130,14 @@ /* Switching, disable interrupts now */ cli
+ /* Save the initial stack in EAX */ + mov eax, [edi+KTHREAD_INITIAL_STACK] + #ifdef CONFIG_SMP /* Save FPU state if the thread has used it. */ mov dword ptr [ebx+KPCR_NPX_THREAD], 0 test byte ptr [edi+KTHREAD_NPX_STATE], NPX_STATE_DIRTY jz 3f - mov eax, [edi+KTHREAD_INITIAL_STACK] cmp dword ptr _FxsrSupport, 0 je 1f fxsave [eax-SIZEOF_FX_SAVE_AREA] @@ -149,8 +151,18 @@
/* Save the stack pointer in this processors TSS */ mov ebp, [ebx+KPCR_TSS] + + /* Check if this isn't V86 Mode, so we can bias the Esp0 */ + test dword ptr [eax - KTRAP_FRAME_SIZE + KTRAP_FRAME_EFLAGS], X86_EFLAGS_VM + jnz NoAdjust + + /* Bias esp */ + //sub dword ptr ss:[ebp+KTSS_ESP0], KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS + +NoAdjust: + /* Push ESP0 Value */ push ss:[ebp+KTSS_ESP0] - + /* Check if address space switch is needed */ mov eax, [esi+KTHREAD_APCSTATE_PROCESS] cmp eax, [edi+KTHREAD_APCSTATE_PROCESS] _____
Modified: trunk/reactos/ntoskrnl/ke/i386/exp.c --- trunk/reactos/ntoskrnl/ke/i386/exp.c 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/ke/i386/exp.c 2005-09-13 19:33:49 UTC (rev 17838) @@ -17,14 +17,18 @@
/* * FIXMES: + * - Put back VEH. * - Clean up file. - * - Add more exception frame support for non-i386 compatibility. + * - Sanitize some context fields. * - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord). * - Implement official stack trace functions (exported) and remove stuff here. * - Forward exceptions to user-mode debugger. - * - Wrap Ki NTDLL callbacks in SEH. */
+VOID +NTAPI +Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame); + /* GLOBALS *****************************************************************/
#define FLAG_IF (1<<9) @@ -485,14 +489,14 @@ ASSERT(ExceptionNr != 14);
/* Store the exception number in an unused field in the trap frame. */ - Tf->DebugArgMark = (PVOID)ExceptionNr; + Tf->DebugArgMark = ExceptionNr;
/* Use the address of the trap frame as approximation to the ring0 esp */ Esp0 = (ULONG)&Tf->Eip;
/* Get CR2 */ cr2 = Ke386GetCr2(); - Tf->DebugPointer = (PVOID)cr2; + Tf->DebugPointer = cr2;
/* * If this was a V86 mode exception then handle it specially @@ -566,21 +570,172 @@ } }
+ULONG +NTAPI +KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame) +{ + /* Check if this is user-mode or V86 */ + if ((TrapFrame->Cs & 1) || (TrapFrame->Eflags & X86_EFLAGS_VM)) + { + /* Return it directly */ + return TrapFrame->Esp; + } + else + { + /* Edited frame */ + if (!(TrapFrame->Cs & FRAME_EDITED)) + { + /* Return edited value */ + return TrapFrame->TempEsp; + } + else + { + /* Virgin frame, calculate */ + return (ULONG)&TrapFrame->Esp; + } + } +} + +VOID +NTAPI +KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame, + IN ULONG Esp) +{ + ULONG Previous = KiEspFromTrapFrame(TrapFrame); + + /* Check if this is user-mode or V86 */ + if ((TrapFrame->Cs & 1) || (TrapFrame->Eflags & X86_EFLAGS_VM)) + { + /* Write it directly */ + TrapFrame->Esp = Esp; + } + else + { + /* Don't allow ESP to be lowered, this is illegal */ + if (Esp < Previous) + { + //KeBugCheck(SET_OF_INVALID_CONTEXT); + } + + /* Create an edit frame, check if it was alrady */ + if (!(TrapFrame->Cs & FRAME_EDITED)) + { + /* Update the value */ + TrapFrame->TempEsp = Esp; + } + else + { + /* Check if ESP changed */ + if (Previous != Esp) + { + /* Save CS */ + TrapFrame->TempCs = TrapFrame->Cs; + TrapFrame->Cs &= ~FRAME_EDITED; + + /* Save ESP */ + TrapFrame->TempEsp = Esp; + } + } + } +} + +ULONG +NTAPI +KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame) +{ + /* If this was V86 Mode */ + if (TrapFrame->Eflags & X86_EFLAGS_VM) + { + /* Just return it */ + return TrapFrame->Ss; + } + else if (TrapFrame->Cs & 1) + { + /* Usermode, return the User SS */ + return TrapFrame->Ss | 3; + } + else + { + /* Kernel mode */ + return KERNEL_DS; + } +} + +VOID +NTAPI +KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame, + IN ULONG Ss) +{ + /* Remove the high-bits */ + Ss &= 0xFFFF; + + /* If this was V86 Mode */ + if (TrapFrame->Eflags & X86_EFLAGS_VM) + { + /* Just write it */ + TrapFrame->Ss = Ss; + } + else if (TrapFrame->Cs & 1) + { + /* Usermode, save the User SS */ + TrapFrame->Ss = Ss | 3; + } +} + BOOLEAN -STDCALL -KeContextToTrapFrame(PCONTEXT Context, - PKEXCEPTION_FRAME ExceptionFrame, - PKTRAP_FRAME TrapFrame) +NTAPI +KeContextToTrapFrame(IN PCONTEXT Context, + IN OUT PKEXCEPTION_FRAME ExceptionFrame, + IN OUT PKTRAP_FRAME TrapFrame, + IN KPROCESSOR_MODE PreviousMode) { + BOOLEAN V86Switch = FALSE; + /* Start with the basic Registers */ if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) { - TrapFrame->Esp = Context->Esp; - TrapFrame->Ss = Context->SegSs; - TrapFrame->Cs = Context->SegCs; - TrapFrame->Eip = Context->Eip; + /* Check if we went through a V86 switch */ + if ((Context->EFlags & X86_EFLAGS_VM) != + (TrapFrame->Eflags & X86_EFLAGS_VM)) + { + /* We did, remember this for later */ + V86Switch = TRUE; + } + + /* Copy EFLAGS. FIXME: Needs to be sanitized */ TrapFrame->Eflags = Context->EFlags; + + /* Copy EBP and EIP */ TrapFrame->Ebp = Context->Ebp; + TrapFrame->Eip = Context->Eip; + + /* Check if we were in V86 Mode */ + if (TrapFrame->Eflags & X86_EFLAGS_VM) + { + /* Simply copy the CS value */ + TrapFrame->Cs = Context->SegCs; + } + else + { + /* We weren't in V86, so sanitize the CS (FIXME!) */ + TrapFrame->Cs = Context->SegCs; + + /* Don't let it under 8, that's invalid */ + if ((PreviousMode !=KernelMode) && (TrapFrame->Cs < 8)) + { + /* Force it to User CS */ + TrapFrame->Cs = USER_CS; + } + } + + /* Handle SS Specially for validation */ + KiSsToTrapFrame(TrapFrame, Context->SegSs); + + /* Write ESP back; take into account Edited Trap Frames */ + KiEspToTrapFrame(TrapFrame, Context->Esp); + + /* Handle our V86 Bias if we went through a switch */ + if (V86Switch) Ki386AdjustEsp0(TrapFrame); }
/* Process the Integer Registers */ @@ -597,21 +752,62 @@ /* Process the Context Segments */ if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) { - TrapFrame->Ds = Context->SegDs; - TrapFrame->Es = Context->SegEs; - TrapFrame->Fs = Context->SegFs; - TrapFrame->Gs = Context->SegGs; + /* Check if we were in V86 Mode */ + if (TrapFrame->Eflags & X86_EFLAGS_VM) + { + /* Copy the V86 Segments directlry */ + TrapFrame->V86_Ds = Context->SegDs; + TrapFrame->V86_Es = Context->SegEs; + TrapFrame->V86_Fs = Context->SegFs; + TrapFrame->V86_Gs = Context->SegGs; + } + else if (!(TrapFrame->Cs & 1)) + { + /* For user mode, write the values directly */ + TrapFrame->Ds = USER_DS; + TrapFrame->Es = USER_DS; + TrapFrame->Fs = Context->SegFs; + KEBUGCHECK(0); + TrapFrame->Gs = 0; + } + else + { + /* For kernel-mode, return the values */ + TrapFrame->Ds = Context->SegDs; + TrapFrame->Es = Context->SegEs; + TrapFrame->Fs = Context->SegFs; + + /* Handle GS specially */ + if (TrapFrame->Cs == USER_CS) + { + /* Don't use it, if user */ + TrapFrame->Gs = 0; + } + else + { + /* Copy it if kernel */ + TrapFrame->Gs = Context->SegGs; + } + } }
/* Handle the Debug Registers */ if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) { + /* FIXME: All these should be sanitized */ TrapFrame->Dr0 = Context->Dr0; TrapFrame->Dr1 = Context->Dr1; TrapFrame->Dr2 = Context->Dr2; TrapFrame->Dr3 = Context->Dr3; TrapFrame->Dr6 = Context->Dr6; TrapFrame->Dr7 = Context->Dr7; + + /* Check if usermode */ + if (PreviousMode != KernelMode) + { + /* Set the Debug Flag */ + KeGetCurrentThread()->DebugActive = (Context->Dr7 & DR7_ACTIVE); + } }
/* Handle FPU and Extended Registers */ @@ -619,51 +815,90 @@ }
VOID -KeTrapFrameToContext(PKTRAP_FRAME TrapFrame, - PCONTEXT Context) +NTAPI +KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame, + IN PKEXCEPTION_FRAME ExceptionFrame, + IN OUT PCONTEXT Context) { - if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) - { - Context->SegSs = TrapFrame->Ss; - Context->Esp = TrapFrame->Esp; - Context->SegCs = TrapFrame->Cs; - Context->Eip = TrapFrame->Eip; - Context->EFlags = TrapFrame->Eflags; - Context->Ebp = TrapFrame->Ebp; - } - if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) - { - Context->Eax = TrapFrame->Eax; - Context->Ebx = TrapFrame->Ebx; - Context->Ecx = TrapFrame->Ecx; - /* - * NOTE: In the trap frame which is built on entry to a system - * call TrapFrame->Edx will actually hold the address of the - * previous TrapFrame. I don't believe leaking this information - * has security implications. Also EDX holds the address of the - * arguments to the system call in progress so it isn't of much - * interest to the debugger. - */ - Context->Edx = TrapFrame->Edx; - Context->Esi = TrapFrame->Esi; - Context->Edi = TrapFrame->Edi; - } - if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) - { - Context->SegDs = TrapFrame->Ds; - Context->SegEs = TrapFrame->Es; - Context->SegFs = TrapFrame->Fs; - Context->SegGs = TrapFrame->Gs; - } + /* Start with the Control flags */ + if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) + { + /* EBP, EIP and EFLAGS */ + Context->Ebp = TrapFrame->Ebp; + Context->Eip = TrapFrame->Eip; + Context->EFlags = TrapFrame->Eflags; + + /* Return the correct CS */ + if (!(TrapFrame->Cs & FRAME_EDITED) && + !(TrapFrame->Eflags & X86_EFLAGS_VM)) + { + /* Get it from the Temp location */ + Context->SegCs = TrapFrame->TempCs & 0xFFFF; + } + else + { + /* Return it directly */ + Context->SegCs = TrapFrame->Cs & 0xFFFF; + } + + /* Get the Ss and ESP */ + Context->SegSs = KiSsFromTrapFrame(TrapFrame); + Context->Esp = KiEspFromTrapFrame(TrapFrame); + } + + /* Handle the Segments */ + if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) + { + /* Do V86 Mode first */ + if (TrapFrame->Eflags & X86_EFLAGS_VM) + { + /* Return from the V86 location */ + Context->SegGs = TrapFrame->V86_Gs & 0xFFFF; + Context->SegFs = TrapFrame->V86_Fs & 0xFFFF; + Context->SegEs = TrapFrame->V86_Es & 0xFFFF; + Context->SegDs = TrapFrame->V86_Ds & 0xFFFF; + } + else + { + /* Check if this was a Kernel Trap */ + if (TrapFrame->Cs == KERNEL_CS) + { + /* Set valid selectors */ + TrapFrame->Gs = 0; + TrapFrame->Fs = PCR_SELECTOR; + TrapFrame->Es = USER_DS; + TrapFrame->Ds = USER_DS; + } + + /* Return the segments */ + Context->SegGs = TrapFrame->Gs & 0xFFFF; + Context->SegFs = TrapFrame->Fs & 0xFFFF; + Context->SegEs = TrapFrame->Es & 0xFFFF; + Context->SegDs = TrapFrame->Ds & 0xFFFF; + } + } + + /* Handle the simple registers */ + if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) + { + /* Return them directly */ + Context->Eax = TrapFrame->Eax; + Context->Ebx = TrapFrame->Ebx; + Context->Ecx = TrapFrame->Ecx; + Context->Edx = TrapFrame->Edx; + Context->Esi = TrapFrame->Esi; + Context->Edi = TrapFrame->Edi; + } + if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) - { + { /* * FIXME: Implement this case */ Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386; } if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) - { + { /* * FIXME: Implement this case * @@ -676,7 +911,7 @@ } #if 0 if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS) - { + { /* * FIXME: Investigate this * @@ -931,7 +1166,7 @@ ULONG_PTR Stack, NewStack; ULONG Size; BOOLEAN UserDispatch = FALSE; - DPRINT1("KiDispatchException() called\n"); + DPRINT("KiDispatchException() called\n");
/* Increase number of Exception Dispatches */ KeGetCurrentPrcb()->KeExceptionDispatchCount++; @@ -947,7 +1182,7 @@ }
/* Get a Context */ - KeTrapFrameToContext(TrapFrame, &Context); + KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
/* Handle kernel-mode first, it's simpler */ if (PreviousMode == KernelMode) @@ -1017,7 +1252,7 @@ /* Align context size and get stack pointer */ Size = (sizeof(CONTEXT) + 3) & ~3; Stack = (Context.Esp & ~3) - Size; - DPRINT1("Stack: %lx\n", Stack); + DPRINT("Stack: %lx\n", Stack);
/* Probe stack and copy Context */ ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG)); @@ -1028,7 +1263,7 @@ (EXCEPTION_MAXIMUM_PARAMETERS - ExceptionRecord->NumberParameters) * sizeof(ULONG) + 3) & ~3; NewStack = Stack - Size; - DPRINT1("NewStack: %lx\n", NewStack); + DPRINT("NewStack: %lx\n", NewStack);
/* Probe stack and copy exception record. Don't forget to add the two params */ ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)), @@ -1041,7 +1276,7 @@ *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
/* Set new Stack Pointer */ - TrapFrame->Esp = NewStack - 2 * sizeof(ULONG_PTR); + KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
/* Set EIP to the User-mode Dispathcer */ TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher; @@ -1073,7 +1308,7 @@
Handled: /* Convert the context back into Trap/Exception Frames */ - KeContextToTrapFrame(&Context, NULL, TrapFrame); + KeContextToTrapFrame(&Context, NULL, TrapFrame, PreviousMode); return; }
_____
Modified: trunk/reactos/ntoskrnl/ke/i386/fpu.c --- trunk/reactos/ntoskrnl/ke/i386/fpu.c 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/ke/i386/fpu.c 2005-09-13 19:33:49 UTC (rev 17838) @@ -528,7 +528,7 @@
/* Fill the rest of the context */ Context->ContextFlags = CONTEXT_FULL; - KeTrapFrameToContext(Tf, Context); + KeTrapFrameToContext(Tf, NULL, Context); Context->ContextFlags |= CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS;
/* Determine exception code */ _____
Modified: trunk/reactos/ntoskrnl/ke/i386/syscall.S --- trunk/reactos/ntoskrnl/ke/i386/syscall.S 2005-09-13 19:11:37 UTC (rev 17837) +++ trunk/reactos/ntoskrnl/ke/i386/syscall.S 2005-09-13 19:33:49 UTC (rev 17838) @@ -1,13 +1,8 @@
-/* $Id$ - * +/* * FILE: ntoskrnl/ke/i386/syscall.S * COPYRIGHT: See COPYING in the top level directory * PURPOSE: System Call Handler * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - * UPDATE HISTORY: - * ??-??-??: Original Version - David Welch(?) - * 13-01-05: Complete rewrite, added support for SYSENTER, direct kmode syscalls - * and re-wrote most of handler code. - Alex Ionescu */
#include <roscfg.h> @@ -16,275 +11,491 @@ #include <ndk/i386/segment.h>
#define UserMode (1) +#define STATUS_INVALID_SYSTEM_SERVICE 0xC000001C
-.globl KeReturnFromSystemCallWithHook .globl _KiServiceExit .globl _KiServiceExit2 .globl _KiFastCallEntry .globl _KiSystemService .globl _KiDebugService +.intel_syntax noprefix
+/* + * NOTE: I will create some macros for trap entry and exit, + * DR* register restoration, modified frame exit, etc, if GAS + * allows it/I find a way how. This would remove a lot of + * duplicated code in this file plus the other irq/trap asm files. + * I think this is similar to what NT does, if you look at teh + * Dr_kit*_a functions which look auto-generated. + */ + +/* + * There are 3 main types of Trap Exits: + * + * - KiServiceExit + * - Clear interrupt flag + * - Common User APC Dispatching + * - Common exit code; segments and volatiles are not restored + * You use this for System Call return, when volatiles are irrelevant. + * (NtContinue, NtRaiseException, KiCallUserMode and all System Call returns) + * + * - KiServiceExit2 + * - Clear interrupt flag + * - Common User APC Dispatching + * - Common exit code; the entire frame is restored. + * You use this when volatiles and other registers need to be restored. + * For example, if debugging is active (NtContinue, NtRaiseException). + * + * - Kei386EoiHelper + * - Clear interrupt flag + * - Common User APC Dispatching + * - Common exit code; the entire frame is restored but *NOT* the Previous Mode + * You use this in the same context as KiServiceExit2, but when the Previous Mode + * should be tampered with. Clearly, as its name suggests, this routine is mostly + * useful for End Of Interrupts. + * Note that this routine is EXPORTED. + * Note that this routine must called by a JMP, not a CALL. + */ + +/* + * The common exit code has 3 modes of operation: + * - Whether or not to restore segments + * - Whether or not to restore volatiles + * - Whether or not to restore the previous mode + * All these are exemplified by the 3 trap exits shown above + */ + +/* + * There is also common Debug Code present in the common exit code, which + * in turn calls common code to save the debug registers + */ + + /* + * FIXMEs: + * - Fix Win32k Callbacks so we can optimize stack usage. + * - Dig in trap code and see why we need to push/pop the segments, + * which -shouldn't- be needed on syscalls; one of the things + * missing for this to work is lazy loading in the GPF handler, + * but there are other things to consider. + * - Use macros and merge with trap.s nicely + */ + +/* + * Entries will be discussed later. + */ + + /*** This file is a mess; it is being worked on. Please contact Alex: + *** alex@relsoft.net if you want to make any changes to it before this + *** message goes away + */ + +/* FUNCTIONS ***************************************************************/ + +BadStack: + + /* Restore ESP0 stack */ + mov ecx, [fs:KPCR_TSS] + mov esp, ss:[ecx+KTSS_ESP0] + + /* FIXME: Generate Trap 6*/ + int 3 + _KiFastCallEntry:
+// ==================== UNIQUE SYSENTER STUB. DO NOT DUPLICATE ============// /* Set FS to PCR */ - movl $PCR_SELECTOR, %ecx - movw %cx, %fs + mov ecx, PCR_SELECTOR + mov fs, cx
+ /* Set DS/ES to Kernel Selector */ + mov ecx, KERNEL_DS + mov ds, cx + mov es, cx + /* Set the current stack to Kernel Stack */ - movl %fs:KPCR_TSS, %ecx - movl %ss:KTSS_ESP0(%ecx), %ecx - movl %ecx, %esp + mov ecx, [fs:KPCR_TSS] + mov esp, ss:[ecx+KTSS_ESP0] + /* + * ^^^^^ Normally we should be able to use KTHREAD.InitialStack - sizeof + * KTRAP_FRAME - sizeof(NPX_AREA) and that will give us exactly + * our esp (ie: ebp == esp by the way the system is organized). + * This didn't work until I added v86m trap frame bias, which was + * needed anways. It works NICELY until we hit a Win32K Callback, + * which also messes up a lea esp, [ebp+...] below. It seems the + * stack for callbacks isn't properly set up (it's missing sizeof + * KTRAP_FRAME), which is understandable since the whole code is + * messed up and smashes new stacks instead of using the kernel + * assigned one. + */
/* Set up a fake INT Stack. */ - pushl $USER_DS - pushl %edx /* Ring 3 SS:ESP */ - pushfl - orl $X86_EFLAGS_IF, (%esp) /* Re-enable IRQs in EFLAGS, to fake INT */ - pushl $USER_CS - pushl $KUSER_SHARED_SYSCALL_RET + push USER_DS + push edx /* Ring 3 SS:ESP */ + pushf /* Ring 3 EFLAGS */ + push 2 /* Ring 0 EFLAGS */ + add edx, 8 /* Skip user parameter list */ + popf /* Set our EFLAGS */ + or dword ptr [esp], X86_EFLAGS_IF /* Re-enable IRQs in EFLAGS, to fake INT */ + push USER_CS [truncated at 1000 lines; 1168 more skipped]