From e6523bb71eaf3832fa601d358e5dfa3a1e3b3276 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Tue, 12 Jul 2005 04:41:41 +0000 Subject: [PATCH] Second part of patch, implements the new RTL functions which will be used (not used by kernel yet). - RtlCreateUserProcess: * Created RtlpInitEnvironment to manage Environment Block creation. Rougly based on old KlInitPeb code but with some optimizations. * Don't ignore Process Security Descriptor if one was specified. * Don't ignore ZeroBits, get correct entrypoint, and don't assume PEB address. * Don't close handle of section before closing process handle on failure. * Support new undocumented flag which pre-allocates 1MB of memory for Native Processes * FIXME: Hande duplication should be done, but wasn't and still isn't. - RtlpCreateUserStack: * New function to create a stack for a Thread, similar to BasepCreateStack but has some differences related to StackCommit/StackReserve. * Also create Guard Page - RtlpFreeUserStack: * Undoes what the function above does, in case of failure in code using it. - RtlCreateUserThread: * Use the new functions instead of rosrtl. - RtlInitializeContext: * New function similar to BasepInitializeContext but; > Uses a single entrypoint, not many possible thunks like Kernel32 (no need) > The starting EFLAGS is Interrupts Enabled, not IOPL 3. > We don't initialize the same Context Flags > The initial context registers are different - RtlFreeUserThreadStack * Don't assume the TEB address - RtlExitUserThread * Remove deprecated stack-switching semantics and use new TEB flag to tell the Kernel to deallocate the stack for us. svn path=/trunk/; revision=16542 --- reactos/lib/kernel32/process/create.c | 6 +- reactos/lib/ntdll/rtl/process.c | 15 + reactos/lib/rtl/process.c | 531 +++++++++++++------------- reactos/lib/rtl/thread.c | 404 ++++++++++++++++---- reactos/ntoskrnl/mm/pe.c | 5 +- 5 files changed, 611 insertions(+), 350 deletions(-) diff --git a/reactos/lib/kernel32/process/create.c b/reactos/lib/kernel32/process/create.c index 222737c60fe..10f8644688a 100644 --- a/reactos/lib/kernel32/process/create.c +++ b/reactos/lib/kernel32/process/create.c @@ -16,7 +16,7 @@ /* FIXME */ #include -//#define NDEBUG +#define NDEBUG #include "../include/debug.h" /* FUNCTIONS ****************************************************************/ @@ -1378,11 +1378,11 @@ CreateProcessW(LPCWSTR lpApplicationName, * Create the thread for the kernel */ DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n", - (PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress)); + Sii.TransferAddress); hThread = KlCreateFirstThread(hProcess, lpThreadAttributes, &Sii, - (PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress), + Sii.TransferAddress, dwCreationFlags, &lpProcessInformation->dwThreadId); if (hThread == NULL) diff --git a/reactos/lib/ntdll/rtl/process.c b/reactos/lib/ntdll/rtl/process.c index 5f898eef235..f689f2bef32 100644 --- a/reactos/lib/ntdll/rtl/process.c +++ b/reactos/lib/ntdll/rtl/process.c @@ -90,4 +90,19 @@ RtlGetVersion(RTL_OSVERSIONINFOW *Info) return STATUS_INVALID_PARAMETER; } +/* + * @implemented + */ +VOID +STDCALL +RtlExitUserThread(NTSTATUS Status) +{ + /* Call the Loader and tell him to notify the DLLs */ + LdrShutdownThread(); + + /* Shut us down */ + NtCurrentTeb()->FreeStackOnTermination = TRUE; + NtTerminateThread(NtCurrentThread(), Status); +} + /* EOF */ diff --git a/reactos/lib/rtl/process.c b/reactos/lib/rtl/process.c index 8af452474d1..ec70933891b 100644 --- a/reactos/lib/rtl/process.c +++ b/reactos/lib/rtl/process.c @@ -16,176 +16,161 @@ #define NDEBUG #include +/* INTERNAL FUNCTIONS *******************************************************/ + +NTSTATUS +STDCALL +RtlpMapFile(PUNICODE_STRING ImageFileName, + ULONG Attributes, + PHANDLE Section) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE hFile = NULL; + IO_STATUS_BLOCK IoStatusBlock; + + /* Open the Image File */ + InitializeObjectAttributes(&ObjectAttributes, + ImageFileName, + Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT), + NULL, + NULL); + Status = ZwOpenFile(&hFile, + SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_DELETE | FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to read image file from disk\n"); + return(Status); + } + + /* Now create a section for this image */ + Status = ZwCreateSection(Section, + SECTION_ALL_ACCESS, + NULL, + NULL, + PAGE_EXECUTE, + SEC_IMAGE, + hFile); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create section for image file\n"); + } + + ZwClose(hFile); + return Status; +} + /* FUNCTIONS ****************************************************************/ - -static NTSTATUS -RtlpMapFile(PUNICODE_STRING ImageFileName, - PRTL_USER_PROCESS_PARAMETERS Ppb, - ULONG Attributes, - PHANDLE Section) +NTSTATUS +STDCALL +RtlpInitEnvironment(HANDLE ProcessHandle, + PPEB Peb, + PRTL_USER_PROCESS_PARAMETERS ProcessParameters) { - HANDLE hFile; - IO_STATUS_BLOCK IoStatusBlock; - OBJECT_ATTRIBUTES ObjectAttributes; - PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; - NTSTATUS Status; + NTSTATUS Status; + PVOID BaseAddress = NULL; + ULONG EnviroSize; + ULONG Size; + PWCHAR Environment = 0; + + DPRINT("RtlpInitEnvironment (hProcess: %lx, Peb: %p Params: %p)\n", + ProcessHandle, Peb, ProcessParameters); + + /* Give the caller 1MB if he requested it */ + if (ProcessParameters->Flags & PPF_RESERVE_1MB) + { + /* Give 1MB starting at 0x4 */ + BaseAddress = (PVOID)4; + EnviroSize = 1024 * 1024; + Status = ZwAllocateVirtualMemory(ProcessHandle, + &BaseAddress, + 0, + &EnviroSize, + MEM_RESERVE, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to reserve 1MB of space \n"); + return(Status); + } + } + + /* Find the end of the Enviroment Block */ + if ((Environment = (PWCHAR)ProcessParameters->Environment)) + { + while (*Environment++) while (*Environment++); - hFile = NULL; + /* Calculate the size of the block */ + EnviroSize = (ULONG)((ULONG_PTR)Environment - + (ULONG_PTR)ProcessParameters->Environment); + DPRINT("EnvironmentSize %ld\n", EnviroSize); - RtlDeNormalizeProcessParams (Ppb); + /* Allocate and Initialize new Environment Block */ + Size = EnviroSize; + Status = ZwAllocateVirtualMemory(ProcessHandle, + &BaseAddress, + 0, + &Size, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to allocate Environment Block\n"); + return(Status); + } + + /* Write the Environment Block */ + ZwWriteVirtualMemory(ProcessHandle, + BaseAddress, + ProcessParameters->Environment, + EnviroSize, + NULL); + + /* Save pointer */ + ProcessParameters->Environment = BaseAddress; + } + + DPRINT("EnvironmentPointer %p\n", BaseAddress); + DPRINT("Ppb->MaximumLength %x\n", ProcessParameters->MaximumLength); -/* DbgPrint("ImagePathName 0x%p\n", Ppb->ImagePathName.Buffer); */ + /* Now allocate space for the Parameter Block */ + BaseAddress = NULL; + Size = ProcessParameters->MaximumLength; + Status = ZwAllocateVirtualMemory(ProcessHandle, + &BaseAddress, + 0, + &Size, + MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to allocate Parameter Block\n"); + return(Status); + } + + /* Write the Parameter Block */ + ZwWriteVirtualMemory(ProcessHandle, + BaseAddress, + ProcessParameters, + ProcessParameters->Length, + NULL); + + /* Write pointer to Parameter Block */ + ZwWriteVirtualMemory(ProcessHandle, + &Peb->ProcessParameters, + &BaseAddress, + sizeof(BaseAddress), + NULL); - InitializeObjectAttributes(&ObjectAttributes, - ImageFileName, - Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT), - NULL, - SecurityDescriptor); - - RtlNormalizeProcessParams (Ppb); - - /* - * Try to open the executable - */ - - Status = ZwOpenFile(&hFile, - SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_DELETE|FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE); - - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - Status = ZwCreateSection(Section, - SECTION_ALL_ACCESS, - NULL, - NULL, - PAGE_EXECUTE, - SEC_IMAGE, - hFile); - ZwClose(hFile); - - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - return(STATUS_SUCCESS); + /* Return */ + return STATUS_SUCCESS; } -static NTSTATUS KlInitPeb (HANDLE ProcessHandle, - PRTL_USER_PROCESS_PARAMETERS Ppb, - PVOID* ImageBaseAddress) -{ - NTSTATUS Status; - PVOID PpbBase; - ULONG PpbSize; - ULONG BytesWritten; - ULONG Offset; - PVOID EnvPtr = NULL; - ULONG EnvSize = 0; - - /* create the Environment */ - if (Ppb->Environment != NULL) - { - MEMORY_BASIC_INFORMATION MemInfo; - - Status = ZwQueryVirtualMemory (NtCurrentProcess (), - Ppb->Environment, - MemoryBasicInformation, - &MemInfo, - sizeof(MEMORY_BASIC_INFORMATION), - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } - EnvSize = MemInfo.RegionSize; - } - DPRINT("EnvironmentSize %ld\n", EnvSize); - - /* allocate and initialize new environment block */ - if (EnvSize != 0) - { - Status = ZwAllocateVirtualMemory(ProcessHandle, - &EnvPtr, - 0, - &EnvSize, - MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - ZwWriteVirtualMemory(ProcessHandle, - EnvPtr, - Ppb->Environment, - EnvSize, - &BytesWritten); - } - DPRINT("EnvironmentPointer %p\n", EnvPtr); - - /* create the PPB */ - PpbBase = NULL; - PpbSize = Ppb->MaximumLength; - - Status = ZwAllocateVirtualMemory(ProcessHandle, - &PpbBase, - 0, - &PpbSize, - MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength); - - /* write process parameters block*/ - RtlDeNormalizeProcessParams (Ppb); - ZwWriteVirtualMemory(ProcessHandle, - PpbBase, - Ppb, - Ppb->MaximumLength, - - &BytesWritten); - RtlNormalizeProcessParams (Ppb); - - /* write pointer to environment */ - Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment); - ZwWriteVirtualMemory(ProcessHandle, - (PVOID)((ULONG_PTR)PpbBase + Offset), - &EnvPtr, - sizeof(EnvPtr), - &BytesWritten); - - /* write pointer to process parameter block */ - Offset = FIELD_OFFSET(PEB, ProcessParameters); - ZwWriteVirtualMemory(ProcessHandle, - (PVOID)(PEB_BASE + Offset), - &PpbBase, - sizeof(PpbBase), - &BytesWritten); - - /* Read image base address. */ - Offset = FIELD_OFFSET(PEB, ImageBaseAddress); - ZwReadVirtualMemory(ProcessHandle, - (PVOID)(PEB_BASE + Offset), - ImageBaseAddress, - sizeof(PVOID), - &BytesWritten); - - return(STATUS_SUCCESS); -} - - /* * @implemented * @@ -200,114 +185,136 @@ static NTSTATUS KlInitPeb (HANDLE ProcessHandle, * * -Gunnar */ -NTSTATUS STDCALL -RtlCreateUserProcess( - IN PUNICODE_STRING ImageFileName, - IN ULONG Attributes, - IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters, - IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL, - IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL, - IN HANDLE ParentProcess OPTIONAL, - IN BOOLEAN InheritHandles, - IN HANDLE DebugPort OPTIONAL, - IN HANDLE ExceptionPort OPTIONAL, - OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo - ) +NTSTATUS +STDCALL +RtlCreateUserProcess(IN PUNICODE_STRING ImageFileName, + IN ULONG Attributes, + IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters, + IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL, + IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL, + IN HANDLE ParentProcess OPTIONAL, + IN BOOLEAN InheritHandles, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL, + OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo) { - HANDLE hSection; - NTSTATUS Status; - PROCESS_BASIC_INFORMATION ProcessBasicInfo; - ULONG retlen; - SECTION_IMAGE_INFORMATION Sii; - ULONG ResultLength; - PVOID ImageBaseAddress; + NTSTATUS Status; + HANDLE hSection; + PROCESS_BASIC_INFORMATION ProcessBasicInfo; + OBJECT_ATTRIBUTES ObjectAttributes; - DPRINT("RtlCreateUserProcess\n"); + DPRINT("RtlCreateUserProcess: %wZ\n", ImageFileName); - Status = RtlpMapFile(ImageFileName, - ProcessParameters, - Attributes, - &hSection); - if( !NT_SUCCESS( Status ) ) - return Status; + /* Map and Load the File */ + Status = RtlpMapFile(ImageFileName, + Attributes, + &hSection); + if(!NT_SUCCESS(Status)) + { + DPRINT1("Could not map process image\n"); + return Status; + } + + /* Clean out the CurDir Handle if we won't use it */ + if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL; + + /* Use us as parent if none other specified */ + if (!ParentProcess) ParentProcess = NtCurrentProcess(); + + /* Initialize the Object Attributes */ + InitializeObjectAttributes(&ObjectAttributes, + NULL, + 0, + NULL, + ProcessSecurityDescriptor); - /* - * Create a new process - */ - if (ParentProcess == NULL) - ParentProcess = NtCurrentProcess(); + /* + * If FLG_ENABLE_CSRDEBUG is used, then CSRSS is created under the + * watch of WindowsSS + */ + if ((RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG) && + (wcsstr(ImageFileName->Buffer, L"csrss"))) + { + UNICODE_STRING DebugString = RTL_CONSTANT_STRING(L"\\WindowsSS"); + InitializeObjectAttributes(&ObjectAttributes, + &DebugString, + 0, + NULL, + ProcessSecurityDescriptor); + } + + + /* Create Kernel Process Object */ + Status = ZwCreateProcess(&ProcessInfo->ProcessHandle, + PROCESS_ALL_ACCESS, + &ObjectAttributes, + ParentProcess, + InheritHandles, + hSection, + DebugPort, + ExceptionPort); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Could not create Kernel Process Object\n"); + ZwClose(hSection); + return(Status); + } + + /* Get some information on the image */ + Status = ZwQuerySection(hSection, + SectionImageInformation, + &ProcessInfo->ImageInformation, + sizeof(SECTION_IMAGE_INFORMATION), + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Could not query Section Info\n"); + ZwClose(ProcessInfo->ProcessHandle); + ZwClose(hSection); + return(Status); + } - Status = ZwCreateProcess(&(ProcessInfo->ProcessHandle), - PROCESS_ALL_ACCESS, - NULL, - ParentProcess, - InheritHandles, - hSection, - DebugPort, - ExceptionPort); - if (!NT_SUCCESS(Status)) - { - ZwClose(hSection); - return(Status); - } + /* Get some information about the process */ + ZwQueryInformationProcess(ProcessInfo->ProcessHandle, + ProcessBasicInformation, + &ProcessBasicInfo, + sizeof(ProcessBasicInfo), + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Could not query Process Info\n"); + ZwClose(ProcessInfo->ProcessHandle); + ZwClose(hSection); + return(Status); + } - /* - * Get some information about the process - */ - ZwQueryInformationProcess(ProcessInfo->ProcessHandle, - ProcessBasicInformation, - &ProcessBasicInfo, - sizeof(ProcessBasicInfo), - &retlen); - DPRINT("ProcessBasicInfo.UniqueProcessId %d\n", - ProcessBasicInfo.UniqueProcessId); - ProcessInfo->ClientId.UniqueProcess = (HANDLE)ProcessBasicInfo.UniqueProcessId; + /* Create Process Environment */ + RtlpInitEnvironment(ProcessInfo->ProcessHandle, + ProcessBasicInfo.PebBaseAddress, + ProcessParameters); - /* - * Create Process Environment Block - */ - DPRINT("Creating peb\n"); - KlInitPeb(ProcessInfo->ProcessHandle, - ProcessParameters, - &ImageBaseAddress); - - Status = ZwQuerySection(hSection, - SectionImageInformation, - &Sii, - sizeof(Sii), - &ResultLength); - if (!NT_SUCCESS(Status) || ResultLength != sizeof(Sii)) - { - DPRINT("Failed to get section image information.\n"); - ZwClose(hSection); - return(Status); - } - - DPRINT("Creating thread for process\n"); - Status = RtlCreateUserThread( - ProcessInfo->ProcessHandle, - NULL, - TRUE, /* CreateSuspended? */ - 0, - Sii.MaximumStackSize, - Sii.CommittedStackSize, - (PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress), - (PVOID)PEB_BASE, - &ProcessInfo->ThreadHandle, - &ProcessInfo->ClientId - ); - - ZwClose(hSection); - - if (!NT_SUCCESS(Status)) - { - DPRINT("Failed to create thread\n"); - return(Status); - } - - return(STATUS_SUCCESS); + /* Create the first Thread */ + Status = RtlCreateUserThread(ProcessInfo->ProcessHandle, + ThreadSecurityDescriptor, + TRUE, + ProcessInfo->ImageInformation.ZeroBits, + ProcessInfo->ImageInformation.MaximumStackSize, + ProcessInfo->ImageInformation.CommittedStackSize, + ProcessInfo->ImageInformation.TransferAddress, + ProcessBasicInfo.PebBaseAddress, + &ProcessInfo->ThreadHandle, + &ProcessInfo->ClientId); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Could not Create Thread\n"); + ZwClose(ProcessInfo->ProcessHandle); + ZwClose(hSection); /* Don't try to optimize this on top! */ + return Status; + } + + /* Close the Section Handle and return */ + ZwClose(hSection); + return STATUS_SUCCESS; } - - /* EOF */ diff --git a/reactos/lib/rtl/thread.c b/reactos/lib/rtl/thread.c index 010021dcfcd..62704e5d09f 100644 --- a/reactos/lib/rtl/thread.c +++ b/reactos/lib/rtl/thread.c @@ -3,113 +3,349 @@ * PROJECT: ReactOS kernel * PURPOSE: Rtl user thread functions * FILE: lib/ntdll/rtl/thread.c - * PROGRAMER: Eric Kohl - * REVISION HISTORY: - * 09/07/99: Created - * 09/10/99: Cleanup and full stack support. - * 25/04/03: Near rewrite. Made code more readable, replaced - * INITIAL_TEB with USER_STACK, added support for - * fixed-size stacks - * 28/04/03: Moved all code to a new statically linked - * library (ROSRTL) so it can be shared with - * kernel32.dll without exporting non-standard - * functions from ntdll.dll + * PROGRAMERS: + * Alex Ionescu (alex@relsoft.net) + * Eric Kohl + * KJK::Hyperion */ /* INCLUDES *****************************************************************/ #include "rtl.h" -#include #define NDEBUG #include +/* PRIVATE FUNCTIONS *******************************************************/ + +NTSTATUS +STDCALL +RtlpCreateUserStack(HANDLE hProcess, + ULONG StackReserve, + ULONG StackCommit, + ULONG StackZeroBits, + PINITIAL_TEB InitialTeb) +{ + NTSTATUS Status; + SYSTEM_BASIC_INFORMATION SystemBasicInfo; + PIMAGE_NT_HEADERS Headers; + ULONG_PTR Stack = 0; + BOOLEAN UseGuard = FALSE; + + DPRINT("RtlpCreateUserStack\n"); + + /* Get some memory information */ + Status = NtQuerySystemInformation(SystemBasicInformation, + &SystemBasicInfo, + sizeof(SYSTEM_BASIC_INFORMATION), + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failure to query system info\n"); + 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; + } + else + { + /* Use the System Settings if needed */ + StackReserve = (StackReserve) ? StackReserve : + SystemBasicInfo.AllocationGranularity; + StackCommit = (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 + StackCommit = StackReserve; + #endif + DPRINT("StackReserve: %lx, StackCommit: %lx\n", StackReserve, StackCommit); + + /* Reserve memory for the stack */ + Status = ZwAllocateVirtualMemory(hProcess, + (PVOID*)&Stack, + StackZeroBits, + &StackReserve, + MEM_RESERVE, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failure to reserve stack\n"); + return Status; + } + + /* Now set up some basic Initial TEB Parameters */ + 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) + { + Stack -= SystemBasicInfo.PageSize; + StackCommit += SystemBasicInfo.PageSize; + UseGuard = TRUE; + } + + DPRINT("AllocatedBase: %p, StackBase: %p, Stack: %p, StackCommit: %lx\n", + InitialTeb->AllocatedStackBase, InitialTeb->StackBase, Stack, + StackCommit); + + /* Allocate memory for the stack */ + Status = ZwAllocateVirtualMemory(hProcess, + (PVOID*)&Stack, + 0, + &StackCommit, + MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failure to allocate stack\n"); + return Status; + } + + /* Now set the current Stack Limit */ + InitialTeb->StackLimit = (PVOID)Stack; + DPRINT("StackLimit: %p\n", Stack); + + /* Create a guard page */ + if (UseGuard) + { + ULONG GuardPageSize = SystemBasicInfo.PageSize; + ULONG Dummy; + + /* Attempt maximum space possible */ + Status = ZwProtectVirtualMemory(hProcess, + (PVOID*)&Stack, + &GuardPageSize, + PAGE_GUARD | PAGE_READWRITE, + &Dummy); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failure to create guard page\n"); + return Status; + } + + /* Update the Stack Limit keeping in mind the Guard Page */ + InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit - + GuardPageSize); + DPRINT1("StackLimit: %p\n", Stack); + } + + /* We are done! */ + return Status; +} + +NTSTATUS +STDCALL +RtlpFreeUserStack(HANDLE hProcess, + PINITIAL_TEB InitialTeb) +{ + ULONG Dummy = 0; + + /* Free the Stack */ + return ZwFreeVirtualMemory(hProcess, + &InitialTeb->AllocatedStackBase, + &Dummy, + MEM_RELEASE); +} + /* FUNCTIONS ***************************************************************/ /* @implemented */ -NTSTATUS STDCALL 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 +STDCALL +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) { - OBJECT_ATTRIBUTES oaThreadAttribs; + NTSTATUS Status; + HANDLE Handle; + CLIENT_ID ThreadCid; + INITIAL_TEB InitialTeb; + OBJECT_ATTRIBUTES ObjectAttributes; + CONTEXT Context; + + DPRINT("RtlCreateUserThread: (hProcess: %lx, Suspended: %lx," + "ZeroBits: %lx, StackReserve: %lx, StackCommit: %lx," + "StartAddress: %p, Parameter: %lx)\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; + } + + /* 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, + SecurityDescriptor); + Status = ZwCreateThread(&Handle, + THREAD_ALL_ACCESS, + &ObjectAttributes, + ProcessHandle, + &ThreadCid, + &Context, + &InitialTeb, + CreateSuspended); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failure to create Thread\n"); + + /* Free the stack */ + RtlpFreeUserStack(ProcessHandle, &InitialTeb); + } + else + { + DPRINT("Thread created: %lx\n", Handle); + if (ThreadHandle) *ThreadHandle = Handle; + if (ClientId) *ClientId = ThreadCid; + } + + /* Return success or the previous failure */ + return Status; +} - InitializeObjectAttributes - ( - &oaThreadAttribs, - NULL, - 0, - NULL, - SecurityDescriptor - ); +/* + * FIXME: Should go in /i386 + @implemented +*/ +VOID +STDCALL +RtlInitializeContext(IN HANDLE ProcessHandle, + OUT PCONTEXT ThreadContext, + IN PVOID ThreadStartParam OPTIONAL, + IN PTHREAD_START_ROUTINE ThreadStartAddress, + IN PINITIAL_TEB InitialTeb) +{ + DPRINT("RtlInitializeContext: (hProcess: %lx, ThreadContext: %p, Teb: %p\n", + ProcessHandle, ThreadContext, InitialTeb); - return RtlRosCreateUserThread - ( - ProcessHandle, - &oaThreadAttribs, - CreateSuspended, - StackZeroBits, - &StackReserve, - &StackCommit, - StartAddress, - ThreadHandle, - ClientId, - 1, - (ULONG_PTR *)&Parameter - ); + /* + * Set the Initial Registers + * This is based on NT's default values -- crazy apps might expect this... + */ + ThreadContext->Ebp = 0; + ThreadContext->Eax = 0; + ThreadContext->Ebx = 1; + ThreadContext->Ecx = 2; + ThreadContext->Edx = 3; + ThreadContext->Esi = 4; + ThreadContext->Edi = 5; + + /* Set the Selectors */ + ThreadContext->SegGs = 0; + ThreadContext->SegFs = TEB_SELECTOR; + ThreadContext->SegEs = USER_DS; + ThreadContext->SegDs = USER_DS; + ThreadContext->SegCs = USER_CS; + ThreadContext->SegSs = USER_DS; + + /* Enable Interrupts */ + ThreadContext->EFlags = 0x200; /*X86_EFLAGS_IF */ + + /* Settings passed */ + ThreadContext->Eip = (ULONG)ThreadStartAddress; + ThreadContext->Esp = (ULONG)InitialTeb; + + /* Only the basic Context is initialized */ + ThreadContext->ContextFlags = CONTEXT_CONTROL | + CONTEXT_INTEGER | + CONTEXT_SEGMENTS; + + /* Set up ESP to the right value */ + ThreadContext->Esp -= sizeof(PVOID); + ZwWriteVirtualMemory(ProcessHandle, + (PVOID)ThreadContext->Esp, + (PVOID)&ThreadStartParam, + sizeof(PVOID), + NULL); + + /* Push it down one more notch for RETEIP */ + ThreadContext->Esp -= sizeof(PVOID); } /* @implemented */ -VOID STDCALL -RtlInitializeContext( - IN HANDLE ProcessHandle, - OUT PCONTEXT ThreadContext, - IN PVOID ThreadStartParam OPTIONAL, - IN PTHREAD_START_ROUTINE ThreadStartAddress, - IN PINITIAL_TEB InitialTeb) +VOID +STDCALL +RtlFreeUserThreadStack(HANDLE ProcessHandle, + HANDLE ThreadHandle) { - RtlRosInitializeContext - ( - ProcessHandle, - ThreadContext, - ThreadStartAddress, - InitialTeb, - 1, - (ULONG_PTR *)&ThreadStartParam - ); -} - -/* - @implemented -*/ -NTSTATUS STDCALL RtlFreeUserThreadStack -( - HANDLE ProcessHandle, - HANDLE ThreadHandle -) -{ - return RtlRosFreeUserThreadStack(ProcessHandle, ThreadHandle); -} - -/* - @implemented -*/ -VOID STDCALL RtlExitUserThread(NTSTATUS Status) -{ - RtlRosExitUserThread(Status); + NTSTATUS Status; + 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; + } + + /* Get the deallocation stack */ + Status = NtReadVirtualMemory(ProcessHandle, + &((PTEB)ThreadBasicInfo.TebBaseAddress)-> + DeallocationStack, + &StackLocation, + sizeof(PVOID), + &Dummy); + if (!NT_SUCCESS(Status) || !StackLocation) + { + DPRINT1("Could not read Deallocation Base\n"); + return; + } + + /* Free it */ + NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE); } /* EOF */ diff --git a/reactos/ntoskrnl/mm/pe.c b/reactos/ntoskrnl/mm/pe.c index 412516e31c1..bb4d19d9c82 100644 --- a/reactos/ntoskrnl/mm/pe.c +++ b/reactos/ntoskrnl/mm/pe.c @@ -483,7 +483,10 @@ l_ReadHeaderFromFile: ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint)); if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint)) - ImageSectionObject->EntryPoint = piohOptHeader->AddressOfEntryPoint; + { + ImageSectionObject->EntryPoint = piohOptHeader->ImageBase + + piohOptHeader->AddressOfEntryPoint; + } ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));