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.
19 /* $Id: init.c,v 1.43 2003/11/16 21:02:07 ekohl Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ldr/init.c
23 * PURPOSE: Loaders for PE executables
24 * PROGRAMMERS: Jean Michault
25 * Rex Jolliff (rex@lvcablemodem.com)
28 * RJJ 10/12/98 Completed image loader function and added hooks for MZ/PE
29 * RJJ 10/12/98 Built driver loader function and added hooks for PE/COFF
30 * RJJ 10/12/98 Rolled in David's code to load COFF drivers
31 * JM 14/12/98 Built initial PE user module loader
32 * RJJ 06/03/99 Moved user PE loader into NTDLL
33 * EA 19990717 LdrGetSystemDirectory()
34 * EK 20000618 Using SystemRoot link instead of LdrGetSystemDirectory()
35 * EK 20021119 Create a process parameter block for the initial process.
38 /* INCLUDES *****************************************************************/
40 #include <ddk/ntddk.h>
41 #include <internal/i386/segment.h>
42 #include <internal/module.h>
43 #include <internal/ntoskrnl.h>
44 #include <internal/ob.h>
45 #include <internal/ps.h>
46 #include <internal/ldr.h>
50 #include <internal/debug.h>
53 /* MACROS ******************************************************************/
55 #define DENORMALIZE(x,addr) {if(x) x=(VOID*)((ULONG)(x)-(ULONG)(addr));}
56 #define ALIGN(x,align) (((ULONG)(x)+(align)-1UL)&(~((align)-1UL)))
59 /* FUNCTIONS *****************************************************************/
62 LdrpMapProcessImage(PHANDLE SectionHandle
,
63 PUNICODE_STRING ImagePath
)
65 OBJECT_ATTRIBUTES ObjectAttributes
;
66 IO_STATUS_BLOCK IoStatusBlock
;
71 InitializeObjectAttributes(&ObjectAttributes
,
77 DPRINT("Opening image file %S\n", ObjectAttributes
.ObjectName
->Buffer
);
78 Status
= NtOpenFile(&FileHandle
,
83 FILE_SYNCHRONOUS_IO_ALERT
);
84 if (!NT_SUCCESS(Status
))
86 DPRINT("NtOpenFile() failed (Status %lx)\n", Status
);
90 /* Create a section for the image */
91 DPRINT("Creating section\n");
92 Status
= NtCreateSection(SectionHandle
,
97 SEC_COMMIT
| SEC_IMAGE
,
100 if (!NT_SUCCESS(Status
))
102 DPRINT("NtCreateSection() failed (Status %lx)\n", Status
);
110 LdrpCreateProcessEnvironment(HANDLE ProcessHandle
,
111 PUNICODE_STRING ImagePath
,
112 PVOID
* ImageBaseAddress
)
114 PRTL_USER_PROCESS_PARAMETERS LocalPpb
;
115 PRTL_USER_PROCESS_PARAMETERS ProcessPpb
;
122 /* Calculate the PPB size */
123 Size
= sizeof(RTL_USER_PROCESS_PARAMETERS
);
124 Size
+= ALIGN(ImagePath
->Length
+ sizeof(WCHAR
), sizeof(ULONG
));
125 RegionSize
= ROUND_UP(Size
, PAGE_SIZE
);
126 DPRINT("Size %lu RegionSize %lu\n", Size
, RegionSize
);
128 /* Allocate the local PPB */
130 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
134 MEM_RESERVE
| MEM_COMMIT
,
136 if (!NT_SUCCESS(Status
))
138 DPRINT("NtAllocateVirtualMemory() failed (Status %lx)\n", Status
);
142 DPRINT("LocalPpb %p AllocationSize %lu\n", LocalPpb
, RegionSize
);
144 /* Initialize the local PPB */
145 RtlZeroMemory(LocalPpb
,
147 LocalPpb
->AllocationSize
= RegionSize
;
148 LocalPpb
->Size
= Size
;
149 LocalPpb
->ImagePathName
.Length
= ImagePath
->Length
;
150 LocalPpb
->ImagePathName
.MaximumLength
= ImagePath
->Length
+ sizeof(WCHAR
);
151 LocalPpb
->ImagePathName
.Buffer
= (PWCHAR
)(LocalPpb
+ 1);
153 /* Copy image path */
154 RtlCopyMemory(LocalPpb
->ImagePathName
.Buffer
,
157 LocalPpb
->ImagePathName
.Buffer
[ImagePath
->Length
/ sizeof(WCHAR
)] = (WCHAR
)0;
159 /* Denormalize the process parameter block */
160 DENORMALIZE(LocalPpb
->ImagePathName
.Buffer
, LocalPpb
);
161 LocalPpb
->Flags
&= ~PPF_NORMALIZED
;
163 /* Create the process PPB */
165 Status
= NtAllocateVirtualMemory(ProcessHandle
,
169 MEM_RESERVE
| MEM_COMMIT
,
171 if (!NT_SUCCESS(Status
))
173 DPRINT("NtAllocateVirtualMemory() failed (Status %lx)\n", Status
);
175 /* Release the local PPB */
177 NtFreeVirtualMemory(NtCurrentProcess(),
184 /* Copy local PPB into the process PPB */
185 NtWriteVirtualMemory(ProcessHandle
,
188 LocalPpb
->AllocationSize
,
191 /* Update pointer to process PPB in the process PEB */
192 Offset
= FIELD_OFFSET(PEB
, ProcessParameters
);
193 NtWriteVirtualMemory(ProcessHandle
,
194 (PVOID
)(PEB_BASE
+ Offset
),
199 /* Release local PPB */
201 NtFreeVirtualMemory(NtCurrentProcess(),
206 /* Set image file name */
207 Status
= NtSetInformationProcess(ProcessHandle
,
208 ProcessImageFileName
,
211 if (!NT_SUCCESS(Status
))
213 DPRINT("NtSetInformationProcess() failed (Status %lx)\n", Status
);
217 /* Read image base address. */
218 Offset
= FIELD_OFFSET(PEB
, ImageBaseAddress
);
219 NtReadVirtualMemory(ProcessHandle
,
220 (PVOID
)(PEB_BASE
+ Offset
),
225 return(STATUS_SUCCESS
);
229 FIXME: this sucks. Sucks sucks sucks. This code was duplicated, if you can
230 believe it, in four different places - excluding this, and twice in the two
231 DLLs that contained it (kernel32.dll and ntdll.dll). As much as I'd like to
232 rip the whole RTL out of ntdll.dll and ntoskrnl.exe and into its own static
233 library, ntoskrnl.exe is built separatedly from the rest of ReactOS, coming
234 with its own linker scripts and specifications, and, save for changes and fixes
235 to make it at least compile, I'm not going to touch any of it. If you feel
236 brave enough, you're welcome [KJK::Hyperion]
238 static NTSTATUS LdrpCreateStack
240 HANDLE ProcessHandle
,
241 PUSER_STACK UserStack
,
242 PULONG_PTR StackReserve
,
243 PULONG_PTR StackCommit
246 PVOID pStackLowest
= NULL
;
250 if(StackReserve
== NULL
|| StackCommit
== NULL
)
251 return STATUS_INVALID_PARAMETER
;
253 /* FIXME: no SEH, no guard pages */
254 *StackCommit
= *StackReserve
;
256 UserStack
->FixedStackBase
= NULL
;
257 UserStack
->FixedStackLimit
= NULL
;
258 UserStack
->ExpandableStackBase
= NULL
;
259 UserStack
->ExpandableStackLimit
= NULL
;
260 UserStack
->ExpandableStackBottom
= NULL
;
262 /* FIXME: this code assumes a stack growing downwards */
264 if(*StackCommit
== *StackReserve
)
266 DPRINT("Fixed stack\n");
268 UserStack
->FixedStackLimit
= NULL
;
270 /* allocate the stack */
271 nErrCode
= NtAllocateVirtualMemory
274 &(UserStack
->FixedStackLimit
),
277 MEM_RESERVE
| MEM_COMMIT
,
282 if(!NT_SUCCESS(nErrCode
)) return nErrCode
;
284 /* store the highest (first) address of the stack */
285 UserStack
->FixedStackBase
=
286 (PUCHAR
)(UserStack
->FixedStackLimit
) + *StackReserve
;
288 /* expandable stack */
291 ULONG_PTR nGuardSize
= PAGE_SIZE
;
294 DPRINT("Expandable stack\n");
296 UserStack
->FixedStackLimit
= NULL
;
297 UserStack
->FixedStackBase
= NULL
;
298 UserStack
->ExpandableStackBottom
= NULL
;
300 /* reserve the stack */
301 nErrCode
= NtAllocateVirtualMemory
304 &(UserStack
->ExpandableStackBottom
),
312 if(!NT_SUCCESS(nErrCode
)) return nErrCode
;
314 DPRINT("Reserved %08X bytes\n", *StackReserve
);
316 /* expandable stack base - the highest address of the stack */
317 UserStack
->ExpandableStackBase
=
318 (PUCHAR
)(UserStack
->ExpandableStackBottom
) + *StackReserve
;
320 /* expandable stack limit - the lowest committed address of the stack */
321 UserStack
->ExpandableStackLimit
=
322 (PUCHAR
)(UserStack
->ExpandableStackBase
) - *StackCommit
;
324 DPRINT("Stack base %p\n", UserStack
->ExpandableStackBase
);
325 DPRINT("Stack limit %p\n", UserStack
->ExpandableStackLimit
);
327 /* commit as much stack as requested */
328 nErrCode
= NtAllocateVirtualMemory
331 &(UserStack
->ExpandableStackLimit
),
339 if(!NT_SUCCESS(nErrCode
)) goto l_Cleanup
;
341 DPRINT("Stack limit %p\n", UserStack
->ExpandableStackLimit
);
343 pGuardBase
= (PUCHAR
)(UserStack
->ExpandableStackLimit
) - PAGE_SIZE
;
345 DPRINT("Guard base %p\n", UserStack
->ExpandableStackBase
);
347 /* set up the guard page */
348 nErrCode
= NtAllocateVirtualMemory
355 PAGE_READWRITE
| PAGE_GUARD
359 if(!NT_SUCCESS(nErrCode
)) goto l_Cleanup
;
361 DPRINT("Guard base %p\n", UserStack
->ExpandableStackBase
);
364 return STATUS_SUCCESS
;
366 /* cleanup in case of failure */
368 if(UserStack
->FixedStackLimit
)
369 pStackLowest
= UserStack
->FixedStackLimit
;
370 else if(UserStack
->ExpandableStackBottom
)
371 pStackLowest
= UserStack
->ExpandableStackBottom
;
373 /* free the stack, if it was allocated */
374 if(pStackLowest
!= NULL
)
375 NtFreeVirtualMemory(ProcessHandle
, &pStackLowest
, &nSize
, MEM_RELEASE
);
381 NTSTATUS INIT_FUNCTION
382 LdrLoadInitialProcess(PHANDLE ProcessHandle
,
383 PHANDLE ThreadHandle
)
385 SECTION_IMAGE_INFORMATION Sii
;
386 UNICODE_STRING ImagePath
;
387 HANDLE SectionHandle
;
389 USER_STACK UserStack
;
390 ULONG_PTR nStackReserve
= 0;
391 ULONG_PTR nStackCommit
= 0;
395 PVOID ImageBaseAddress
;
396 ULONG InitialStack
[5];
399 /* Get the absolute path to smss.exe. */
400 RtlInitUnicodeStringFromLiteral(&ImagePath
,
401 L
"\\SystemRoot\\system32\\smss.exe");
403 /* Map process image */
404 Status
= LdrpMapProcessImage(&SectionHandle
,
406 if (!NT_SUCCESS(Status
))
408 DPRINT("LdrpMapImage() failed (Status %lx)\n", Status
);
412 /* Get information about the process image. */
413 Status
= NtQuerySection(SectionHandle
,
414 SectionImageInformation
,
418 if (!NT_SUCCESS(Status
) || ResultLength
!= sizeof(Sii
))
420 DPRINT("ZwQuerySection failed (Status %X)\n", Status
);
421 NtClose(ProcessHandle
);
422 NtClose(SectionHandle
);
426 DPRINT("Creating process\n");
427 Status
= NtCreateProcess(ProcessHandle
,
435 NtClose(SectionHandle
);
436 if (!NT_SUCCESS(Status
))
438 DPRINT("NtCreateProcess() failed (Status %lx)\n", Status
);
442 /* Create process environment */
443 DPRINT("Creating the process environment\n");
444 Status
= LdrpCreateProcessEnvironment(*ProcessHandle
,
447 if (!NT_SUCCESS(Status
))
449 DPRINT("LdrpCreateProcessEnvironment() failed (Status %lx)\n", Status
);
450 NtClose(*ProcessHandle
);
453 DPRINT("ImageBaseAddress: %p\n", ImageBaseAddress
);
456 /* Calculate initial stack sizes */
457 if (Sii
.StackReserve
> 0x100000)
458 nStackReserve
= Sii
.StackReserve
;
460 nStackReserve
= 0x100000; /* 1MByte */
464 if (Sii
.StackCommit
> PAGE_SIZE
)
465 nStackCommit
= Sii
.StackCommit
;
467 nStackCommit
= PAGE_SIZE
;
469 nStackCommit
= nStackReserve
- PAGE_SIZE
;
471 DPRINT("StackReserve 0x%lX StackCommit 0x%lX\n",
472 nStackReserve
, nStackCommit
);
475 /* Create the process stack */
476 Status
= LdrpCreateStack
484 if (!NT_SUCCESS(Status
))
486 DPRINT("Failed to write initial stack.\n");
487 NtClose(ProcessHandle
);
491 if(UserStack
.FixedStackBase
&& UserStack
.FixedStackLimit
)
493 pStackBase
= UserStack
.FixedStackBase
;
494 pStackLowest
= UserStack
.FixedStackLimit
;
498 pStackBase
= UserStack
.ExpandableStackBase
;
499 pStackLowest
= UserStack
.ExpandableStackBottom
;
502 DPRINT("pStackBase = %p\n", pStackBase
);
503 DPRINT("pStackLowest = %p\n", pStackLowest
);
506 * Initialize context to point to LdrStartup
509 memset(&Context
,0,sizeof(CONTEXT
));
510 Context
.ContextFlags
= CONTEXT_FULL
;
511 Context
.FloatSave
.ControlWord
= 0xffff037f;
512 Context
.FloatSave
.StatusWord
= 0xffff0000;
513 Context
.FloatSave
.TagWord
= 0xffffffff;
514 Context
.FloatSave
.DataSelector
= 0xffff0000;
515 Context
.Eip
= (ULONG_PTR
)(ImageBaseAddress
+ (ULONG_PTR
)Sii
.EntryPoint
);
516 Context
.SegCs
= USER_CS
;
517 Context
.SegDs
= USER_DS
;
518 Context
.SegEs
= USER_DS
;
519 Context
.SegFs
= TEB_SELECTOR
;
520 Context
.SegGs
= USER_DS
;
521 Context
.SegSs
= USER_DS
;
522 Context
.EFlags
= 0x202;
523 Context
.Esp
= (ULONG_PTR
)pStackBase
- 20;
525 #error Unsupported architecture
529 * Write in the initial stack.
532 InitialStack
[1] = PEB_BASE
;
533 Status
= NtWriteVirtualMemory(*ProcessHandle
,
536 sizeof(InitialStack
),
538 if (!NT_SUCCESS(Status
))
542 DPRINT("Failed to write initial stack.\n");
544 NtFreeVirtualMemory(*ProcessHandle
,
548 NtClose(*ProcessHandle
);
552 /* Create initial thread */
553 DPRINT("Creating thread for initial process\n");
554 Status
= NtCreateThread(ThreadHandle
,
562 if (!NT_SUCCESS(Status
))
566 DPRINT("NtCreateThread() failed (Status %lx)\n", Status
);
568 NtFreeVirtualMemory(*ProcessHandle
,
573 NtClose(*ProcessHandle
);
577 DPRINT("Process created successfully\n");
579 return(STATUS_SUCCESS
);