3 * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/ldr/init.c
22 * PURPOSE: Loaders for PE executables
23 * PROGRAMMERS: Jean Michault
24 * Rex Jolliff (rex@lvcablemodem.com)
27 * RJJ 10/12/98 Completed image loader function and added hooks for MZ/PE
28 * RJJ 10/12/98 Built driver loader function and added hooks for PE/COFF
29 * RJJ 10/12/98 Rolled in David's code to load COFF drivers
30 * JM 14/12/98 Built initial PE user module loader
31 * RJJ 06/03/99 Moved user PE loader into NTDLL
32 * EA 19990717 LdrGetSystemDirectory()
33 * EK 20000618 Using SystemRoot link instead of LdrGetSystemDirectory()
34 * HYP 20020911 Code to determine smss's path from the registry
37 /* INCLUDES *****************************************************************/
39 #include <ddk/ntddk.h>
40 #include <internal/i386/segment.h>
41 #include <internal/module.h>
42 #include <internal/ntoskrnl.h>
43 #include <internal/ob.h>
44 #include <internal/ps.h>
45 #include <internal/ldr.h>
49 #include <internal/debug.h>
51 /* FUNCTIONS *****************************************************************/
54 * TODO: Read the location of the initial process from command line before
55 * trying the registry - embedded setups, like the installation CD-ROM, may not
58 NTSTATUS LdrLoadInitialProcess (VOID)
62 UNICODE_STRING ProcessName = {0, 0, NULL};
63 OBJECT_ATTRIBUTES ObjectAttributes;
66 PIMAGE_NT_HEADERS NTHeaders;
70 INITIAL_TEB InitialTeb;
71 ULONG OldPageProtection;
72 SECTION_IMAGE_INFORMATION Sii;
74 PVOID ImageBaseAddress;
75 ULONG InitialStack[5];
77 /* FIXME: Test this please */
79 PWSTR Environment = L"SystemRoot=\\SystemRoot\0";
80 RTL_QUERY_REGISTRY_TABLE RegistryValues[] = {
83 RTL_QUERY_REGISTRY_DIRECT,
87 L"\\SystemRoot\\system32\\smss.exe"
88 sizeof(L"\\SystemRoot\\system32\\smss.exe") - sizeof(WCHAR)
90 { NULL, 0, NULL, NULL, 0, NULL, 0 }
93 /* try to query the SMSS path from the registry */
94 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
100 /* failure or invalid data: use default */
101 if(!NT_SUCCESS(Status) || ProcessName.Length < sizeof(WCHAR))
102 RtlInitUnicodeStringFromLiteral(&ProcessName,
103 L"\\SystemRoot\\system32\\smss.exe");
104 /* relative path: open \SystemRoot\system32 */
105 else if(ProcessName.Buffer[0] != L'\\')
107 UNICODE_STRING DirPath;
109 RtlInitUnicodeStringFromLiteral(&DirPath, L"\\SystemRoot\\system32");
111 InitializeObjectAttributes(&ObjectAttributes,
117 if(!NT_SUCCESS(ZwOpenFile(&RootDir, 0, &ObjectAttributes, NULL, 0, 0)))
118 /* failure: use default */
119 RtlInitUnicodeStringFromLiteral(&ProcessName,
120 L"\\SystemRoot\\system32\\smss.exe");
123 InitializeObjectAttributes(&ObjectAttributes,
130 * Get the absolute path to smss.exe using the
133 RtlInitUnicodeStringFromLiteral(&ProcessName,
134 L"\\SystemRoot\\system32\\smss.exe");
136 * Open process image to determine ImageBase
137 * and StackBase/Size.
139 InitializeObjectAttributes(&ObjectAttributes,
145 DPRINT("Opening image file %S\n", ObjectAttributes.ObjectName->Buffer);
146 Status = ZwOpenFile(&FileHandle,
153 /* FIXME? ExFreePool() should ignore non-pool data */
154 RtlFreeUnicodeString(&ProcessName);
157 if (!NT_SUCCESS(Status))
159 DPRINT("Image open failed (Status was %x)\n", Status);
164 * Create a section for the image
166 DPRINT("Creating section\n");
167 Status = ZwCreateSection(&SectionHandle,
172 SEC_COMMIT | SEC_IMAGE,
174 if (!NT_SUCCESS(Status))
176 DPRINT("ZwCreateSection failed (Status %x)\n", Status);
183 * Get information about the process image.
185 Status = ZwQuerySection(SectionHandle,
186 SectionImageInformation,
190 if (!NT_SUCCESS(Status) || ResultLength != sizeof(Sii))
192 DPRINT("ZwQuerySection failed (Status %X)\n", Status);
193 ZwClose(SectionHandle);
197 DPRINT("Creating process\n");
198 Status = ZwCreateProcess(&ProcessHandle,
206 if (!NT_SUCCESS(Status))
208 DPRINT("Could not create process\n");
213 * Create initial stack and thread
217 * Create page backed section for stack
219 DPRINT("Allocating stack\n");
221 DPRINT("Referencing process\n");
222 Status = ObReferenceObjectByHandle(ProcessHandle,
228 if (!NT_SUCCESS(Status))
230 DPRINT("ObReferenceObjectByProcess() failed (Status %x)\n", Status);
234 DPRINT("Attaching to process\n");
235 KeAttachProcess(Process);
236 ImageBaseAddress = Process->Peb->ImageBaseAddress;
237 NTHeaders = RtlImageNtHeader(ImageBaseAddress);
238 DPRINT("NTHeaders %x\n", NTHeaders);
239 InitialTeb.StackReserve = NTHeaders->OptionalHeader.SizeOfStackReserve;
240 /* FIXME: use correct commit size */
241 InitialTeb.StackCommit = NTHeaders->OptionalHeader.SizeOfStackReserve - PAGE_SIZE;
242 // InitialTeb.StackCommit = NTHeaders->OptionalHeader.SizeOfStackCommit;
243 /* add guard page size */
244 InitialTeb.StackCommit += PAGE_SIZE;
245 DPRINT("StackReserve 0x%lX StackCommit 0x%lX\n",
246 InitialTeb.StackReserve, InitialTeb.StackCommit);
248 DPRINT("Dereferencing process\n");
249 ObDereferenceObject(Process);
251 DPRINT("Allocating stack\n");
252 InitialTeb.StackAllocate = NULL;
253 Status = NtAllocateVirtualMemory(ProcessHandle,
254 &InitialTeb.StackAllocate,
256 &InitialTeb.StackReserve,
259 if (!NT_SUCCESS(Status))
261 DPRINT("Stack allocation failed (Status %x)", Status);
265 DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
266 InitialTeb.StackAllocate, InitialTeb.StackReserve);
268 InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
269 InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
271 DPRINT("StackBase: %p StackCommit: 0x%lX\n",
272 InitialTeb.StackBase, InitialTeb.StackCommit);
275 Status = NtAllocateVirtualMemory(ProcessHandle,
276 &InitialTeb.StackLimit,
278 &InitialTeb.StackCommit,
281 if (!NT_SUCCESS(Status))
283 /* release the stack space */
284 NtFreeVirtualMemory(ProcessHandle,
285 InitialTeb.StackAllocate,
286 &InitialTeb.StackReserve,
289 DPRINT("Error comitting stack page!\n");
293 DPRINT("StackLimit: %p\nStackCommit: 0x%lX\n",
294 InitialTeb.StackLimit,
295 InitialTeb.StackCommit);
297 /* Protect guard page */
298 Status = NtProtectVirtualMemory(ProcessHandle,
299 InitialTeb.StackLimit,
301 PAGE_GUARD | PAGE_READWRITE,
303 if (!NT_SUCCESS(Status))
305 /* release the stack space */
306 NtFreeVirtualMemory(ProcessHandle,
307 InitialTeb.StackAllocate,
308 &InitialTeb.StackReserve,
311 DPRINT("Error protecting guard page!\n");
316 * Initialize context to point to LdrStartup
318 memset(&Context,0,sizeof(CONTEXT));
319 Context.Eip = (ULONG)(ImageBaseAddress + (ULONG)Sii.EntryPoint);
320 Context.SegCs = USER_CS;
321 Context.SegDs = USER_DS;
322 Context.SegEs = USER_DS;
323 Context.SegFs = TEB_SELECTOR;
324 Context.SegGs = USER_DS;
325 Context.SegSs = USER_DS;
326 Context.EFlags = 0x202;
327 Context.Esp = (ULONG)InitialTeb.StackBase - 20;
330 * Write in the initial stack.
333 InitialStack[1] = PEB_BASE;
334 Status = ZwWriteVirtualMemory(ProcessHandle,
337 sizeof(InitialStack),
339 if (!NT_SUCCESS(Status))
341 DPRINT1("Failed to write initial stack.\n");
346 * FIXME: Create process and let 'er rip
348 DPRINT("Creating thread for initial process\n");
349 Status = ZwCreateThread(&ThreadHandle,
357 if (!NT_SUCCESS(Status))
359 DPRINT("Thread creation failed (Status %x)\n", Status);
361 NtFreeVirtualMemory(ProcessHandle,
362 InitialTeb.StackAllocate,
363 &InitialTeb.StackReserve,
366 /* FIXME: unmap the section here */
367 /* FIXME: destroy the section here */
368 /* FIXME: Kill the process here */
373 return(STATUS_SUCCESS);