Fixed LARGE_INTEGER handling
[reactos.git] / reactos / ntoskrnl / ldr / init.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ldr/loader.c
5 * PURPOSE: Loaders for PE executables
6 * PROGRAMMERS: Jean Michault
7 * Rex Jolliff (rex@lvcablemodem.com)
8 * UPDATE HISTORY:
9 * DW 22/05/98 Created
10 * RJJ 10/12/98 Completed image loader function and added hooks for MZ/PE
11 * RJJ 10/12/98 Built driver loader function and added hooks for PE/COFF
12 * RJJ 10/12/98 Rolled in David's code to load COFF drivers
13 * JM 14/12/98 Built initial PE user module loader
14 * RJJ 06/03/99 Moved user PE loader into NTDLL
15 */
16
17 /* INCLUDES *****************************************************************/
18
19 #include <windows.h>
20
21 #include <internal/i386/segment.h>
22 #include <internal/linkage.h>
23 #include <internal/module.h>
24 #include <internal/ntoskrnl.h>
25 #include <internal/ob.h>
26 #include <internal/ps.h>
27 #include <string.h>
28 #include <internal/string.h>
29 #include <internal/symbol.h>
30 #include <internal/teb.h>
31 #include <ddk/ntddk.h>
32
33 //#define NDEBUG
34 #include <internal/debug.h>
35
36 /* FUNCTIONS ****************************************************************/
37
38 /* LdrLoadImage
39 * FUNCTION:
40 * Builds the initial environment for a process. Should be used
41 * to load the initial user process.
42 * ARGUMENTS:
43 * HANDLE ProcessHandle handle of the process to load the module into
44 * PUNICODE_STRING Filename name of the module to load
45 * RETURNS:
46 * NTSTATUS
47 */
48
49 #define STACK_TOP (0xb0000000)
50
51 static NTSTATUS LdrCreatePeb(HANDLE ProcessHandle)
52 {
53 NTSTATUS Status;
54 PVOID PebBase;
55 ULONG PebSize;
56 NT_PEB Peb;
57 ULONG BytesWritten;
58
59 PebBase = PEB_BASE;
60 PebSize = 0x1000;
61 Status = ZwAllocateVirtualMemory(ProcessHandle,
62 &PebBase,
63 0,
64 &PebSize,
65 MEM_COMMIT,
66 PAGE_READWRITE);
67 if (!NT_SUCCESS(Status))
68 {
69 return(Status);
70 }
71
72
73 memset(&Peb, 0, sizeof(Peb));
74 Peb.StartupInfo = PEB_STARTUPINFO;
75
76 ZwWriteVirtualMemory(ProcessHandle,
77 (PVOID)PEB_BASE,
78 &Peb,
79 sizeof(Peb),
80 &BytesWritten);
81
82 return(STATUS_SUCCESS);
83 }
84
85 NTSTATUS LdrLoadImage(HANDLE ProcessHandle, PUNICODE_STRING Filename)
86 {
87 char BlockBuffer[1024];
88 DWORD ImageBase, LdrStartupAddr, StackBase;
89 ULONG ImageSize, StackSize;
90 NTSTATUS Status;
91 OBJECT_ATTRIBUTES FileObjectAttributes;
92 HANDLE FileHandle, SectionHandle, NTDllSectionHandle, ThreadHandle;
93 HANDLE DupNTDllSectionHandle;
94 CONTEXT Context;
95 UNICODE_STRING DllPathname;
96 PIMAGE_DOS_HEADER DosHeader;
97 PIMAGE_NT_HEADERS NTHeaders;
98 ULONG BytesWritten;
99 ULONG InitialViewSize;
100 ULONG i;
101 HANDLE DupSectionHandle;
102
103 /* Locate and open NTDLL to determine ImageBase and LdrStartup */
104 RtlInitUnicodeString(&DllPathname,L"\\??\\C:\\reactos\\system\\ntdll.dll");
105 InitializeObjectAttributes(&FileObjectAttributes,
106 &DllPathname,
107 0,
108 NULL,
109 NULL);
110 DPRINT("Opening NTDLL\n");
111 Status = ZwOpenFile(&FileHandle,
112 FILE_ALL_ACCESS,
113 &FileObjectAttributes,
114 NULL,
115 0,
116 0);
117 if (!NT_SUCCESS(Status))
118 {
119 DPRINT("NTDLL open failed ");
120 DbgPrintErrorMessage(Status);
121
122 return Status;
123 }
124 Status = ZwReadFile(FileHandle, 0, 0, 0, 0, BlockBuffer, 1024, 0, 0);
125 if (!NT_SUCCESS(Status))
126 {
127 DPRINT("NTDLL header read failed ");
128 DbgPrintErrorMessage(Status);
129 ZwClose(FileHandle);
130
131 return Status;
132 }
133 /* FIXME: this will fail if the NT headers are more than 1024 bytes from start */
134 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
135 if (DosHeader->e_magic != IMAGE_DOS_MAGIC ||
136 DosHeader->e_lfanew == 0L ||
137 *(PULONG)((PUCHAR)BlockBuffer + DosHeader->e_lfanew) != IMAGE_PE_MAGIC)
138 {
139 DPRINT("NTDLL format invalid\n");
140 ZwClose(FileHandle);
141
142 return STATUS_UNSUCCESSFUL;
143 }
144 NTHeaders = (PIMAGE_NT_HEADERS)(BlockBuffer + DosHeader->e_lfanew);
145 ImageBase = NTHeaders->OptionalHeader.ImageBase;
146 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
147 /* FIXME: retrieve the offset of LdrStartup from NTDLL */
148 DPRINT("ImageBase %x\n",ImageBase);
149 LdrStartupAddr = ImageBase + NTHeaders->OptionalHeader.AddressOfEntryPoint;
150
151 /* Create a section for NTDLL */
152 Status = ZwCreateSection(&NTDllSectionHandle,
153 SECTION_ALL_ACCESS,
154 NULL,
155 NULL,
156 PAGE_READWRITE,
157 MEM_COMMIT,
158 FileHandle);
159 if (!NT_SUCCESS(Status))
160 {
161 DPRINT("NTDLL create section failed ");
162 DbgPrintErrorMessage(Status);
163 ZwClose(FileHandle);
164
165 return Status;
166 }
167
168 /* Map the NTDLL into the process */
169 InitialViewSize = DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)
170 + sizeof(IMAGE_SECTION_HEADER) * NTHeaders->FileHeader.NumberOfSections;
171 Status = ZwMapViewOfSection(NTDllSectionHandle,
172 ProcessHandle,
173 (PVOID *)&ImageBase,
174 0,
175 InitialViewSize,
176 NULL,
177 &InitialViewSize,
178 0,
179 MEM_COMMIT,
180 PAGE_READWRITE);
181 if (!NT_SUCCESS(Status))
182 {
183 DPRINT("NTDLL map view of secion failed ");
184 DbgPrintErrorMessage(Status);
185
186 /* FIXME: destroy the section here */
187
188 ZwClose(FileHandle);
189
190 return Status;
191 }
192 for (i=0; i<NTHeaders->FileHeader.NumberOfSections; i++)
193 {
194 PIMAGE_SECTION_HEADER Sections;
195 LARGE_INTEGER Offset;
196 ULONG Base;
197
198 Sections = (PIMAGE_SECTION_HEADER)SECHDROFFSET(BlockBuffer);
199 Base = Sections[i].VirtualAddress + ImageBase;
200 Offset.HighPart = 0;
201 Offset.LowPart = Sections[i].PointerToRawData;
202 Status = ZwMapViewOfSection(NTDllSectionHandle,
203 ProcessHandle,
204 (PVOID *)&Base,
205 0,
206 Sections[i].Misc.VirtualSize,
207 &Offset,
208 (PULONG)&Sections[i].Misc.VirtualSize,
209 0,
210 MEM_COMMIT,
211 PAGE_READWRITE);
212 if (!NT_SUCCESS(Status))
213 {
214 DPRINT("NTDLL map view of secion failed ");
215 DbgPrintErrorMessage(Status);
216
217 /* FIXME: destroy the section here */
218
219 ZwClose(FileHandle);
220 return Status;
221 }
222 }
223 ZwClose(FileHandle);
224
225 /* Open process image to determine ImageBase and StackBase/Size */
226 InitializeObjectAttributes(&FileObjectAttributes,
227 Filename,
228 0,
229 NULL,
230 NULL);
231 DPRINT("Opening image file %w\n",FileObjectAttributes.ObjectName->Buffer);
232 Status = ZwOpenFile(&FileHandle, FILE_ALL_ACCESS, &FileObjectAttributes,
233 NULL, 0, 0);
234 if (!NT_SUCCESS(Status))
235 {
236 DPRINT("Image open failed ");
237 DbgPrintErrorMessage(Status);
238
239 return Status;
240 }
241 Status = ZwReadFile(FileHandle, 0, 0, 0, 0, BlockBuffer, 1024, 0, 0);
242 if (!NT_SUCCESS(Status))
243 {
244 DPRINT("Image header read failed ");
245 DbgPrintErrorMessage(Status);
246 ZwClose(FileHandle);
247
248 return Status;
249 }
250
251 /* FIXME: this will fail if the NT headers are more than 1024 bytes from start */
252
253 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
254 if (DosHeader->e_magic != IMAGE_DOS_MAGIC ||
255 DosHeader->e_lfanew == 0L ||
256 *(PULONG)((PUCHAR)BlockBuffer + DosHeader->e_lfanew) != IMAGE_PE_MAGIC)
257 {
258 DPRINT("Image invalid format rc=%08lx\n", Status);
259 ZwClose(FileHandle);
260
261 return STATUS_UNSUCCESSFUL;
262 }
263 NTHeaders = (PIMAGE_NT_HEADERS)(BlockBuffer + DosHeader->e_lfanew);
264 ImageBase = NTHeaders->OptionalHeader.ImageBase;
265 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
266
267 /* Create a section for the image */
268 Status = ZwCreateSection(&SectionHandle,
269 SECTION_ALL_ACCESS,
270 NULL,
271 NULL,
272 PAGE_READWRITE,
273 MEM_COMMIT,
274 FileHandle);
275 if (!NT_SUCCESS(Status))
276 {
277 DPRINT("Image create section failed ");
278 DbgPrintErrorMessage(Status);
279 ZwClose(FileHandle);
280
281 return Status;
282 }
283
284 /* Map the image into the process */
285 InitialViewSize = DosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)
286 + sizeof(IMAGE_SECTION_HEADER) * NTHeaders->FileHeader.NumberOfSections;
287 DPRINT("InitialViewSize %x\n",InitialViewSize);
288 Status = ZwMapViewOfSection(SectionHandle,
289 ProcessHandle,
290 (PVOID *)&ImageBase,
291 0,
292 InitialViewSize,
293 NULL,
294 &InitialViewSize,
295 0,
296 MEM_COMMIT,
297 PAGE_READWRITE);
298 if (!NT_SUCCESS(Status))
299 {
300 DPRINT("Image map view of section failed ");
301 DbgPrintErrorMessage(Status);
302
303 /* FIXME: destroy the section here */
304
305 ZwClose(FileHandle);
306
307 return Status;
308 }
309 ZwClose(FileHandle);
310
311 /* Create page backed section for stack */
312 StackBase = (STACK_TOP - NTHeaders->OptionalHeader.SizeOfStackReserve);
313 StackSize = NTHeaders->OptionalHeader.SizeOfStackReserve;
314 Status = ZwAllocateVirtualMemory(ProcessHandle,
315 (PVOID *)&StackBase,
316 0,
317 &StackSize,
318 MEM_COMMIT,
319 PAGE_READWRITE);
320 if (!NT_SUCCESS(Status))
321 {
322 DPRINT("Stack allocation failed ");
323 DbgPrintErrorMessage(Status);
324
325 /* FIXME: unmap the section here */
326 /* FIXME: destroy the section here */
327
328 return Status;
329 }
330
331 ZwDuplicateObject(NtCurrentProcess(),
332 &SectionHandle,
333 ProcessHandle,
334 &DupSectionHandle,
335 0,
336 FALSE,
337 DUPLICATE_SAME_ACCESS);
338 ZwDuplicateObject(NtCurrentProcess(),
339 &NTDllSectionHandle,
340 ProcessHandle,
341 &DupNTDllSectionHandle,
342 0,
343 FALSE,
344 DUPLICATE_SAME_ACCESS);
345
346 ZwWriteVirtualMemory(ProcessHandle,
347 (PVOID)(STACK_TOP - 4),
348 &DupNTDllSectionHandle,
349 sizeof(DupNTDllSectionHandle),
350 &BytesWritten);
351 ZwWriteVirtualMemory(ProcessHandle,
352 (PVOID)(STACK_TOP - 8),
353 &ImageBase,
354 sizeof(ImageBase),
355 &BytesWritten);
356 ZwWriteVirtualMemory(ProcessHandle,
357 (PVOID)(STACK_TOP - 12),
358 &DupSectionHandle,
359 sizeof(DupSectionHandle),
360 &BytesWritten);
361
362
363 /*
364 * Create a peb (grungy)
365 */
366 Status = LdrCreatePeb(ProcessHandle);
367 if (!NT_SUCCESS(Status))
368 {
369 DbgPrint("LDR: Failed to create initial peb\n");
370 return(Status);
371 }
372
373 /* Initialize context to point to LdrStartup */
374 memset(&Context,0,sizeof(CONTEXT));
375 Context.SegSs = USER_DS;
376 Context.Esp = STACK_TOP - 16;
377 Context.EFlags = 0x202;
378 Context.SegCs = USER_CS;
379 Context.Eip = LdrStartupAddr;
380 Context.SegDs = USER_DS;
381 Context.SegEs = USER_DS;
382 Context.SegFs = USER_DS;
383 Context.SegGs = USER_DS;
384
385 DPRINT("LdrStartupAddr %x\n",LdrStartupAddr);
386 /* FIXME: Create process and let 'er rip */
387 Status = ZwCreateThread(&ThreadHandle,
388 THREAD_ALL_ACCESS,
389 NULL,
390 ProcessHandle,
391 NULL,
392 &Context,
393 NULL,
394 FALSE);
395 if (!NT_SUCCESS(Status))
396 {
397 DPRINT("Thread creation failed ");
398 DbgPrintErrorMessage(Status);
399
400 /* FIXME: destroy the stack memory block here */
401 /* FIXME: unmap the section here */
402 /* FIXME: destroy the section here */
403
404 return Status;
405 }
406
407 return STATUS_SUCCESS;
408 }
409
410 NTSTATUS LdrLoadInitialProcess(VOID)
411 /*
412 * FIXME: The location of the initial process should be configurable,
413 * from command line or registry
414 */
415 {
416 NTSTATUS Status;
417 HANDLE ProcessHandle;
418 UNICODE_STRING ProcessName;
419
420 Status = ZwCreateProcess(&ProcessHandle,
421 PROCESS_ALL_ACCESS,
422 NULL,
423 SystemProcessHandle,
424 FALSE,
425 NULL,
426 NULL,
427 NULL);
428 if (!NT_SUCCESS(Status))
429 {
430 DbgPrint("Could not create process\n");
431 return Status;
432 }
433
434 RtlInitUnicodeString(&ProcessName, L"\\??\\C:\\reactos\\system\\shell.exe");
435 Status = LdrLoadImage(ProcessHandle, &ProcessName);
436
437 return Status;
438 }