From bec72fa6a78bcd221363edd79335df6bab8564ad Mon Sep 17 00:00:00 2001 From: Stefan Ginsberg Date: Thu, 29 Oct 2009 10:04:15 +0000 Subject: [PATCH] - Implement the ThreadDescriptorTableEntry case for NtQueryInformationThread. This is required for the GetThreadSelectorEntry routine used by user mode debuggers. - #if out some x86-only LDT code from PS and move it to psldt.c. svn path=/trunk/; revision=43827 --- reactos/dll/win32/kernel32/thread/thread.c | 40 ++++---- reactos/include/ndk/i386/ketypes.h | 5 + reactos/ntoskrnl/include/internal/i386/ke.h | 8 ++ reactos/ntoskrnl/include/internal/ps.h | 13 ++- reactos/ntoskrnl/ke/i386/ldt.c | 50 ++++++++++ reactos/ntoskrnl/ntoskrnl-generic.rbuild | 1 + reactos/ntoskrnl/ps/i386/psldt.c | 105 ++++++++++++++++++++ reactos/ntoskrnl/ps/kill.c | 4 +- reactos/ntoskrnl/ps/process.c | 16 --- reactos/ntoskrnl/ps/query.c | 12 ++- 10 files changed, 217 insertions(+), 37 deletions(-) create mode 100644 reactos/ntoskrnl/ps/i386/psldt.c diff --git a/reactos/dll/win32/kernel32/thread/thread.c b/reactos/dll/win32/kernel32/thread/thread.c index 6936d4054b3..3fb6a6da7e7 100644 --- a/reactos/dll/win32/kernel32/thread/thread.c +++ b/reactos/dll/win32/kernel32/thread/thread.c @@ -651,28 +651,32 @@ SetThreadPriorityBoost(IN HANDLE hThread, /* * @implemented */ -BOOL WINAPI +BOOL +WINAPI GetThreadSelectorEntry(IN HANDLE hThread, - IN DWORD dwSelector, - OUT LPLDT_ENTRY lpSelectorEntry) + IN DWORD dwSelector, + OUT LPLDT_ENTRY lpSelectorEntry) { - DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry; - NTSTATUS Status; + DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry; + NTSTATUS Status; - DescriptionTableEntry.Selector = dwSelector; - Status = NtQueryInformationThread(hThread, - ThreadDescriptorTableEntry, - &DescriptionTableEntry, - sizeof(DESCRIPTOR_TABLE_ENTRY), - NULL); - if(!NT_SUCCESS(Status)) - { - SetLastErrorByStatus(Status); - return FALSE; - } + /* Set the selector and do the query */ + DescriptionTableEntry.Selector = dwSelector; + Status = NtQueryInformationThread(hThread, + ThreadDescriptorTableEntry, + &DescriptionTableEntry, + sizeof(DESCRIPTOR_TABLE_ENTRY), + NULL); + if (!NT_SUCCESS(Status)) + { + /* Fail */ + SetLastErrorByStatus(Status); + return FALSE; + } - *lpSelectorEntry = DescriptionTableEntry.Descriptor; - return TRUE; + /* Success, return the selector */ + *lpSelectorEntry = DescriptionTableEntry.Descriptor; + return TRUE; } /* diff --git a/reactos/include/ndk/i386/ketypes.h b/reactos/include/ndk/i386/ketypes.h index e94658771ef..4ce98184a46 100644 --- a/reactos/include/ndk/i386/ketypes.h +++ b/reactos/include/ndk/i386/ketypes.h @@ -66,6 +66,11 @@ Author: #define KGDT_DF_TSS 0x50 #define KGDT_NMI_TSS 0x58 +// +// Define the number of GDTs that can be queried by user mode +// +#define KGDT_NUMBER 10 + // // CR4 // diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index 4c997d0673b..c40b259dcd5 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -88,6 +88,14 @@ KiThreadStartup(PKSYSTEM_ROUTINE SystemRoutine, KTRAP_FRAME TrapFrame); #endif +NTSTATUS +NTAPI +Ke386GetGdtEntryThread( + IN PKTHREAD Thread, + IN ULONG Offset, + IN PKGDTENTRY Descriptor +); + #endif #endif /* __NTOSKRNL_INCLUDE_INTERNAL_I386_KE_H */ diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h index 405cc41c0c6..50f32626f47 100644 --- a/reactos/ntoskrnl/include/internal/ps.h +++ b/reactos/ntoskrnl/include/internal/ps.h @@ -300,8 +300,9 @@ PspDestroyQuotaBlock( IN PEPROCESS Process ); +#if defined(_X86_) // -// VDM Support +// VDM and LDT Support // NTSTATUS NTAPI @@ -315,6 +316,16 @@ PspDeleteVdmObjects( IN PEPROCESS Process ); +NTSTATUS +NTAPI +PspQueryDescriptorThread( + IN PETHREAD Thread, + IN PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength OPTIONAL +); +#endif + // // Job Routines // diff --git a/reactos/ntoskrnl/ke/i386/ldt.c b/reactos/ntoskrnl/ke/i386/ldt.c index 7ac9e428962..4a08fd1c6fa 100644 --- a/reactos/ntoskrnl/ke/i386/ldt.c +++ b/reactos/ntoskrnl/ke/i386/ldt.c @@ -5,6 +5,7 @@ * PURPOSE: LDT managment * * PROGRAMMERS: David Welch (welch@cwcom.net) + * Stefan Ginsberg (stefan.ginsberg@reactos.org) */ /* INCLUDES *****************************************************************/ @@ -20,6 +21,55 @@ static KSPIN_LOCK GdtLock; /* FUNCTIONS *****************************************************************/ +NTSTATUS +NTAPI +Ke386GetGdtEntryThread(IN PKTHREAD Thread, + IN ULONG Offset, + IN PKGDTENTRY Descriptor) +{ + /* Make sure the offset is inside the allowed range */ + if (!((Offset) < (KGDT_NUMBER * sizeof(KGDTENTRY)))) + { + /* It isn't, fail */ + return STATUS_ACCESS_VIOLATION; + } + + /* Check if this is the LDT selector */ + if (Offset == KGDT_LDT) + { + /* Get it from the thread's process */ + RtlCopyMemory(Descriptor, + &Thread->Process->LdtDescriptor, + sizeof(KGDTENTRY)); + } + else + { + /* Get the descriptor entry from the GDT */ + RtlCopyMemory(Descriptor, + (PCHAR)((PKIPCR)KeGetPcr()->GDT) + Offset, + sizeof(KGDTENTRY)); + + /* Check if this is the TEB selector */ + if (Offset == KGDT_R3_TEB) + { + /* + * Make sure we set the correct base for this thread. This is per + * process and is set in the GDT on context switch, so it might not + * be correct for the thread specified. + */ + Descriptor->BaseLow = + (USHORT)((ULONG_PTR)(Thread->Teb) & 0xFFFF); + Descriptor->HighWord.Bytes.BaseMid = + (UCHAR)((ULONG_PTR)(Thread->Teb) >> 16); + Descriptor->HighWord.Bytes.BaseHi = + (UCHAR)((ULONG_PTR)(Thread->Teb) >> 24); + } + } + + /* Success */ + return STATUS_SUCCESS; +} + VOID KeSetBaseGdtSelector(ULONG Entry, PVOID Base) diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild index 5ff09a5e51f..d34f964a860 100644 --- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild +++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild @@ -444,6 +444,7 @@ psctx.c + psldt.c diff --git a/reactos/ntoskrnl/ps/i386/psldt.c b/reactos/ntoskrnl/ps/i386/psldt.c new file mode 100644 index 00000000000..19fccfe8ab2 --- /dev/null +++ b/reactos/ntoskrnl/ps/i386/psldt.c @@ -0,0 +1,105 @@ +/* + * PROJECT: ReactOS Kernel + * LICENSE: GPL - See COPYING in the top level directory + * FILE: ntoskrnl/ps/i386/psldt.c + * PURPOSE: LDT support for x86 + * PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +NTSTATUS +NTAPI +PspDeleteLdt(PEPROCESS Process) +{ + /* FIXME */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +PspDeleteVdmObjects(PEPROCESS Process) +{ + /* FIXME */ + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +PspQueryDescriptorThread(IN PETHREAD Thread, + IN PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength OPTIONAL) +{ + DESCRIPTOR_TABLE_ENTRY DescriptorEntry; + LDT_ENTRY Descriptor; + NTSTATUS Status; + PAGED_CODE(); + + /* Verify the size */ + if (ThreadInformationLength != sizeof(DESCRIPTOR_TABLE_ENTRY)) + { + /* Fail */ + return STATUS_INFO_LENGTH_MISMATCH; + } + + /* Enter SEH for the copy */ + _SEH2_TRY + { + /* Get the descriptor */ + RtlCopyMemory(&DescriptorEntry, + ThreadInformation, + sizeof(DESCRIPTOR_TABLE_ENTRY)); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Return the exception code */ + _SEH2_YIELD(return _SEH2_GetExceptionCode()); + } + _SEH2_END; + + /* Check if this is a GDT selector */ + if (!(DescriptorEntry.Selector & 0x4)) + { + /* Get the GDT entry */ + Status = Ke386GetGdtEntryThread(&Thread->Tcb, + DescriptorEntry.Selector & 0xFFFFFFF8, + (PKGDTENTRY)&Descriptor); + if (!NT_SUCCESS(Status)) return Status; + + /* Enter SEH for the copy */ + _SEH2_TRY + { + /* Copy the GDT entry to caller */ + RtlCopyMemory(&((PDESCRIPTOR_TABLE_ENTRY)ThreadInformation)-> + Descriptor, + &Descriptor, + sizeof(LDT_ENTRY)); + if (ReturnLength) *ReturnLength = sizeof(LDT_ENTRY); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Return the exception code */ + _SEH2_YIELD(return _SEH2_GetExceptionCode()); + } + _SEH2_END; + + /* Success */ + Status = STATUS_SUCCESS; + } + else + { + /* This is only supported for VDM, which we don't implement */ + ASSERT(Thread->ThreadsProcess->LdtInformation == NULL); + Status = STATUS_NO_LDT; + } + + /* Return status to caller */ + return Status; +} diff --git a/reactos/ntoskrnl/ps/kill.c b/reactos/ntoskrnl/ps/kill.c index 92237434fa6..31de3a1d738 100644 --- a/reactos/ntoskrnl/ps/kill.c +++ b/reactos/ntoskrnl/ps/kill.c @@ -270,9 +270,11 @@ PspDeleteProcess(IN PVOID ObjectBody) Process->SectionObject = NULL; } - /* Clean LDT and VDM_OBJECTS */ +#if defined(_X86_) + /* Clean Ldt and Vdm objects */ PspDeleteLdt(Process); PspDeleteVdmObjects(Process); +#endif /* Delete the Object Table */ if (Process->ObjectTable) diff --git a/reactos/ntoskrnl/ps/process.c b/reactos/ntoskrnl/ps/process.c index 31c01628822..2cc0c4f6ae2 100644 --- a/reactos/ntoskrnl/ps/process.c +++ b/reactos/ntoskrnl/ps/process.c @@ -70,22 +70,6 @@ KPRIORITY PspPriorityTable[PROCESS_PRIORITY_CLASS_ABOVE_NORMAL + 1] = /* PRIVATE FUNCTIONS *********************************************************/ -NTSTATUS -NTAPI -PspDeleteLdt(PEPROCESS Process) -{ - /* FIXME */ - return STATUS_SUCCESS; -} - -NTSTATUS -NTAPI -PspDeleteVdmObjects(PEPROCESS Process) -{ - /* FIXME */ - return STATUS_SUCCESS; -} - PETHREAD NTAPI PsGetNextProcessThread(IN PEPROCESS Process, diff --git a/reactos/ntoskrnl/ps/query.c b/reactos/ntoskrnl/ps/query.c index f9d70a93590..b4c2abaefea 100644 --- a/reactos/ntoskrnl/ps/query.c +++ b/reactos/ntoskrnl/ps/query.c @@ -1819,9 +1819,19 @@ NtQueryInformationThread(IN HANDLE ThreadHandle, KeLowerIrql(OldIrql); break; + /* LDT and GDT information */ case ThreadDescriptorTableEntry: - DPRINT1("NtQueryInformationThread(): case ThreadDescriptorTableEntry not implemented!\n"); + +#if defined(_X86_) + /* Call the worker routine */ + Status = PspQueryDescriptorThread(Thread, + ThreadInformation, + ThreadInformationLength, + ReturnLength); +#else + /* Only implemented on x86 */ Status = STATUS_NOT_IMPLEMENTED; +#endif break; case ThreadPriorityBoost: