From c0a3750d26f2a6a2b8b595178f6f923bbe7bcfca Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Fri, 29 Dec 2006 18:49:00 +0000 Subject: [PATCH] - Fix critical bugs in exception handling: Unwinding was completely broken, using the wrong SEH protector to detect collided unwinding. The correct protector itself also had a broken check. - Fix architectural bug in the entire TrapFrame<->Context conversion system and Ring Privilege Transitions (Inter-ring and intra-ring) which was lacking proper sanitation and validation of segments, flags and debug registers. Among other things, IOPL is now respected, CS is not KGDT_R0_CODE | RPL_MASK anymore, and the GPF code is now properly being called. This completely fixes exception handling being totally broken and crashing firefox installer, mirc, and other applications. - Rewrite the page fault handler base code in assembly instead of relying on a broken C routine. Detect VDM, V8086, detecting expected/normal fault in ExpInterlockedPopEntrySList and faults in the system handler code. Rewrite MmAccessFault to be the main function that calls out to other sub-fault functions, and use the same prototype as NT. - Fix the KGDT boot table to have proper granularity and big flags, and extend it to 256 entries. - Create proper thread context in RtlInitializeContext and cleanup Rtl Thread routines. - Remove all int3 and breakpoints from trap handlers, and replace them with a much better "UNHANDLED_PATH" macro which freezes the system, beeps, and displays a message with the line of code that's unhandled. This is to clearly tell the user that something is unhandled, instead of nesting infinite exceptions due to the int3. - Fix a bug in INT_PROLOG. - Sanitize EFLAGS and Code Segments in KeContextToTrapFrame and KeTrapFrameToContext. - Implement KiUpdateDr7 and KiRecordDr7 as well as DR_MASK and other DR-validation macros and functions to protect against DR-vulnerabilites as well as to properly account for each active hardware breakpoint in a per-thread fashion by using the dispatcher header. - Allow CR0_EM when running in a VDM. - Fix FPU/NPX Register handling in KeContextToTrapFrame and KeTrapFrameToContext, and also speed it up by manual copying instead of a memory move. - Properly give IOPL 3 to user-mode threads if they requested it. - Detect GPF during GPF. - Detect pagefault with a trap-frame spread over two or more pages and nested. - Properly sanitize and set correct trap frame in KiInitailizeUserApc. - Return STATUS_ACCESS_VIOLATION during page faults instead of STATUS_UNSUCESSFUL. - Fix assert in VdmSwapContext, as well as Code Selector check which was broken. - Fix delayed object deletion (ObDeferDeleteObject) and the Ob Repear Routine and list. - Update Kernel Fun. - BUGBUG: Temporaily hack VMWare to detection to always detect VMWare. svn path=/trunk/; revision=25238 --- reactos/base/setup/vmwinst/vmwinst.c | 8 +- reactos/dll/ntdll/def/ntdll.def | 1 + reactos/include/ndk/asm.h | 11 +- reactos/include/ndk/rtlfuncs.h | 6 +- reactos/lib/rtl/i386/except_asm.s | 4 +- reactos/lib/rtl/i386/exception.c | 26 +- reactos/lib/rtl/rtlp.h | 20 +- reactos/lib/rtl/thread.c | 239 ++++++-------- reactos/ntoskrnl/KrnlFun.c | 64 ++-- reactos/ntoskrnl/ex/i386/fastinterlck_asm.S | 9 +- .../ntoskrnl/include/internal/i386/asmmacro.S | 35 ++- reactos/ntoskrnl/include/internal/i386/ke.h | 4 - reactos/ntoskrnl/include/internal/ke.h | 2 + reactos/ntoskrnl/include/internal/ke_x.h | 80 +++++ reactos/ntoskrnl/include/internal/mm.h | 15 +- reactos/ntoskrnl/include/internal/ob.h | 5 +- reactos/ntoskrnl/ke/i386/cpu.c | 16 +- reactos/ntoskrnl/ke/i386/exp.c | 284 ++++++++++++++--- reactos/ntoskrnl/ke/i386/trap.s | 296 ++++++++++++++++-- reactos/ntoskrnl/ke/i386/usercall.c | 23 +- reactos/ntoskrnl/mm/i386/memsafe.s | 17 - reactos/ntoskrnl/mm/i386/pfault.c | 135 -------- reactos/ntoskrnl/mm/mdl.c | 4 +- reactos/ntoskrnl/mm/mm.c | 115 ++++--- reactos/ntoskrnl/ntoskrnl.rbuild | 2 - reactos/ntoskrnl/ob/oblife.c | 19 +- reactos/ntoskrnl/ob/obref.c | 42 +-- reactos/ntoskrnl/vdm/vdmexec.c | 6 +- 28 files changed, 943 insertions(+), 545 deletions(-) delete mode 100644 reactos/ntoskrnl/mm/i386/memsafe.s delete mode 100644 reactos/ntoskrnl/mm/i386/pfault.c diff --git a/reactos/base/setup/vmwinst/vmwinst.c b/reactos/base/setup/vmwinst/vmwinst.c index c68242cb928..1438f3ec7ab 100644 --- a/reactos/base/setup/vmwinst/vmwinst.c +++ b/reactos/base/setup/vmwinst/vmwinst.c @@ -68,7 +68,7 @@ LONG CALLBACK VectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) return EXCEPTION_CONTINUE_EXECUTION; } -static BOOL +BOOL DetectVMware(int *Version) { int magic, ver; @@ -1010,7 +1010,7 @@ WinMain(HINSTANCE hInstance, { PVOID ExceptionHandler; - int Version; + //int Version; WCHAR *lc; hAppInstance = hInstance; @@ -1024,9 +1024,9 @@ WinMain(HINSTANCE hInstance, return 1; } - if(!DetectVMware(&Version)) + //if(!DetectVMware(&Version)) { - return 1; + //return 1; } /* unregister the handler */ diff --git a/reactos/dll/ntdll/def/ntdll.def b/reactos/dll/ntdll/def/ntdll.def index 0c27f034a55..38a73be609f 100644 --- a/reactos/dll/ntdll/def/ntdll.def +++ b/reactos/dll/ntdll/def/ntdll.def @@ -67,6 +67,7 @@ NtAcceptConnectPort@24 NtAccessCheck@32 NtAccessCheckAndAuditAlarm@44 NtAddAtom@12 +NtAddBootEntry@8 NtAdjustGroupsToken@24 NtAdjustPrivilegesToken@24 NtAlertResumeThread@8 diff --git a/reactos/include/ndk/asm.h b/reactos/include/ndk/asm.h index 831fcf340af..20783db79fe 100644 --- a/reactos/include/ndk/asm.h +++ b/reactos/include/ndk/asm.h @@ -169,6 +169,7 @@ Author: #define KPCR_STALL_SCALE_FACTOR 0x4C #define KPCR_SET_MEMBER 0x48 #define KPCR_NUMBER 0x51 +#define KPCR_VDM_ALERT 0x54 #define KPCR_PRCB_DATA 0x120 #define KPCR_CURRENT_THREAD 0x124 #define KPCR_PRCB_NEXT_THREAD 0x128 @@ -473,9 +474,13 @@ Author: #endif // -// DR7 Values +// DR6 and 7 Masks // +#define DR6_LEGAL 0xE00F +#define DR7_LEGAL 0xFFFF0155 +#define DR7_ACTIVE 0x55 #define DR7_RESERVED_MASK 0xDC00 +#define DR7_OVERRIDE_MASK 0xF0000 // // Usermode callout frame definitions @@ -491,6 +496,10 @@ Author: // #ifdef __ASM__ #define STATUS_ACCESS_VIOLATION 0xC0000005 +#define STATUS_IN_PAGE_ERROR 0xC0000006 +#define STATUS_GUARD_PAGE_VIOLATION 0x80000001 +#define STATUS_STACK_OVERFLOW 0xC00000FD +#define KI_EXCEPTION_ACCESS_VIOLATION 0x10000004 #define STATUS_INVALID_SYSTEM_SERVICE 0xC000001C #define STATUS_NO_CALLBACK_ACTIVE 0xC0000258 #define STATUS_CALLBACK_POP_STACK 0xC0000423 diff --git a/reactos/include/ndk/rtlfuncs.h b/reactos/include/ndk/rtlfuncs.h index 7c3d1002031..fcb8a08689c 100644 --- a/reactos/include/ndk/rtlfuncs.h +++ b/reactos/include/ndk/rtlfuncs.h @@ -1893,9 +1893,9 @@ RtlCreateUserThread( IN HANDLE ProcessHandle, IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN BOOLEAN CreateSuspended, - IN LONG StackZeroBits, - IN ULONG StackReserve, - IN ULONG StackCommit, + IN ULONG StackZeroBits, + IN SIZE_T StackReserve, + IN SIZE_T StackCommit, IN PTHREAD_START_ROUTINE StartAddress, IN PVOID Parameter, IN OUT PHANDLE ThreadHandle, diff --git a/reactos/lib/rtl/i386/except_asm.s b/reactos/lib/rtl/i386/except_asm.s index 0c0f0a7104f..ed20db17cc3 100644 --- a/reactos/lib/rtl/i386/except_asm.s +++ b/reactos/lib/rtl/i386/except_asm.s @@ -134,7 +134,7 @@ _RtlpExecuteHandlerForException@20: .globl _RtlpExecuteHandlerForUnwind@20 _RtlpExecuteHandlerForUnwind@20: /* Copy the routine in EDX */ - mov edx, offset _RtlpExceptionProtector + mov edx, offset _RtlpUnwindProtector .endfunc .func RtlpExecuteHandler@20 @@ -243,7 +243,7 @@ _RtlpUnwindProtector: /* Put the exception record in ECX and check the Flags */ mov ecx, [esp+4] test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND - jnz .return + jz .return /* Save the frame in ECX and Context in EDX */ mov ecx, [esp+8] diff --git a/reactos/lib/rtl/i386/exception.c b/reactos/lib/rtl/i386/exception.c index edfb835d811..227e4f1c239 100644 --- a/reactos/lib/rtl/i386/exception.c +++ b/reactos/lib/rtl/i386/exception.c @@ -10,30 +10,9 @@ /* INCLUDES *****************************************************************/ #include - #define NDEBUG #include -/* PRIVATE FUNCTIONS *********************************************************/ - -VOID -NTAPI -RtlpGetStackLimits(PULONG_PTR StackBase, - PULONG_PTR StackLimit); - -PEXCEPTION_REGISTRATION_RECORD -NTAPI -RtlpGetExceptionList(VOID); - -VOID -NTAPI -RtlpSetExceptionList(PEXCEPTION_REGISTRATION_RECORD NewExceptionList); - -typedef struct _DISPATCHER_CONTEXT -{ - PEXCEPTION_REGISTRATION_RECORD RegistrationPointer; -} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT; - /* PUBLIC FUNCTIONS **********************************************************/ /* @@ -100,7 +79,6 @@ RtlDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, sizeof(*RegistrationFrame)); /* Call the handler */ - DPRINT1("Calling handler: %p\n", RegistrationFrame->Handler); Disposition = RtlpExecuteHandlerForException(ExceptionRecord, RegistrationFrame, Context, @@ -192,7 +170,7 @@ RtlUnwind(IN PVOID TargetFrame OPTIONAL, IN PVOID ReturnValue) { PEXCEPTION_REGISTRATION_RECORD RegistrationFrame, OldFrame; - DISPATCHER_CONTEXT DispatcherContext; + DISPATCHER_CONTEXT DispatcherContext; EXCEPTION_RECORD ExceptionRecord2, ExceptionRecord3; EXCEPTION_DISPOSITION Disposition; ULONG_PTR StackLow, StackHigh; @@ -306,7 +284,7 @@ RtlUnwind(IN PVOID TargetFrame OPTIONAL, &DispatcherContext, RegistrationFrame-> Handler); - switch (Disposition) + switch(Disposition) { /* Continue searching */ case ExceptionContinueSearch: diff --git a/reactos/lib/rtl/rtlp.h b/reactos/lib/rtl/rtlp.h index c45d298fbaa..17b3597016f 100644 --- a/reactos/lib/rtl/rtlp.h +++ b/reactos/lib/rtl/rtlp.h @@ -16,6 +16,24 @@ extern VOID FASTCALL CHECK_PAGED_CODE_RTL(char *file, int line); #define PAGED_CODE_RTL() #endif +VOID +NTAPI +RtlpGetStackLimits(PULONG_PTR StackBase, + PULONG_PTR StackLimit); + +PEXCEPTION_REGISTRATION_RECORD +NTAPI +RtlpGetExceptionList(VOID); + +VOID +NTAPI +RtlpSetExceptionList(PEXCEPTION_REGISTRATION_RECORD NewExceptionList); + +typedef struct _DISPATCHER_CONTEXT +{ + PEXCEPTION_REGISTRATION_RECORD RegistrationPointer; +} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT; + /* These provide support for sharing code between User and Kernel RTL */ PVOID NTAPI @@ -112,7 +130,7 @@ RtlpCaptureContext(OUT PCONTEXT ContextRecord); NTSTATUS NTAPI DebugService(IN ULONG Service, - IN PCVOID Buffer, + IN const void* Buffer, IN ULONG Length, IN PVOID Argument1, IN PVOID Argument2); diff --git a/reactos/lib/rtl/thread.c b/reactos/lib/rtl/thread.c index 4df102553b2..55dae05113c 100644 --- a/reactos/lib/rtl/thread.c +++ b/reactos/lib/rtl/thread.c @@ -3,7 +3,7 @@ * PROJECT: ReactOS system libraries * PURPOSE: Rtl user thread functions * FILE: lib/rtl/thread.c - * PROGRAMERS: + * PROGRAMERS: * Alex Ionescu (alex@relsoft.net) * Eric Kohl * KJK::Hyperion @@ -21,60 +21,54 @@ NTSTATUS NTAPI -RtlpCreateUserStack(HANDLE hProcess, - ULONG StackReserve, - ULONG StackCommit, - ULONG StackZeroBits, - PINITIAL_TEB InitialTeb) +RtlpCreateUserStack(IN HANDLE hProcess, + IN SIZE_T StackReserve OPTIONAL, + IN SIZE_T StackCommit OPTIONAL, + IN ULONG StackZeroBits OPTIONAL, + OUT PINITIAL_TEB InitialTeb) { NTSTATUS Status; SYSTEM_BASIC_INFORMATION SystemBasicInfo; PIMAGE_NT_HEADERS Headers; ULONG_PTR Stack = 0; BOOLEAN UseGuard = FALSE; - - DPRINT("RtlpCreateUserStack\n"); - + ULONG Dummy, GuardPageSize; + /* Get some memory information */ - Status = NtQuerySystemInformation(SystemBasicInformation, + Status = ZwQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SYSTEM_BASIC_INFORMATION), NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failure to query system info\n"); - return Status; - } - + if (!NT_SUCCESS(Status)) return Status; + /* Use the Image Settings if we are dealing with the current Process */ if (hProcess == NtCurrentProcess()) { /* Get the Image Headers */ Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); - DPRINT("Headers: %p\n", Headers); - + /* If we didn't get the parameters, find them ourselves */ - StackReserve = (StackReserve) ? - StackReserve : Headers->OptionalHeader.SizeOfStackReserve; - StackCommit = (StackCommit) ? - StackCommit : Headers->OptionalHeader.SizeOfStackCommit; + if (!StackReserve) StackReserve = Headers->OptionalHeader. + SizeOfStackReserve; + if (!StackCommit) StackCommit = Headers->OptionalHeader. + SizeOfStackCommit; } else { /* Use the System Settings if needed */ - StackReserve = (StackReserve) ? StackReserve : - SystemBasicInfo.AllocationGranularity; - StackCommit = (StackCommit) ? StackCommit : SystemBasicInfo.PageSize; + if (!StackReserve) StackReserve = SystemBasicInfo.AllocationGranularity; + if (!StackCommit) StackCommit = SystemBasicInfo.PageSize; } - + /* Align everything to Page Size */ StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity); StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize); - #if 1 // FIXME: Remove once Guard Page support is here + + // FIXME: Remove once Guard Page support is here + #if 1 StackCommit = StackReserve; #endif - DPRINT("StackReserve: %lx, StackCommit: %lx\n", StackReserve, StackCommit); - + /* Reserve memory for the stack */ Status = ZwAllocateVirtualMemory(hProcess, (PVOID*)&Stack, @@ -82,33 +76,26 @@ RtlpCreateUserStack(HANDLE hProcess, &StackReserve, MEM_RESERVE, PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failure to reserve stack\n"); - return Status; - } - + if (!NT_SUCCESS(Status)) return Status; + /* Now set up some basic Initial TEB Parameters */ InitialTeb->PreviousStackBase = NULL; InitialTeb->PreviousStackLimit = NULL; InitialTeb->AllocatedStackBase = (PVOID)Stack; InitialTeb->StackBase = (PVOID)(Stack + StackReserve); - + /* Update the Stack Position */ Stack += StackReserve - StackCommit; - + /* Check if we will need a guard page */ if (StackReserve > StackCommit) { + /* Remove a page to set as guard page */ Stack -= SystemBasicInfo.PageSize; StackCommit += SystemBasicInfo.PageSize; UseGuard = TRUE; } - - DPRINT("AllocatedBase: %p, StackBase: %p, Stack: %lx, StackCommit: %lx\n", - InitialTeb->AllocatedStackBase, InitialTeb->StackBase, Stack, - StackCommit); - + /* Allocate memory for the stack */ Status = ZwAllocateVirtualMemory(hProcess, (PVOID*)&Stack, @@ -116,75 +103,68 @@ RtlpCreateUserStack(HANDLE hProcess, &StackCommit, MEM_COMMIT, PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failure to allocate stack\n"); - return Status; - } - + if (!NT_SUCCESS(Status)) return Status; + /* Now set the current Stack Limit */ InitialTeb->StackLimit = (PVOID)Stack; - DPRINT("StackLimit: %lx\n", Stack); - + /* Create a guard page */ if (UseGuard) { - ULONG GuardPageSize = SystemBasicInfo.PageSize; - ULONG Dummy; - - /* Attempt maximum space possible */ + /* Attempt maximum space possible */ + GuardPageSize = SystemBasicInfo.PageSize; Status = ZwProtectVirtualMemory(hProcess, (PVOID*)&Stack, &GuardPageSize, PAGE_GUARD | PAGE_READWRITE, &Dummy); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failure to create guard page\n"); - return Status; - } - + if (!NT_SUCCESS(Status)) return Status; + /* Update the Stack Limit keeping in mind the Guard Page */ InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit - GuardPageSize); - DPRINT1("StackLimit: %lx\n", Stack); } - + /* We are done! */ - return Status; + return STATUS_SUCCESS; } NTSTATUS NTAPI -RtlpFreeUserStack(HANDLE hProcess, - PINITIAL_TEB InitialTeb) +RtlpFreeUserStack(IN HANDLE Process, + IN PINITIAL_TEB InitialTeb) { ULONG Dummy = 0; - + NTSTATUS Status; + /* Free the Stack */ - return ZwFreeVirtualMemory(hProcess, - &InitialTeb->AllocatedStackBase, - &Dummy, - MEM_RELEASE); + Status = ZwFreeVirtualMemory(Process, + &InitialTeb->AllocatedStackBase, + &Dummy, + MEM_RELEASE); + + /* Clear the initial TEB */ + RtlZeroMemory(InitialTeb, sizeof(INITIAL_TEB)); + return Status; } - + /* FUNCTIONS ***************************************************************/ /* @implemented */ -NTSTATUS -NTAPI -RtlCreateUserThread(HANDLE ProcessHandle, - PSECURITY_DESCRIPTOR SecurityDescriptor, - BOOLEAN CreateSuspended, - LONG StackZeroBits, - ULONG StackReserve, - ULONG StackCommit, - PTHREAD_START_ROUTINE StartAddress, - PVOID Parameter, - PHANDLE ThreadHandle, - PCLIENT_ID ClientId) +NTSTATUS +NTAPI +RtlCreateUserThread(IN HANDLE ProcessHandle, + IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, + IN BOOLEAN CreateSuspended, + IN ULONG StackZeroBits OPTIONAL, + IN SIZE_T StackReserve OPTIONAL, + IN SIZE_T StackCommit OPTIONAL, + IN PTHREAD_START_ROUTINE StartAddress, + IN PVOID Parameter OPTIONAL, + OUT PHANDLE ThreadHandle OPTIONAL, + OUT PCLIENT_ID ClientId OPTIONAL) { NTSTATUS Status; HANDLE Handle; @@ -192,37 +172,27 @@ RtlCreateUserThread(HANDLE ProcessHandle, INITIAL_TEB InitialTeb; OBJECT_ATTRIBUTES ObjectAttributes; CONTEXT Context; - - DPRINT("RtlCreateUserThread: (hProcess: %p, Suspended: %d," - "ZeroBits: %lx, StackReserve: %lx, StackCommit: %lx," - "StartAddress: %p, Parameter: %p)\n", ProcessHandle, - CreateSuspended, StackZeroBits, StackReserve, StackCommit, - StartAddress, Parameter); - + /* First, we'll create the Stack */ Status = RtlpCreateUserStack(ProcessHandle, StackReserve, StackCommit, StackZeroBits, &InitialTeb); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failure to create User Stack\n"); - return Status; - } - + if (!NT_SUCCESS(Status)) return Status; + /* Next, we'll set up the Initial Context */ RtlInitializeContext(ProcessHandle, &Context, Parameter, StartAddress, InitialTeb.StackBase); - + /* We are now ready to create the Kernel Thread Object */ - InitializeObjectAttributes(&ObjectAttributes, - NULL, - 0, - NULL, + InitializeObjectAttributes(&ObjectAttributes, + NULL, + 0, + NULL, SecurityDescriptor); Status = ZwCreateThread(&Handle, THREAD_ALL_ACCESS, @@ -234,18 +204,16 @@ RtlCreateUserThread(HANDLE ProcessHandle, CreateSuspended); if (!NT_SUCCESS(Status)) { - DPRINT1("Failure to create Thread\n"); - /* Free the stack */ RtlpFreeUserStack(ProcessHandle, &InitialTeb); } else { - DPRINT("Thread created: %p\n", Handle); + /* Return thread data */ if (ThreadHandle) *ThreadHandle = Handle; if (ClientId) *ClientId = ThreadCid; } - + /* Return success or the previous failure */ return Status; } @@ -262,10 +230,7 @@ RtlInitializeContext(IN HANDLE ProcessHandle, IN PTHREAD_START_ROUTINE ThreadStartAddress, IN PINITIAL_TEB InitialTeb) { - DPRINT("RtlInitializeContext: (hProcess: %p, ThreadContext: %p, Teb: %p\n", - ProcessHandle, ThreadContext, InitialTeb); - - /* + /* * Set the Initial Registers * This is based on NT's default values -- crazy apps might expect this... */ @@ -276,27 +241,27 @@ RtlInitializeContext(IN HANDLE ProcessHandle, ThreadContext->Edx = 3; ThreadContext->Esi = 4; ThreadContext->Edi = 5; - + /* Set the Selectors */ ThreadContext->SegGs = 0; - ThreadContext->SegFs = KGDT_R3_TEB | RPL_MASK; - ThreadContext->SegEs = KGDT_R3_DATA | RPL_MASK; - ThreadContext->SegDs = KGDT_R3_DATA | RPL_MASK; - ThreadContext->SegCs = KGDT_R3_CODE | RPL_MASK; - ThreadContext->SegSs = KGDT_R3_DATA | RPL_MASK; - + ThreadContext->SegFs = KGDT_R3_TEB; + ThreadContext->SegEs = KGDT_R3_DATA; + ThreadContext->SegDs = KGDT_R3_DATA; + ThreadContext->SegSs = KGDT_R3_DATA; + ThreadContext->SegCs = KGDT_R3_CODE; + /* Enable Interrupts */ - ThreadContext->EFlags = 0x200; /*X86_EFLAGS_IF */ - + ThreadContext->EFlags = EFLAGS_INTERRUPT_MASK; + /* Settings passed */ ThreadContext->Eip = (ULONG)ThreadStartAddress; ThreadContext->Esp = (ULONG)InitialTeb; - + /* Only the basic Context is initialized */ - ThreadContext->ContextFlags = CONTEXT_CONTROL | - CONTEXT_INTEGER | + ThreadContext->ContextFlags = CONTEXT_CONTROL | + CONTEXT_INTEGER | CONTEXT_SEGMENTS; - + /* Set up ESP to the right value */ ThreadContext->Esp -= sizeof(PVOID); ZwWriteVirtualMemory(ProcessHandle, @@ -304,7 +269,7 @@ RtlInitializeContext(IN HANDLE ProcessHandle, (PVOID)&ThreadStartParam, sizeof(PVOID), NULL); - + /* Push it down one more notch for RETEIP */ ThreadContext->Esp -= sizeof(PVOID); } @@ -312,13 +277,13 @@ RtlInitializeContext(IN HANDLE ProcessHandle, /* * @implemented */ -VOID -NTAPI +VOID +NTAPI RtlExitUserThread(NTSTATUS Status) { /* Call the Loader and tell him to notify the DLLs */ LdrShutdownThread(); - + /* Shut us down */ NtCurrentTeb()->FreeStackOnTermination = TRUE; NtTerminateThread(NtCurrentThread(), Status); @@ -327,8 +292,8 @@ RtlExitUserThread(NTSTATUS Status) /* @implemented */ -VOID -NTAPI +VOID +NTAPI RtlFreeUserThreadStack(HANDLE ProcessHandle, HANDLE ThreadHandle) { @@ -336,19 +301,15 @@ RtlFreeUserThreadStack(HANDLE ProcessHandle, THREAD_BASIC_INFORMATION ThreadBasicInfo; ULONG Dummy, Size = 0; PVOID StackLocation; - + /* Query the Basic Info */ Status = NtQueryInformationThread(ThreadHandle, ThreadBasicInformation, &ThreadBasicInfo, sizeof(THREAD_BASIC_INFORMATION), NULL); - if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) - { - DPRINT1("Could not query info, or TEB is NULL\n"); - return; - } - + if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress) return; + /* Get the deallocation stack */ Status = NtReadVirtualMemory(ProcessHandle, &((PTEB)ThreadBasicInfo.TebBaseAddress)-> @@ -356,12 +317,8 @@ RtlFreeUserThreadStack(HANDLE ProcessHandle, &StackLocation, sizeof(PVOID), &Dummy); - if (!NT_SUCCESS(Status) || !StackLocation) - { - DPRINT1("Could not read Deallocation Base\n"); - return; - } - + if (!NT_SUCCESS(Status) || !StackLocation) return; + /* Free it */ NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE); } diff --git a/reactos/ntoskrnl/KrnlFun.c b/reactos/ntoskrnl/KrnlFun.c index 40543a4c39c..284e6529087 100644 --- a/reactos/ntoskrnl/KrnlFun.c +++ b/reactos/ntoskrnl/KrnlFun.c @@ -10,31 +10,32 @@ // // // Ob: -// - Fix bug related to Deferred Loading (don't requeue active work item). // - Add Directory Lock. +// - Strengthen code with debug checks and assertions. +// - Fix FIXMEs/commented out code. +// +// Ex: +// - Fixup existing code that talks to Ke. +// - Implement Generic Callback mechanism. +// - Use pushlocks for handle implementation. +// +// Lpc: +// - Figure out why NTLPC-processes won't die anymore. +// +// Ke1: +// - Implement KiInitMachineDependent. +// - Implement Privileged Instruction Handler in Umode GPF. // // Fstub: // - Implement IoAssignDriveLetters using mount manager support. // -// Ke: -// - Figure out why the DPC stack doesn't really work. -// - Fix SEH/Page Fault + Exceptions!? Weird exception bugs! +// Hal: +// - Use APC and DPC Interrupt Dispatchers. +// - CMOS Initialization and CMOS Spinlock. +// +// Ke2: // - New optimized table-based tick-hashed timer implementation. // - New Thread Scheduler based on 2003. -// - Implement KiCallbackReturn, KiGetTickCount, KiRaiseAssertion. -// -// Hal: -// - New IRQL Implementation. -// - CMOS Initialization and CMOS Spinlock. -// - Report resource usage to kernel (HalReportResourceUsage). -// -// Lpc: -// - Activate new NTLPC and delete old implementation. -// - Figure out why LPC-processes won't die anymore. -// -// Ex: -// - Implement Generic Callback mechanism. -// - Use pushlocks for handle implementation. // // Kd: // - Implement KD Kernel Debugging and WinDBG support. @@ -45,3 +46,30 @@ // /////////////////////////////////////////////////////////////////////////////// +// REACTOS GUIDANCE PLAN +// ________________________________________________________________________________________________________ +// / \ +// | OB, PS, LPC, DBGK, IO => Almost entirely fixed interaction with Ke/Ex. | | +// | SE => Not looked at. Interaction with Ps/Io is minimal and currently hacked away. Preserve. |J| +// | EX => Needs re-visiting (in trunk). Do callbacks/push locks for interaction with Ps. |A| +// | KD/KDBG => Laptop has special version of ROS without these components. Commit in branch. |N| +// | INIT => Boot sequence still needs work in terms of interaction with Ke and CPU features. | | +// | || || || || || || || || || || || || |F| +// | \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ |E| +// | HAL => Needs APC/DPC/IRQL implementation fixed ASAP in terms of interaction with Ke. |B| +// | FSTUB => Needs IoAssignDriveLetters fixed ASAP but not critical to Ke/Ex. Interacts with Io. | | +// | || || || || || || || || || || || || |M| +// | \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ |A| +// | CM => TOTAL REWRITE. |R| +// | || || || || || || || || || || || || | | +// | || || || || || || || || || || || || |A| +// | \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ |P| +// | KE => Timer Rewrite + Thread Scheduler Rewrite. |R| +// | || || || || || || || || || || || || |I| +// | || || || || || || || || || || || || |L| +// | || || || || || || || || || || || || | | +// | \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ |M| +// | MM => TOTAL REWRITE. |A| +// | |Y| +// \________________________________________________________________________________________________________/ +// diff --git a/reactos/ntoskrnl/ex/i386/fastinterlck_asm.S b/reactos/ntoskrnl/ex/i386/fastinterlck_asm.S index 3c263b13050..b223bb332cd 100644 --- a/reactos/ntoskrnl/ex/i386/fastinterlck_asm.S +++ b/reactos/ntoskrnl/ex/i386/fastinterlck_asm.S @@ -381,6 +381,9 @@ */ .global @ExInterlockedPopEntrySList@8 .global @InterlockedPopEntrySList@4 +.global _ExpInterlockedPopEntrySListResume@0 +.global _ExpInterlockedPopEntrySListFault@0 +.global _ExpInterlockedPopEntrySListEnd@0 @ExInterlockedPopEntrySList@8: @InterlockedPopEntrySList@4: @@ -392,10 +395,10 @@ mov ebp, ecx /* Get sequence number and link pointer */ +_ExpInterlockedPopEntrySListResume@0: mov edx, [ebp+4] mov eax, [ebp] -1: /* Check if the list is empty */ or eax, eax jz 2f @@ -404,9 +407,11 @@ lea ecx, [edx-1] /* Get next pointer and do the exchange */ +_ExpInterlockedPopEntrySListFault@0: mov ebx, [eax] +_ExpInterlockedPopEntrySListEnd@0: LOCK cmpxchg8b [ebp] - jnz 1b + jnz _ExpInterlockedPopEntrySListResume@0 /* Restore registers and return */ 2: diff --git a/reactos/ntoskrnl/include/internal/i386/asmmacro.S b/reactos/ntoskrnl/include/internal/i386/asmmacro.S index cb6d8093977..5c0511102ea 100644 --- a/reactos/ntoskrnl/include/internal/i386/asmmacro.S +++ b/reactos/ntoskrnl/include/internal/i386/asmmacro.S @@ -65,6 +65,30 @@ #define RELEASE_SPINLOCK(x) #endif +// +// @name UNHANDLED_PATH +// +// This macro TODO +// +// @param None +// +// @remark None. +// +.macro UNHANDLED_PATH + /* Get EIP */ + call $+5 + pop eax + + /* Print debug message */ + push eax + push offset _UnhandledMsg + call _DbgPrint + add esp, 8 + + /* Loop indefinitely */ + jmp $ +.endm + // // @name IDT // @@ -182,7 +206,6 @@ _KiUnexpectedInterrupt&Number: push offset V86DebugMsg call _DbgPrint add esp, 8 - int 3 jmp $ .endm @@ -511,7 +534,7 @@ _KiUnexpectedInterrupt&Number: /* Check if this was kernel mode */ 1: - cmp dword ptr [esp+KTRAP_FRAME_CS], KGDT_R0_CODE + cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R0_CODE jz 1f /* Set segments */ @@ -947,7 +970,7 @@ PendingUserApc: /* Assert the saved exception list */ or edx, edx jnz 1f - int 3 + UNHANDLED_PATH 1: #endif @@ -962,7 +985,7 @@ PendingUserApc: /* Assert the saved previous mode */ cmp ecx, -1 jnz 1f - int 3 + UNHANDLED_PATH 1: #endif @@ -976,7 +999,7 @@ PendingUserApc: mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE] cmp ecx, -1 jz 1f - int 3 + UNHANDLED_PATH 1: #endif .endif @@ -1111,7 +1134,7 @@ FastExit: add dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00 6: - int 3 + UNHANDLED_PATH jmp 5b #endif diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index bc8efa2e4f7..b13f133ddee 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -41,12 +41,8 @@ #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 */ - #define FRAME_EDITED 0xFFF8 -#define WE_DO_NOT_SPEAK_ABOUT_THE_V86_HACK 1 - #ifndef __ASM__ extern ULONG Ke386CacheAlignment; diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 7f44c7ba5d0..447c26aeec7 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -130,6 +130,8 @@ extern PVOID KeUserApcDispatcher; extern PVOID KeUserCallbackDispatcher; extern PVOID KeUserExceptionDispatcher; extern PVOID KeRaiseUserExceptionDispatcher; +extern UCHAR KiDebugRegisterTrapOffsets[9]; +extern UCHAR KiDebugRegisterContextOffsets[9]; /* MACROS *************************************************************************/ diff --git a/reactos/ntoskrnl/include/internal/ke_x.h b/reactos/ntoskrnl/include/internal/ke_x.h index a22cfa30488..99a8cd2ecc1 100644 --- a/reactos/ntoskrnl/include/internal/ke_x.h +++ b/reactos/ntoskrnl/include/internal/ke_x.h @@ -6,6 +6,86 @@ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */ +// +// Thread Dispatcher Header DebugActive Mask +// +#define DR_MASK(x) 1 << x +#define DR_ACTIVE_MASK 0x10 +#define DR_REG_MASK 0x4F + +// +// Sanitizes a selector +// +FORCEINLINE +ULONG +Ke386SanitizeSeg(IN ULONG Cs, + IN KPROCESSOR_MODE Mode) +{ + // + // Check if we're in kernel-mode, and force CPL 0 if so. + // Otherwise, force CPL 3. + // + return ((Mode == KernelMode) ? + (Cs & (0xFFFF & ~RPL_MASK)) : + (RPL_MASK | (Cs & 0xFFFF))); +} + +// +// Sanitizes EFLAGS +// +FORCEINLINE +ULONG +Ke386SanitizeFlags(IN ULONG Eflags, + IN KPROCESSOR_MODE Mode) +{ + // + // Check if we're in kernel-mode, and sanitize EFLAGS if so. + // Otherwise, also force interrupt mask on. + // + return ((Mode == KernelMode) ? + (Eflags & (EFLAGS_USER_SANITIZE | EFLAGS_INTERRUPT_MASK)) : + (EFLAGS_INTERRUPT_MASK | (Eflags & EFLAGS_USER_SANITIZE))); +} + +// +// Gets a DR register from a CONTEXT structure +// +FORCEINLINE +PVOID +KiDrFromContext(IN ULONG Dr, + IN PCONTEXT Context) +{ + return *(PVOID*)((ULONG_PTR)Context + KiDebugRegisterContextOffsets[Dr]); +} + +// +// Gets a DR register from a KTRAP_FRAME structure +// +FORCEINLINE +PVOID* +KiDrFromTrapFrame(IN ULONG Dr, + IN PKTRAP_FRAME TrapFrame) +{ + return (PVOID*)((ULONG_PTR)TrapFrame + KiDebugRegisterTrapOffsets[Dr]); +} + +// +// +// +FORCEINLINE +PVOID +Ke386SanitizeDr(IN PVOID DrAddress, + IN KPROCESSOR_MODE Mode) +{ + // + // Check if we're in kernel-mode, and return the address directly if so. + // Otherwise, make sure it's not inside the kernel-mode address space. + // If it is, then clear the address. + // + return ((Mode == KernelMode) ? DrAddress : + (DrAddress <= MM_HIGHEST_USER_ADDRESS) ? DrAddress : 0); +} + // // Enters a Guarded Region // diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index 768947c45be..e63bdec36cf 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -686,17 +686,10 @@ MmPageFault( NTSTATUS NTAPI MmAccessFault( - KPROCESSOR_MODE Mode, - ULONG_PTR Address, - BOOLEAN FromMdl -); - -NTSTATUS -NTAPI -MmNotPresentFault( - KPROCESSOR_MODE Mode, - ULONG_PTR Address, - BOOLEAN FromMdl + IN BOOLEAN StoreInstruction, + IN PVOID Address, + IN KPROCESSOR_MODE Mode, + IN PVOID TrapInformation ); /* anonmem.c *****************************************************************/ diff --git a/reactos/ntoskrnl/include/internal/ob.h b/reactos/ntoskrnl/include/internal/ob.h index c6fe3dffbab..2762164fc79 100644 --- a/reactos/ntoskrnl/include/internal/ob.h +++ b/reactos/ntoskrnl/include/internal/ob.h @@ -188,9 +188,10 @@ ObQueryDeviceMapInformation( // Object Lifetime Functions // VOID -FASTCALL +NTAPI ObpDeleteObject( - IN PVOID Object + IN PVOID Object, + IN BOOLEAN CalledFromWorkerThread ); LONG diff --git a/reactos/ntoskrnl/ke/i386/cpu.c b/reactos/ntoskrnl/ke/i386/cpu.c index 22eeb177ee9..b9e8cf1c0c9 100644 --- a/reactos/ntoskrnl/ke/i386/cpu.c +++ b/reactos/ntoskrnl/ke/i386/cpu.c @@ -29,17 +29,17 @@ UCHAR KiDoubleFaultTSS[KTSS_IO_MAPS]; /* The TSS to use for NMI Fault Traps (INT 0x2) */ UCHAR KiNMITSS[KTSS_IO_MAPS]; -/* The Boot GDT (FIXME: should have more entries */ -KGDTENTRY KiBootGdt[12] = +/* The Boot GDT */ +KGDTENTRY KiBootGdt[256] = { {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_NULL */ - {0xffff, 0x0000, {{0x00, 0x9a, 0xcf, 0x00}}}, /* KGDT_R0_CODE */ - {0xffff, 0x0000, {{0x00, 0x92, 0xcf, 0x00}}}, /* KGDT_R0_DATA */ - {0xffff, 0x0000, {{0x00, 0xfa, 0xcf, 0x00}}}, /* KGDT_R3_CODE */ - {0xffff, 0x0000, {{0x00, 0xf2, 0xcf, 0x00}}}, /* KGDT_R3_DATA*/ + {0xffff, 0x0000, {{0x00, 0x9b, 0xcf, 0x00}}}, /* KGDT_R0_CODE */ + {0xffff, 0x0000, {{0x00, 0x93, 0xcf, 0x00}}}, /* KGDT_R0_DATA */ + {0xffff, 0x0000, {{0x00, 0xfb, 0xcf, 0x00}}}, /* KGDT_R3_CODE */ + {0xffff, 0x0000, {{0x00, 0xf3, 0xcf, 0x00}}}, /* KGDT_R3_DATA*/ {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_TSS */ - {0x0fff, 0x0000, {{0x00, 0x92, 0x00, 0xff}}}, /* KGDT_R0_PCR */ - {0x0fff, 0x0000, {{0x00, 0xf2, 0x00, 0x00}}}, /* KGDT_R3_TEB */ + {0x0fff, 0x0000, {{0x00, 0x93, 0xc0, 0xff}}}, /* KGDT_R0_PCR */ + {0x0fff, 0x0000, {{0x00, 0xf3, 0x40, 0x00}}}, /* KGDT_R3_TEB */ {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_UNUSED */ {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_LDT */ {0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_DF_TSS */ diff --git a/reactos/ntoskrnl/ke/i386/exp.c b/reactos/ntoskrnl/ke/i386/exp.c index d7b54625967..8a33723c9b7 100644 --- a/reactos/ntoskrnl/ke/i386/exp.c +++ b/reactos/ntoskrnl/ke/i386/exp.c @@ -14,6 +14,36 @@ #define NDEBUG #include +/* GLOBALS *******************************************************************/ + +/* DR Registers in the CONTEXT structure */ +UCHAR KiDebugRegisterContextOffsets[9] = +{ + FIELD_OFFSET(CONTEXT, Dr0), + FIELD_OFFSET(CONTEXT, Dr1), + FIELD_OFFSET(CONTEXT, Dr2), + FIELD_OFFSET(CONTEXT, Dr3), + 0, + 0, + FIELD_OFFSET(CONTEXT, Dr6), + FIELD_OFFSET(CONTEXT, Dr7), + 0, +}; + +/* DR Registers in the KTRAP_FRAME structure */ +UCHAR KiDebugRegisterTrapOffsets[9] = +{ + FIELD_OFFSET(KTRAP_FRAME, Dr0), + FIELD_OFFSET(KTRAP_FRAME, Dr1), + FIELD_OFFSET(KTRAP_FRAME, Dr2), + FIELD_OFFSET(KTRAP_FRAME, Dr3), + 0, + 0, + FIELD_OFFSET(KTRAP_FRAME, Dr6), + FIELD_OFFSET(KTRAP_FRAME, Dr7), + 0, +}; + /* FUNCTIONS *****************************************************************/ _SEH_DEFINE_LOCALS(KiCopyInfo) @@ -53,6 +83,101 @@ KeInitExceptions(VOID) } } +ULONG +FASTCALL +KiUpdateDr7(IN ULONG Dr7) +{ + ULONG DebugMask = KeGetCurrentThread()->DispatcherHeader.DebugActive; + + /* Check if debugging is enabled */ + if (DebugMask & DR_ACTIVE_MASK) + { + /* Sanity checks */ + ASSERT((DebugMask & DR_REG_MASK) != 0); + ASSERT((Dr7 & ~DR7_RESERVED_MASK) == DR7_OVERRIDE_MASK); + return 0; + } + + /* Return DR7 itself */ + return Dr7; +} + +BOOLEAN +FASTCALL +KiRecordDr7(OUT PULONG Dr7Ptr, + OUT PULONG DrMask) +{ + ULONG NewMask, Mask; + UCHAR Result; + + /* Check if the caller gave us a mask */ + if (!DrMask) + { + /* He didn't use the one from the thread */ + Mask = KeGetCurrentThread()->DispatcherHeader.DebugActive; + } + else + { + /* He did, read it */ + Mask = *DrMask; + } + + /* Sanity check */ + ASSERT((*Dr7Ptr & DR7_RESERVED_MASK) == 0); + + /* Check if DR7 is empty */ + NewMask = Mask; + if (!(*Dr7Ptr)) + { + /* Assume failure */ + Result = FALSE; + + /* Check the DR mask */ + NewMask &= 0x7F; + if (NewMask & DR_REG_MASK) + { + /* Set the active mask */ + NewMask |= DR_ACTIVE_MASK; + + /* Set DR7 override */ + *DrMask = DR7_OVERRIDE_MASK; + } + else + { + /* Sanity check */ + ASSERT(NewMask == 0); + } + } + else + { + /* Check if we have a mask or not */ + Result = NewMask ? TRUE: FALSE; + + /* Update the mask to disable debugging */ + NewMask &= ~DR_ACTIVE_MASK; + NewMask |= 0x80; + } + + /* Check if caller wants the new mask */ + if (DrMask) + { + /* Update it */ + *DrMask = NewMask; + } + else + { + /* Check if the mask changed */ + if (Mask != NewMask) + { + /* Update it */ + KeGetCurrentThread()->DispatcherHeader.DebugActive = NewMask; + } + } + + /* Return the result */ + return Result; +} + ULONG NTAPI KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame) @@ -192,6 +317,8 @@ KeContextToTrapFrame(IN PCONTEXT Context, ULONG i; BOOLEAN V86Switch = FALSE; KIRQL OldIrql = APC_LEVEL; + ULONG DrMask = 0; + PVOID SafeDr; /* Do this at APC_LEVEL */ if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql); @@ -207,8 +334,8 @@ KeContextToTrapFrame(IN PCONTEXT Context, V86Switch = TRUE; } - /* Copy EFLAGS. FIXME: Needs to be sanitized */ - TrapFrame->EFlags = Context->EFlags; + /* Copy EFLAGS and sanitize them*/ + TrapFrame->EFlags = Ke386SanitizeFlags(Context->EFlags, PreviousMode); /* Copy EBP and EIP */ TrapFrame->Ebp = Context->Ebp; @@ -222,14 +349,14 @@ KeContextToTrapFrame(IN PCONTEXT Context, } else { - /* We weren't in V86, so sanitize the CS (FIXME!) */ - TrapFrame->SegCs = Context->SegCs; + /* We weren't in V86, so sanitize the CS */ + TrapFrame->SegCs = Ke386SanitizeSeg(Context->SegCs, PreviousMode); /* Don't let it under 8, that's invalid */ if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8)) { /* Force it to User CS */ - TrapFrame->SegCs = (KGDT_R3_CODE | RPL_MASK); + TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK; } } @@ -261,7 +388,7 @@ KeContextToTrapFrame(IN PCONTEXT Context, /* Check if we were in V86 Mode */ if (TrapFrame->EFlags & EFLAGS_V86_MASK) { - /* Copy the V86 Segments directlry */ + /* Copy the V86 Segments directly */ TrapFrame->V86Ds = Context->SegDs; TrapFrame->V86Es = Context->SegEs; TrapFrame->V86Fs = Context->SegFs; @@ -272,12 +399,12 @@ KeContextToTrapFrame(IN PCONTEXT Context, /* For kernel mode, write the standard values */ TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK; TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK; - TrapFrame->SegFs = Context->SegFs; + TrapFrame->SegFs = Ke386SanitizeSeg(Context->SegFs, PreviousMode); TrapFrame->SegGs = 0; } else { - /* For user mode, return the values directlry */ + /* For user mode, return the values directly */ TrapFrame->SegDs = Context->SegDs; TrapFrame->SegEs = Context->SegEs; TrapFrame->SegFs = Context->SegFs; @@ -320,7 +447,13 @@ KeContextToTrapFrame(IN PCONTEXT Context, /* Mask out any invalid flags */ FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS); - /* FIXME: Check if this is a VDM app */ + /* Check if this is a VDM app */ + if (PsGetCurrentProcess()->VdmObjects) + { + /* Allow the EM flag */ + FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState & + (CR0_EM | CR0_MP); + } } } @@ -373,16 +506,40 @@ KeContextToTrapFrame(IN PCONTEXT Context, } else { - /* Just dump the Fn state in */ - RtlCopyMemory(&FxSaveArea->U.FnArea, - &Context->FloatSave, - sizeof(FNSAVE_FORMAT)); + /* Copy the structure */ + FxSaveArea->U.FnArea.ControlWord = Context->FloatSave. + ControlWord; + FxSaveArea->U.FnArea.StatusWord = Context->FloatSave. + StatusWord; + FxSaveArea->U.FnArea.TagWord = Context->FloatSave.TagWord; + FxSaveArea->U.FnArea.ErrorOffset = Context->FloatSave. + ErrorOffset; + FxSaveArea->U.FnArea.ErrorSelector = Context->FloatSave. + ErrorSelector; + FxSaveArea->U.FnArea.DataOffset = Context->FloatSave. + DataOffset; + FxSaveArea->U.FnArea.DataSelector = Context->FloatSave. + DataSelector; + + /* Loop registers */ + for (i = 0; i < SIZE_OF_80387_REGISTERS; i++) + { + /* Copy registers */ + FxSaveArea->U.FnArea.RegisterArea[i] = + Context->FloatSave.RegisterArea[i]; + } } /* Mask out any invalid flags */ FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS); - /* FIXME: Check if this is a VDM app */ + /* Check if this is a VDM app */ + if (PsGetCurrentProcess()->VdmObjects) + { + /* Allow the EM flag */ + FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState & + (CR0_EM | CR0_MP); + } } else { @@ -394,23 +551,38 @@ KeContextToTrapFrame(IN PCONTEXT Context, /* Handle the Debug Registers */ if ((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; + /* Loop DR registers */ + for (i = 0; i < 4; i++) + { + /* Sanitize the context DR Address */ + SafeDr = Ke386SanitizeDr(KiDrFromContext(i, Context), PreviousMode); - /* Check if usermode */ + /* Save it in the trap frame */ + *KiDrFromTrapFrame(i, TrapFrame) = SafeDr; + + /* Check if this DR address is active and add it in the DR mask */ + if (SafeDr) DrMask |= DR_MASK(i); + } + + /* Now save and sanitize DR6 */ + TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL; + if (TrapFrame->Dr6) DrMask |= DR_MASK(6); + + /* Save and sanitize DR7 */ + TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL; + KiRecordDr7(&TrapFrame->Dr7, &DrMask); + + /* If we're in user-mode */ if (PreviousMode != KernelMode) { - /* Set the Debug Flag */ - KeGetCurrentThread()->DispatcherHeader.DebugActive = - (Context->Dr7 & DR7_ACTIVE) ? TRUE: FALSE; + /* FIXME: Save the mask */ + //KeGetCurrentThread()->DispatcherHeader.DebugActive = DrMask; } } + /* Check if thread has IOPL and force it enabled if so */ + if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= 0x3000; + /* Restore IRQL */ if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql); } @@ -429,6 +601,7 @@ KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame, } FloatSaveBuffer; FLOATING_SAVE_AREA *FloatSaveArea; KIRQL OldIrql = APC_LEVEL; + ULONG i; /* Do this at APC_LEVEL */ if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql); @@ -550,10 +723,23 @@ KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame, KiFlushNPXState(NULL); } - /* Copy into the Context */ - RtlCopyMemory(&Context->FloatSave, - FloatSaveArea, - sizeof(FNSAVE_FORMAT)); + /* Copy structure */ + Context->FloatSave.ControlWord = FloatSaveArea->ControlWord; + Context->FloatSave.StatusWord = FloatSaveArea->StatusWord; + Context->FloatSave.TagWord = FloatSaveArea->TagWord; + Context->FloatSave.ErrorOffset = FloatSaveArea->ErrorOffset; + Context->FloatSave.ErrorSelector = FloatSaveArea->ErrorSelector; + Context->FloatSave.DataOffset = FloatSaveArea->DataOffset; + Context->FloatSave.DataSelector = FloatSaveArea->DataSelector; + Context->FloatSave.Cr0NpxState = FxSaveArea->Cr0NpxState; + + /* Loop registers */ + for (i = 0; i < SIZE_OF_80387_REGISTERS; i++) + { + /* Copy them */ + Context->FloatSave.RegisterArea[i] = + FloatSaveArea->RegisterArea[i]; + } } else { @@ -566,24 +752,26 @@ KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame, if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) { - /* Copy the debug registers */ - Context->Dr0 = TrapFrame->Dr0; - Context->Dr1 = TrapFrame->Dr1; - Context->Dr2 = TrapFrame->Dr2; - Context->Dr3 = TrapFrame->Dr3; - Context->Dr6 = TrapFrame->Dr6; - - /* For user-mode, only set DR7 if a debugger is active */ - if (((TrapFrame->SegCs & MODE_MASK) || - (TrapFrame->EFlags & EFLAGS_V86_MASK)) && - (KeGetCurrentThread()->DispatcherHeader.DebugActive)) + /* Make sure DR7 is valid */ + if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK) { - /* Copy it over */ - Context->Dr7 = TrapFrame->Dr7; + /* Copy the debug registers */ + Context->Dr0 = TrapFrame->Dr0; + Context->Dr1 = TrapFrame->Dr1; + Context->Dr2 = TrapFrame->Dr2; + Context->Dr3 = TrapFrame->Dr3; + Context->Dr6 = TrapFrame->Dr6; + + /* Update DR7 */ + //Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7); } else { - /* Clear it */ + /* Otherwise clear DR registers */ + Context->Dr0 = + Context->Dr1 = + Context->Dr3 = + Context->Dr6 = Context->Dr7 = 0; } } @@ -757,13 +945,13 @@ DispatchToUser: KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR)); /* Force correct segments */ - TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK; - TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK; - TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK; - TrapFrame->SegFs = KGDT_R3_TEB | RPL_MASK; + TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, PreviousMode); + TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode); + TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode); + TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, PreviousMode); TrapFrame->SegGs = 0; - /* Set EIP to the User-mode Dispathcer */ + /* Set EIP to the User-mode Dispatcher */ TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher; _SEH_LEAVE; } diff --git a/reactos/ntoskrnl/ke/i386/trap.s b/reactos/ntoskrnl/ke/i386/trap.s index 8288c2cc170..074919b5c67 100644 --- a/reactos/ntoskrnl/ke/i386/trap.s +++ b/reactos/ntoskrnl/ke/i386/trap.s @@ -87,13 +87,17 @@ _KiUnexpectedEntrySize: _UnexpectedMsg: .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n" +_UnhandledMsg: + .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n" + /* SOFTWARE INTERRUPT SERVICES ***********************************************/ .text _KiGetTickCount: _KiCallbackReturn: _KiRaiseAssertion: - int 3 + /* FIXME: TODO */ + UNHANDLED_PATH .func KiSystemService Dr_kss: DR_TRAP_FIXUP @@ -144,6 +148,7 @@ SharedCode: /* Check if we should flush the User Batch */ xor ebx, ebx +ReadBatch: or ebx, [ecx+TEB_GDI_BATCH_COUNT] jz NotWin32K @@ -432,8 +437,8 @@ V86_Exit: iret AbiosExit: - /* Not yet supported */ - int 3 + /* FIXME: TODO */ + UNHANDLED_PATH .func KiDebugService Dr_kids: DR_TRAP_FIXUP @@ -672,6 +677,13 @@ _DispatchTwoParam: /* HARDWARE TRAP HANDLERS ****************************************************/ +.func KiFixupFrame +_KiFixupFrame: + + /* TODO: Routine to fixup a KTRAP_FRAME when faulting from a syscall. */ + UNHANDLED_PATH +.endfunc + .func KiTrap0 Dr_kit0: DR_TRAP_FIXUP V86_kit0: V86_TRAP_FIXUP @@ -710,7 +722,8 @@ VdmCheck: /* We don't support this yet! */ V86Int0: - int 3 + /* FIXME: TODO */ + UNHANDLED_PATH .endfunc .func KiTrap1 @@ -754,7 +767,7 @@ V86Int1: jz EnableInterrupts /* We don't support VDM! */ - int 3 + UNHANDLED_PATH .endfunc .globl _KiTrap2 @@ -813,7 +826,7 @@ V86Int3: jz EnableInterrupts3 /* We don't support VDM! */ - int 3 + UNHANDLED_PATH .endfunc .func KiTrap4 @@ -855,7 +868,7 @@ VdmCheck4: /* We don't support this yet! */ V86Int4: - int 3 + UNHANDLED_PATH .endfunc .func KiTrap5 @@ -901,7 +914,7 @@ VdmCheck5: /* We don't support this yet! */ V86Int5: - int 3 + UNHANDLED_PATH .endfunc .func KiTrap6 @@ -917,8 +930,7 @@ _KiTrap6: V86_TRAP_PROLOG kit6 /* Not yet supported (Invalid OPCODE from V86) */ - int 3 - jmp $ + UNHANDLED_PATH NotV86UD: /* Push error code */ @@ -993,8 +1005,7 @@ LockCrash: IsVdmOpcode: /* Unhandled yet */ - int 3 - jmp $ + UNHANDLED_PATH /* Return to caller */ jmp _Kei386EoiHelper@0 @@ -1302,8 +1313,7 @@ V86Npx: jz HandleUserNpx /* V86 NPX not handled */ - int 3 - jmp $ + UNHANDLED_PATH EmulationEnabled: /* Did this come from kernel-mode? */ @@ -1456,7 +1466,7 @@ RaiseIrql: jnz NoReflect /* FIXME: TODO */ - int 3 + UNHANDLED_PATH NoReflect: @@ -1485,9 +1495,21 @@ NotV86: test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK jnz UserModeGpf - /* FIXME: Check for GPF during GPF */ + /* Check if we have a VDM alert */ + cmp dword ptr fs:[KPCR_VDM_ALERT], 0 + jnz VdmAlertGpf + + /* Check for GPF during GPF */ + mov eax, [ebp+KTRAP_FRAME_EIP] + cmp eax, offset CheckPrivilegedInstruction + jbe KmodeGpf + cmp eax, offset CheckPrivilegedInstruction2 + + /* FIXME: TODO */ + UNHANDLED_PATH /* Get the opcode and trap frame */ +KmodeGpf: mov eax, [ebp+KTRAP_FRAME_EIP] mov eax, [eax] mov edx, [ebp+KTRAP_FRAME_EBP] @@ -1573,8 +1595,7 @@ TrapCopy: MsrCheck: /* FIXME: Handle RDMSR/WRMSR */ - int 3 - jmp $ + UNHANDLED_PATH NotIretGpf: @@ -1606,7 +1627,6 @@ SegPopGpf: lea eax, [ebp+KTRAP_FRAME_ESP] cmp edx, eax jz HandleSegPop - int 3 /* Handle segment POP fault by setting it to 0 */ HandleSegPop: @@ -1620,26 +1640,239 @@ ExitGpfTrap: UserModeGpf: - /* FIXME: Unhandled */ - int 3 - jmp $ + /* If the previous mode was kernel, raise a fatal exception */ + mov eax, 13 + test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK + jz _KiSystemFatalException + + /* Get the process and check which CS this came from */ + mov ebx, fs:[KPCR_CURRENT_THREAD] + mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS] + cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK + jz CheckVdmGpf + + /* Check if this is a VDM */ + cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0 + jnz DispatchV86Gpf + + /* Enable interrupts and check if we have an error code */ + sti + cmp word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0 + jnz SetException + jmp CheckPrivilegedInstruction + +HandleSegPop2: + /* Update EIP (will be updated below again) */ + add dword ptr [ebp+KTRAP_FRAME_EIP], 1 + +HandleBop4: + /* Clear the segment, update EIP and ESP */ + mov dword ptr [edx], 0 + add dword ptr [ebp+KTRAP_FRAME_EIP], 1 + add dword ptr [ebp+KTRAP_FRAME_ESP], 4 + jmp _Kei386EoiHelper@0 + +CheckVdmGpf: + /* Check if this is a VDM */ + cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0 + jz CheckPrivilegedInstruction + + /* Check what kind of instruction this is */ + mov eax, [ebp+KTRAP_FRAME_EIP] + mov eax, [eax] + + /* FIXME: Check for BOP4 */ + + /* Check if this is POP FS */ + mov edx, ebp + add edx, KTRAP_FRAME_FS + cmp ax, 0xA10F + jz HandleSegPop2 + + /* Check if this is POP GS */ + add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS + cmp ax, 0xA90F + jz HandleSegPop2 + +CheckPrivilegedInstruction: + /* FIXME */ + UNHANDLED_PATH + +CheckPrivilegedInstruction2: + /* FIXME */ + UNHANDLED_PATH + +SetException: + /* FIXME */ + UNHANDLED_PATH + +DispatchV86Gpf: + /* FIXME */ + UNHANDLED_PATH .endfunc .func KiTrap14 Dr_kit14: DR_TRAP_FIXUP V86_kit14: V86_TRAP_FIXUP _KiTrap14: + /* Enter trap */ TRAP_PROLOG kit14 - /* Call the C exception handler */ - push 14 - push ebp - call _KiPageFaultHandler - add esp, 8 + /* Check if we have a VDM alert */ + cmp dword ptr fs:[KPCR_VDM_ALERT], 0 + jnz VdmAlertGpf - /* Return to caller */ + /* Get the current thread */ + mov edi, fs:[KPCR_CURRENT_THREAD] + + /* Get the stack address of the frame */ + lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH] + sub eax, [edi+KTHREAD_INITIAL_STACK] + jz NoFixUp + + /* This isn't the base frame, check if it's the second */ + cmp eax, -KTRAP_FRAME_EFLAGS + jb NoFixUp + + /* Check if we have a TEB */ + mov eax, fs:[KPCR_TEB] + or eax, eax + jle NoFixUp + + /* Fixup the frame */ + call _KiFixupFrame + + /* Save CR2 */ +NoFixUp: + mov edi, cr2 + + /* ROS HACK: Sometimes we get called with INTS DISABLED! WTF? */ + test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK + je HandlePf + + /* Enable interrupts and check if we got here with interrupts disabled */ + sti + test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK + jz IllegalState + +HandlePf: + /* Send trap frame and check if this is kernel-mode or usermode */ + push ebp + mov eax, [ebp+KTRAP_FRAME_CS] + and eax, MODE_MASK + push eax + + /* Send faulting address and check if this is read or write */ + push edi + mov eax, [ebp+KTRAP_FRAME_ERROR_CODE] + and eax, 1 + push eax + + /* Call the access fault handler */ + call _MmAccessFault@16 + test eax, eax + jl AccessFail + + /* Access fault handled, return to caller */ jmp _Kei386EoiHelper@0 + +AccessFail: + /* First check if this is a fault in the S-LIST functions */ + mov ecx, offset _ExpInterlockedPopEntrySListFault@0 + cmp [ebp+KTRAP_FRAME_EIP], ecx + jz SlistFault + + /* Check if this is a fault in the syscall handler */ + mov ecx, offset CopyParams + cmp [ebp+KTRAP_FRAME_EIP], ecx + jz SysCallCopyFault + mov ecx, offset ReadBatch + cmp [ebp+KTRAP_FRAME_EIP], ecx + jnz CheckVdmPf + + /* FIXME: TODO */ + UNHANDLED_PATH + jmp _Kei386EoiHelper@0 + +SysCallCopyFault: + /* FIXME: TODO */ + UNHANDLED_PATH + jmp _Kei386EoiHelper@0 + + /* Check if the fault occured in a V86 mode */ +CheckVdmPf: + mov ecx, [ebp+KTRAP_FRAME_ERROR_CODE] + and ecx, 1 + shr ecx, 1 + test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK + jnz VdmPF + + /* Check if the fault occured in a VDM */ + mov esi, fs:[KPCR_CURRENT_THREAD] + mov esi, [esi+KTHREAD_APCSTATE_PROCESS] + cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0 + jz CheckStatus + + /* Check if we this was in kernel-mode */ + test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK + jz CheckStatus + cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK + jz CheckStatus + +VdmPF: + /* FIXME: TODO */ + UNHANDLED_PATH + + /* Save EIP and check what kind of status failure we got */ +CheckStatus: + mov esi, [ebp+KTRAP_FRAME_EIP] + cmp eax, STATUS_ACCESS_VIOLATION + je AccessViol + cmp eax, STATUS_GUARD_PAGE_VIOLATION + je SpecialCode + cmp eax, STATUS_STACK_OVERFLOW + je SpecialCode + + /* Setup an in-page exception to dispatch */ + mov edx, ecx + mov ebx, esi + mov esi, edi + mov ecx, 3 + mov edi, eax + mov eax, STATUS_IN_PAGE_ERROR + call _CommonDispatchException + +AccessViol: + /* Use more proper status code */ + mov eax, KI_EXCEPTION_ACCESS_VIOLATION + +SpecialCode: + /* Setup a normal page fault exception */ + mov ebx, esi + mov edx, ecx + mov esi, edi + jmp _DispatchTwoParam + +SlistFault: + /* FIXME: TODO */ + UNHANDLED_PATH + +IllegalState: + + /* This is completely illegal, bugcheck the system */ + push ebp + push esi + push ecx + push eax + push edi + push IRQL_NOT_LESS_OR_EQUAL + call _KeBugCheckWithTf@24 + +VdmAlertGpf: + + /* FIXME: NOT SUPPORTED */ + UNHANDLED_PATH .endfunc .func KiTrap0F @@ -1752,8 +1985,7 @@ _Ki16BitStackException: add esp, [eax+KTHREAD_INITIAL_STACK] /* Switch to good stack segment */ - /* TODO */ - int 3 + UNHANDLED_PATH .endfunc /* UNEXPECTED INTERRUPT HANDLERS **********************************************/ @@ -1867,7 +2099,7 @@ CheckQuantum: jz Return /* FIXME: Schedule new thread */ - int 3 + UNHANDLED_PATH Return: /* All done */ @@ -1904,7 +2136,7 @@ _KiInterruptTemplateDispatch: _KiChainedDispatch2ndLvl@0: /* Not yet supported */ - int 3 + UNHANDLED_PATH .endfunc .func KiChainedDispatch@0 diff --git a/reactos/ntoskrnl/ke/i386/usercall.c b/reactos/ntoskrnl/ke/i386/usercall.c index 8c56ddb886e..d70d3e24e18 100644 --- a/reactos/ntoskrnl/ke/i386/usercall.c +++ b/reactos/ntoskrnl/ke/i386/usercall.c @@ -71,7 +71,7 @@ KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame, _SEH_DECLARE_LOCALS(KiCopyInfo); /* Don't deliver APCs in V86 mode */ - if (TrapFrame->EFlags & X86_EFLAGS_VM) return; + if (TrapFrame->EFlags & EFLAGS_V86_MASK) return; /* Save the full context */ Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; @@ -102,22 +102,19 @@ KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame, TrapFrame->HardwareEsp = Stack; /* Setup Ring 3 state */ - TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK; - TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK; - TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK; - TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK; + TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, UserMode); + TrapFrame->HardwareSegSs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode); + TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode); + TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode); + TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, UserMode); TrapFrame->SegGs = 0; + TrapFrame->ErrCode = 0; /* Sanitize EFLAGS */ - TrapFrame->EFlags = Context.EFlags & EFLAGS_USER_SANITIZE; - TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK; + TrapFrame->EFlags = Ke386SanitizeFlags(Context.EFlags, UserMode); - /* Check if user-mode has IO privileges */ - if (KeGetCurrentThread()->Iopl) - { - /* Enable them*/ - TrapFrame->EFlags |= (0x3000); - } + /* Check if thread has IOPL and force it enabled if so */ + if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= 0x3000; /* Setup the stack */ *(PULONG_PTR)(Stack + 0 * sizeof(ULONG_PTR)) = (ULONG_PTR)NormalRoutine; diff --git a/reactos/ntoskrnl/mm/i386/memsafe.s b/reactos/ntoskrnl/mm/i386/memsafe.s deleted file mode 100644 index 7141a09de7b..00000000000 --- a/reactos/ntoskrnl/mm/i386/memsafe.s +++ /dev/null @@ -1,17 +0,0 @@ -.globl @MmSafeReadPtr@4 -.globl _MmSafeReadPtrStart -.globl _MmSafeReadPtrEnd - -/*****************************************************************************/ - - /* - * PVOID FASTCALL MmSafeReadPtr(PVOID Source) - */ -@MmSafeReadPtr@4: -_MmSafeReadPtrStart: - /* - * If we incur a pagefault, eax will be set NULL - */ - movl (%ecx),%eax -_MmSafeReadPtrEnd: - ret diff --git a/reactos/ntoskrnl/mm/i386/pfault.c b/reactos/ntoskrnl/mm/i386/pfault.c deleted file mode 100644 index 55d6c57b84e..00000000000 --- a/reactos/ntoskrnl/mm/i386/pfault.c +++ /dev/null @@ -1,135 +0,0 @@ -/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/mm/i386/pfault.c - * PURPOSE: Paging file functions - * - * PROGRAMMERS: David Welch (welch@mcmail.com) - */ - -/* INCLUDES *****************************************************************/ - -#include -#define NDEBUG -#include - -/* EXTERNS *******************************************************************/ - -extern VOID MmSafeReadPtrStart(VOID); -extern VOID MmSafeReadPtrEnd(VOID); - - -extern BOOLEAN Mmi386MakeKernelPageTableGlobal(PVOID Address); -extern ULONG KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2); - -extern BOOLEAN Ke386NoExecute; - -/* FUNCTIONS *****************************************************************/ - -ULONG KiPageFaultHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr) -{ - ULONG_PTR cr2; - NTSTATUS Status; - KPROCESSOR_MODE Mode; - EXCEPTION_RECORD Er; - - ASSERT(ExceptionNr == 14); - - /* get the faulting address */ - cr2 = __readcr2(); - Tf->DbgArgPointer = cr2; - - /* it's safe to enable interrupts after cr2 has been saved */ - if (Tf->EFlags & (X86_EFLAGS_VM|X86_EFLAGS_IF)) - { - _enable(); - } - - if (cr2 >= (ULONG_PTR)MmSystemRangeStart) - { - /* check for an invalid page directory in kernel mode */ - if (!(Tf->ErrCode & 0x5) && Mmi386MakeKernelPageTableGlobal((PVOID)cr2)) - { - return 0; - } - - /* check for non executable memory in kernel mode */ - if (Ke386NoExecute && Tf->ErrCode & 0x10) - { - KEBUGCHECKWITHTF(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY, 0, 0, 0, 0, Tf); - } - } - - Mode = Tf->ErrCode & 0x4 ? UserMode : KernelMode; - - /* handle the fault */ - if (Tf->ErrCode & 0x1) - { - Status = MmAccessFault(Mode, cr2, FALSE); - } - else - { - Status = MmNotPresentFault(Mode, cr2, FALSE); - } - - /* handle the return for v86 mode */ - if (Tf->EFlags & X86_EFLAGS_VM) - { - if (!NT_SUCCESS(Status)) - { - /* FIXME: This should use ->VdmObjects */ - if(!PsGetCurrentProcess()->Pcb.Unused) - { - *((PKV86M_TRAP_FRAME)Tf)->regs->PStatus = STATUS_NONCONTINUABLE_EXCEPTION; - } - return 1; - } - return 0; - } - - if (Mode == KernelMode) - { - if (!NT_SUCCESS(Status)) - { - if (Tf->Eip >= (ULONG_PTR)MmSafeReadPtrStart && - Tf->Eip < (ULONG_PTR)MmSafeReadPtrEnd) - { - Tf->Eip = (ULONG_PTR)MmSafeReadPtrEnd; - Tf->Eax = 0; - return 0; - } - } - } - else - { - if (KeGetCurrentThread()->ApcState.UserApcPending) - { - KIRQL oldIrql; - - KeRaiseIrql(APC_LEVEL, &oldIrql); - KiDeliverApc(UserMode, NULL, NULL); - KeLowerIrql(oldIrql); - } - } - - if (NT_SUCCESS(Status)) - { - return 0; - } - - Er.ExceptionCode = STATUS_ACCESS_VIOLATION; - Er.ExceptionFlags = 0; - Er.ExceptionRecord = NULL; - Er.ExceptionAddress = (PVOID)Tf->Eip; - Er.NumberParameters = 2; - Er.ExceptionInformation[0] = Tf->ErrCode & 0x1; - Er.ExceptionInformation[1] = (ULONG)cr2; - - /* FIXME: Which exceptions are noncontinuable? */ - Er.ExceptionFlags = 0; - - KiDispatchException(&Er, 0, Tf, Mode, TRUE); - return 0; -} - diff --git a/reactos/ntoskrnl/mm/mdl.c b/reactos/ntoskrnl/mm/mdl.c index f4eaeaada6c..47093d763d0 100644 --- a/reactos/ntoskrnl/mm/mdl.c +++ b/reactos/ntoskrnl/mm/mdl.c @@ -433,7 +433,7 @@ VOID STDCALL MmProbeAndLockPages (PMDL Mdl, if (!MmIsPagePresent(NULL, Address)) { - Status = MmNotPresentFault(Mode, (ULONG_PTR)Address, TRUE); + Status = MmAccessFault(FALSE, Address, Mode, NULL); if (!NT_SUCCESS(Status)) { for (j = 0; j < i; j++) @@ -457,7 +457,7 @@ VOID STDCALL MmProbeAndLockPages (PMDL Mdl, if ((Operation == IoWriteAccess || Operation == IoModifyAccess) && (!(MmGetPageProtect(NULL, (PVOID)Address) & PAGE_READWRITE))) { - Status = MmAccessFault(Mode, (ULONG_PTR)Address, TRUE); + Status = MmAccessFault(TRUE, Address, Mode, NULL); if (!NT_SUCCESS(Status)) { for (j = 0; j < i; j++) diff --git a/reactos/ntoskrnl/mm/mm.c b/reactos/ntoskrnl/mm/mm.c index e7a0642ed0c..fb3f7707e5e 100644 --- a/reactos/ntoskrnl/mm/mm.c +++ b/reactos/ntoskrnl/mm/mm.c @@ -75,9 +75,9 @@ BOOLEAN STDCALL MmIsAddressValid(PVOID VirtualAddress) NTSTATUS NTAPI -MmAccessFault(KPROCESSOR_MODE Mode, - ULONG_PTR Address, - BOOLEAN FromMdl) +MmpAccessFault(KPROCESSOR_MODE Mode, + ULONG_PTR Address, + BOOLEAN FromMdl) { PMADDRESS_SPACE AddressSpace; MEMORY_AREA* MemoryArea; @@ -109,7 +109,7 @@ MmAccessFault(KPROCESSOR_MODE Mode, { DPRINT1("MmAccessFault(Mode %d, Address %x)\n", Mode, Address); DbgPrint("%s:%d\n",__FILE__,__LINE__); - return(STATUS_UNSUCCESSFUL); + return(STATUS_ACCESS_VIOLATION); } AddressSpace = MmGetKernelAddressSpace(); } @@ -131,13 +131,13 @@ MmAccessFault(KPROCESSOR_MODE Mode, { MmUnlockAddressSpace(AddressSpace); } - return (STATUS_UNSUCCESSFUL); + return (STATUS_ACCESS_VIOLATION); } switch (MemoryArea->Type) { case MEMORY_AREA_SYSTEM: - Status = STATUS_UNSUCCESSFUL; + Status = STATUS_ACCESS_VIOLATION; break; case MEMORY_AREA_PAGED_POOL: @@ -152,15 +152,15 @@ MmAccessFault(KPROCESSOR_MODE Mode, break; case MEMORY_AREA_VIRTUAL_MEMORY: - Status = STATUS_UNSUCCESSFUL; + Status = STATUS_ACCESS_VIOLATION; break; case MEMORY_AREA_SHARED_DATA: - Status = STATUS_UNSUCCESSFUL; + Status = STATUS_ACCESS_VIOLATION; break; default: - Status = STATUS_UNSUCCESSFUL; + Status = STATUS_ACCESS_VIOLATION; break; } } @@ -174,32 +174,6 @@ MmAccessFault(KPROCESSOR_MODE Mode, return(Status); } -NTSTATUS -NTAPI -MmCommitPagedPoolAddress(PVOID Address, BOOLEAN Locked) -{ - NTSTATUS Status; - PFN_TYPE AllocatedPage; - Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage); - if (!NT_SUCCESS(Status)) - { - MmUnlockAddressSpace(MmGetKernelAddressSpace()); - Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage); - MmLockAddressSpace(MmGetKernelAddressSpace()); - } - Status = - MmCreateVirtualMapping(NULL, - (PVOID)PAGE_ROUND_DOWN(Address), - PAGE_READWRITE, - &AllocatedPage, - 1); - if (Locked) - { - MmLockPage(AllocatedPage); - } - return(Status); -} - NTSTATUS NTAPI MmNotPresentFault(KPROCESSOR_MODE Mode, @@ -227,7 +201,7 @@ MmNotPresentFault(KPROCESSOR_MODE Mode, DPRINT("No current process\n"); if (Address < (ULONG_PTR)MmSystemRangeStart) { - return(STATUS_UNSUCCESSFUL); + return(STATUS_ACCESS_VIOLATION); } } @@ -242,7 +216,7 @@ MmNotPresentFault(KPROCESSOR_MODE Mode, if (Mode != KernelMode) { CPRINT("Address: %x\n", Address); - return(STATUS_UNSUCCESSFUL); + return(STATUS_ACCESS_VIOLATION); } AddressSpace = MmGetKernelAddressSpace(); } @@ -268,7 +242,7 @@ MmNotPresentFault(KPROCESSOR_MODE Mode, { MmUnlockAddressSpace(AddressSpace); } - return (STATUS_UNSUCCESSFUL); + return (STATUS_ACCESS_VIOLATION); } switch (MemoryArea->Type) @@ -280,7 +254,7 @@ MmNotPresentFault(KPROCESSOR_MODE Mode, } case MEMORY_AREA_SYSTEM: - Status = STATUS_UNSUCCESSFUL; + Status = STATUS_ACCESS_VIOLATION; break; case MEMORY_AREA_SECTION_VIEW: @@ -309,7 +283,7 @@ MmNotPresentFault(KPROCESSOR_MODE Mode, break; default: - Status = STATUS_UNSUCCESSFUL; + Status = STATUS_ACCESS_VIOLATION; break; } } @@ -323,6 +297,67 @@ MmNotPresentFault(KPROCESSOR_MODE Mode, return(Status); } +extern BOOLEAN Mmi386MakeKernelPageTableGlobal(PVOID Address); + +NTSTATUS +NTAPI +MmAccessFault(IN BOOLEAN StoreInstruction, + IN PVOID Address, + IN KPROCESSOR_MODE Mode, + IN PVOID TrapInformation) +{ + /* Cute little hack for ROS */ + if ((ULONG_PTR)Address >= (ULONG_PTR)MmSystemRangeStart) + { + /* Check for an invalid page directory in kernel mode */ + if (Mmi386MakeKernelPageTableGlobal(Address)) + { + /* All is well with the world */ + return STATUS_SUCCESS; + } + } + + /* Keep same old ReactOS Behaviour */ + if (StoreInstruction) + { + /* Call access fault */ + return MmpAccessFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE); + } + else + { + /* Call not present */ + return MmNotPresentFault(Mode, (ULONG_PTR)Address, TrapInformation ? FALSE : TRUE); + } +} + +NTSTATUS +NTAPI +MmCommitPagedPoolAddress(PVOID Address, BOOLEAN Locked) +{ + NTSTATUS Status; + PFN_TYPE AllocatedPage; + Status = MmRequestPageMemoryConsumer(MC_PPOOL, FALSE, &AllocatedPage); + if (!NT_SUCCESS(Status)) + { + MmUnlockAddressSpace(MmGetKernelAddressSpace()); + Status = MmRequestPageMemoryConsumer(MC_PPOOL, TRUE, &AllocatedPage); + MmLockAddressSpace(MmGetKernelAddressSpace()); + } + Status = + MmCreateVirtualMapping(NULL, + (PVOID)PAGE_ROUND_DOWN(Address), + PAGE_READWRITE, + &AllocatedPage, + 1); + if (Locked) + { + MmLockPage(AllocatedPage); + } + return(Status); +} + + + /* Miscellanea functions: they may fit somewhere else */ /* diff --git a/reactos/ntoskrnl/ntoskrnl.rbuild b/reactos/ntoskrnl/ntoskrnl.rbuild index 50498768219..3f0ce54a4b3 100644 --- a/reactos/ntoskrnl/ntoskrnl.rbuild +++ b/reactos/ntoskrnl/ntoskrnl.rbuild @@ -257,9 +257,7 @@ - memsafe.s page.c - pfault.c anonmem.c diff --git a/reactos/ntoskrnl/ob/oblife.c b/reactos/ntoskrnl/ob/oblife.c index 23e0e5e5160..72ef1c16471 100644 --- a/reactos/ntoskrnl/ob/oblife.c +++ b/reactos/ntoskrnl/ob/oblife.c @@ -134,8 +134,9 @@ ObpDeallocateObject(IN PVOID Object) } VOID -FASTCALL -ObpDeleteObject(IN PVOID Object) +NTAPI +ObpDeleteObject(IN PVOID Object, + IN BOOLEAN CalledFromWorkerThread) { POBJECT_HEADER Header; POBJECT_TYPE ObjectType; @@ -203,12 +204,15 @@ VOID NTAPI ObpReapObject(IN PVOID Parameter) { - POBJECT_HEADER ReapObject; + POBJECT_HEADER ReapObject = (PVOID)1; PVOID NextObject; /* Start reaping */ - while ((ReapObject = InterlockedExchangePointer(&ObpReaperList, NULL))) + do { + /* Get the reap object */ + ReapObject = InterlockedExchangePointer(&ObpReaperList, ReapObject); + /* Start deletion loop */ do { @@ -216,12 +220,13 @@ ObpReapObject(IN PVOID Parameter) NextObject = ReapObject->NextToFree; /* Delete the object */ - ObpDeleteObject(&ReapObject->Body); + ObpDeleteObject(&ReapObject->Body, TRUE); /* Move to the next one */ ReapObject = NextObject; - } while (NextObject); - } + } while ((NextObject) && (NextObject != (PVOID)1)); + } while ((ObpReaperList != (PVOID)1) || + (InterlockedCompareExchange((PLONG)&ObpReaperList, 0, 1) != 1)); } /*++ diff --git a/reactos/ntoskrnl/ob/obref.c b/reactos/ntoskrnl/ob/obref.c index cf4858113e7..0432345edce 100644 --- a/reactos/ntoskrnl/ob/obref.c +++ b/reactos/ntoskrnl/ob/obref.c @@ -50,21 +50,27 @@ ObReferenceObjectSafe(IN PVOID Object) VOID NTAPI -ObpDeferObjectDeletion(IN PVOID Object) +ObpDeferObjectDeletion(IN POBJECT_HEADER Header) { - POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER(Object); + PVOID Entry, NewEntry; - /* Add us to the list */ + /* Loop while trying to update the list */ do { - Header->NextToFree = ObpReaperList; - } while (InterlockedCompareExchangePointer(&ObpReaperList, - Header, - Header->NextToFree) != - Header->NextToFree); + /* Get the current entry */ + Entry = ObpReaperList; - /* Queue the work item */ - ExQueueWorkItem(&ObpReaperWorkItem, DelayedWorkQueue); + /* Link our object to the list */ + Header->NextToFree = Entry; + NewEntry = Header; + + /* Update the list */ + } while (InterlockedCompareExchangePointer(&ObpReaperList, + NewEntry, + Entry) != Entry); + + /* Queue the work item if needed */ + if (!Entry) ExQueueWorkItem(&ObpReaperWorkItem, CriticalWorkQueue); } LONG @@ -91,11 +97,7 @@ ObDereferenceObjectEx(IN PVOID Object, /* Check whether the object can now be deleted. */ NewCount = InterlockedExchangeAdd(&Header->PointerCount, -Count); - if (!Count) - { - /* Add us to the deferred deletion list */ - ObpDeferObjectDeletion(Object); - } + if (!Count) ObpDeferObjectDeletion(Header); /* Return the current count */ return NewCount; @@ -308,12 +310,12 @@ ObfDereferenceObject(IN PVOID Object) if (KeGetCurrentIrql() == PASSIVE_LEVEL) { /* Remove the object */ - ObpDeleteObject(Object); + ObpDeleteObject(Object, FALSE); } else { /* Add us to the deferred deletion list */ - ObpDeferObjectDeletion(Object); + ObpDeferObjectDeletion(Header); } } @@ -325,11 +327,13 @@ VOID NTAPI ObDereferenceObjectDeferDelete(IN PVOID Object) { + POBJECT_HEADER Header = OBJECT_TO_OBJECT_HEADER(Object); + /* Check whether the object can now be deleted. */ - if (!(InterlockedDecrement(&OBJECT_TO_OBJECT_HEADER(Object)->PointerCount))) + if (!InterlockedDecrement(&Header->PointerCount)) { /* Add us to the deferred deletion list */ - ObpDeferObjectDeletion(Object); + ObpDeferObjectDeletion(Header); } } diff --git a/reactos/ntoskrnl/vdm/vdmexec.c b/reactos/ntoskrnl/vdm/vdmexec.c index 947ca035439..f95ea1d7710 100644 --- a/reactos/ntoskrnl/vdm/vdmexec.c +++ b/reactos/ntoskrnl/vdm/vdmexec.c @@ -50,7 +50,7 @@ VdmSwapContext(IN PKTRAP_FRAME TrapFrame, /* Make sure that we're at APC_LEVEL and that this is a valid frame */ ASSERT_IRQL(APC_LEVEL); - ASSERT(TrapFrame->DbgArgMark = 0xBADB0D00); + ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00); /* Check if this is a V86 frame */ if (TrapFrame->EFlags & EFLAGS_V86_MASK) @@ -61,9 +61,9 @@ VdmSwapContext(IN PKTRAP_FRAME TrapFrame, OutContext->SegEs = TrapFrame->V86Es; OutContext->SegDs = TrapFrame->V86Ds; } - else if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK)) + else if (TrapFrame->SegCs != (KGDT_R3_CODE | RPL_MASK)) { - /* This was user mode, copy segment registers */ + /* This was kernel mode, copy segment registers */ OutContext->SegGs = TrapFrame->SegGs; OutContext->SegFs = TrapFrame->SegFs; OutContext->SegEs = TrapFrame->SegEs;