2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/freeldr.c
5 * PURPOSE: FreeLDR Bootstrap Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *****************************************************************/
15 /* GLOBALS *******************************************************************/
17 /* FreeLDR Module Data */
18 LOADER_MODULE KeLoaderModules
[64];
19 ULONG KeLoaderModuleCount
;
20 static CHAR KeLoaderModuleStrings
[64][256];
21 PLOADER_MODULE CachedModules
[MaximumCachedModuleType
];
23 /* FreeLDR Memory Data */
24 ADDRESS_RANGE KeMemoryMap
[64];
25 ULONG KeMemoryMapRangeCount
;
26 ULONG_PTR FirstKrnlPhysAddr
;
27 ULONG_PTR LastKrnlPhysAddr
;
28 ULONG_PTR LastKernelAddress
;
29 ULONG MmFreeLdrMemHigher
, MmFreeLdrMemLower
;
30 ULONG MmFreeLdrPageDirectoryStart
, MmFreeLdrPageDirectoryEnd
;
32 /* FreeLDR Loader Data */
33 ROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock
;
34 static CHAR KeLoaderCommandLine
[256];
35 BOOLEAN AcpiTableDetected
;
37 /* FreeLDR PE Hack Data */
38 extern unsigned int _image_base__
;
39 ULONG_PTR KERNEL_BASE
= (ULONG_PTR
)&_image_base__
;
40 extern LDR_DATA_TABLE_ENTRY HalModuleObject
;
43 LOADER_PARAMETER_BLOCK BldrLoaderBlock
;
44 LOADER_PARAMETER_EXTENSION BldrExtensionBlock
;
45 CHAR BldrCommandLine
[256];
46 CHAR BldrArcBootPath
[64];
47 CHAR BldrArcHalPath
[64];
48 CHAR BldrNtHalPath
[64];
49 CHAR BldrNtBootPath
[64];
50 LDR_DATA_TABLE_ENTRY BldrModules
[64];
51 MEMORY_ALLOCATION_DESCRIPTOR BldrMemoryDescriptors
[64];
52 WCHAR BldrModuleStrings
[64][260];
53 NLS_DATA_BLOCK BldrNlsDataBlock
;
54 SETUP_LOADER_BLOCK BldrSetupBlock
;
56 /* FUNCTIONS *****************************************************************/
60 KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock
,
61 IN PLOADER_PARAMETER_BLOCK
*NtLoaderBlock
)
63 PLOADER_PARAMETER_BLOCK LoaderBlock
;
64 PLDR_DATA_TABLE_ENTRY LdrEntry
;
65 PMEMORY_ALLOCATION_DESCRIPTOR MdEntry
;
66 PLOADER_MODULE RosEntry
;
70 PCHAR BootPath
, HalPath
;
71 CHAR CommandLine
[256];
73 /* First get some kernel-loader globals */
74 AcpiTableDetected
= (RosLoaderBlock
->Flags
& MB_FLAGS_ACPI_TABLE
) ? TRUE
: FALSE
;
75 MmFreeLdrMemHigher
= RosLoaderBlock
->MemHigher
;
76 MmFreeLdrMemLower
= RosLoaderBlock
->MemLower
;
77 MmFreeLdrPageDirectoryStart
= RosLoaderBlock
->PageDirectoryStart
;
78 MmFreeLdrPageDirectoryEnd
= RosLoaderBlock
->PageDirectoryEnd
;
79 KeLoaderModuleCount
= RosLoaderBlock
->ModsCount
;
81 /* Set the NT Loader block and initialize it */
82 *NtLoaderBlock
= LoaderBlock
= &BldrLoaderBlock
;
83 RtlZeroMemory(LoaderBlock
, sizeof(LOADER_PARAMETER_BLOCK
));
85 /* Set the NLS Data block */
86 LoaderBlock
->NlsData
= &BldrNlsDataBlock
;
88 /* Assume this is from FreeLDR's SetupLdr */
89 LoaderBlock
->SetupLdrBlock
= &BldrSetupBlock
;
91 /* Setup the list heads */
92 InitializeListHead(&LoaderBlock
->LoadOrderListHead
);
93 InitializeListHead(&LoaderBlock
->MemoryDescriptorListHead
);
94 InitializeListHead(&LoaderBlock
->BootDriverListHead
);
96 /* Loop boot driver list */
97 for (i
= 0; i
< KeLoaderModuleCount
; i
++)
99 /* Get the ROS loader entry */
100 RosEntry
= &KeLoaderModules
[i
];
101 DriverName
= (PCHAR
)RosEntry
->String
;
102 ModStart
= (PVOID
)RosEntry
->ModStart
;
103 ModSize
= RosEntry
->ModEnd
- (ULONG_PTR
)ModStart
;
105 /* Check if this is any of the NLS files */
106 if (!_stricmp(DriverName
, "ansi.nls"))
109 LoaderBlock
->NlsData
->AnsiCodePageData
= ModStart
;
111 /* Create an MD for it */
112 MdEntry
= &BldrMemoryDescriptors
[i
];
113 MdEntry
->MemoryType
= LoaderNlsData
;
114 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
115 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
116 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
117 &MdEntry
->ListEntry
);
120 else if (!_stricmp(DriverName
, "oem.nls"))
123 LoaderBlock
->NlsData
->OemCodePageData
= ModStart
;
125 /* Create an MD for it */
126 MdEntry
= &BldrMemoryDescriptors
[i
];
127 MdEntry
->MemoryType
= LoaderNlsData
;
128 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
129 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
130 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
131 &MdEntry
->ListEntry
);
134 else if (!_stricmp(DriverName
, "casemap.nls"))
136 /* Unicode Code page */
137 LoaderBlock
->NlsData
->UnicodeCodePageData
= ModStart
;
139 /* Create an MD for it */
140 MdEntry
= &BldrMemoryDescriptors
[i
];
141 MdEntry
->MemoryType
= LoaderNlsData
;
142 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
143 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
144 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
145 &MdEntry
->ListEntry
);
149 /* Check if this is the SYSTEM hive */
150 if (!(_stricmp(DriverName
, "system")) ||
151 !(_stricmp(DriverName
, "system.hiv")))
153 /* Save registry data */
154 LoaderBlock
->RegistryBase
= ModStart
;
155 LoaderBlock
->RegistryLength
= ModSize
;
157 /* Disable setup mode */
158 LoaderBlock
->SetupLdrBlock
= NULL
;
160 /* Create an MD for it */
161 MdEntry
= &BldrMemoryDescriptors
[i
];
162 MdEntry
->MemoryType
= LoaderRegistryData
;
163 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
164 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
165 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
166 &MdEntry
->ListEntry
);
170 /* Check if this is the HARDWARE hive */
171 if (!(_stricmp(DriverName
, "hardware")) ||
172 !(_stricmp(DriverName
, "hardware.hiv")))
174 /* Save registry data */
175 LoaderBlock
->RegistryBase
= ModStart
;
176 LoaderBlock
->RegistryLength
= ModSize
;
178 /* Create an MD for it */
179 MdEntry
= &BldrMemoryDescriptors
[i
];
180 MdEntry
->MemoryType
= LoaderRegistryData
;
181 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
182 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
183 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
184 &MdEntry
->ListEntry
);
188 /* Setup the loader entry */
189 LdrEntry
= &BldrModules
[i
];
190 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
192 /* Convert driver name from ANSI to Unicode */
193 for (j
= 0; j
< strlen(DriverName
); j
++)
195 BldrModuleStrings
[i
][j
] = DriverName
[j
];
198 /* Setup driver name */
199 RtlInitUnicodeString(&LdrEntry
->BaseDllName
, BldrModuleStrings
[i
]);
200 RtlInitUnicodeString(&LdrEntry
->FullDllName
, BldrModuleStrings
[i
]);
202 /* Copy data from Freeldr Module Entry */
203 LdrEntry
->DllBase
= ModStart
;
204 LdrEntry
->SizeOfImage
= ModSize
;
206 /* Initialize other data */
207 LdrEntry
->LoadCount
= 1;
208 LdrEntry
->Flags
= LDRP_IMAGE_DLL
|
209 LDRP_ENTRY_PROCESSED
;
210 if (RosEntry
->Reserved
) LdrEntry
->Flags
|= LDRP_ENTRY_INSERTED
;
212 /* Insert it into the loader block */
213 InsertTailList(&LoaderBlock
->LoadOrderListHead
,
214 &LdrEntry
->InLoadOrderLinks
);
216 /* Check if this is the kernel */
217 if (!(_stricmp(DriverName
, "ntoskrnl.exe")))
219 /* Create an MD for it */
220 MdEntry
= &BldrMemoryDescriptors
[i
];
221 MdEntry
->MemoryType
= LoaderSystemCode
;
222 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
223 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
224 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
225 &MdEntry
->ListEntry
);
227 else if (!(_stricmp(DriverName
, "hal.dll")))
229 /* Create an MD for the HAL */
230 MdEntry
= &BldrMemoryDescriptors
[i
];
231 MdEntry
->MemoryType
= LoaderHalCode
;
232 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
233 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
234 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
235 &MdEntry
->ListEntry
);
239 /* Create an MD for any driver */
240 MdEntry
= &BldrMemoryDescriptors
[i
];
241 MdEntry
->MemoryType
= LoaderBootDriver
;
242 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
243 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
244 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
245 &MdEntry
->ListEntry
);
249 /* Setup command line */
250 LoaderBlock
->LoadOptions
= BldrCommandLine
;
251 strcpy(BldrCommandLine
, KeLoaderCommandLine
);
253 /* Setup the extension block */
254 LoaderBlock
->Extension
= &BldrExtensionBlock
;
255 LoaderBlock
->Extension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
256 LoaderBlock
->Extension
->MajorVersion
= 5;
257 LoaderBlock
->Extension
->MinorVersion
= 2;
259 /* Now setup the setup block if we have one */
260 if (LoaderBlock
->SetupLdrBlock
)
262 /* All we'll setup right now is the flag for text-mode setup */
263 LoaderBlock
->SetupLdrBlock
->Flags
= 1;
266 /* Make a copy of the command line */
267 strcpy(CommandLine
, LoaderBlock
->LoadOptions
);
269 /* Find the first \, separating the ARC path from NT path */
270 BootPath
= strchr(CommandLine
, '\\');
271 *BootPath
= ANSI_NULL
;
272 strncpy(BldrArcBootPath
, CommandLine
, 63);
273 LoaderBlock
->ArcBootDeviceName
= BldrArcBootPath
;
275 /* The rest of the string is the NT path */
276 HalPath
= strchr(BootPath
+ 1, ' ');
277 *HalPath
= ANSI_NULL
;
278 BldrNtBootPath
[0] = '\\';
279 strncat(BldrNtBootPath
, BootPath
+ 1, 63);
280 strcat(BldrNtBootPath
,"\\");
281 LoaderBlock
->NtBootPathName
= BldrNtBootPath
;
283 /* Set the HAL paths */
284 strncpy(BldrArcHalPath
, BldrArcBootPath
, 63);
285 LoaderBlock
->ArcHalDeviceName
= BldrArcHalPath
;
286 strcpy(BldrNtHalPath
, "\\");
287 LoaderBlock
->NtHalPathName
= BldrNtHalPath
;
289 /* Use this new command line */
290 strncpy(LoaderBlock
->LoadOptions
, HalPath
+ 2, 255);
292 /* Parse it and change every slash to a space */
293 BootPath
= LoaderBlock
->LoadOptions
;
294 do {if (*BootPath
== '/') *BootPath
= ' ';} while (*BootPath
++);
299 KiRosPrepareForSystemStartup(IN ULONG Dummy
,
300 IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock
)
307 PIMAGE_NT_HEADERS NtHeader
;
308 PIMAGE_OPTIONAL_HEADER OptHead
;
309 PLOADER_PARAMETER_BLOCK NtLoaderBlock
;
314 /* Load the GDT and IDT */
315 Ke386SetGlobalDescriptorTable(KiGdtDescriptor
);
316 Ke386SetInterruptDescriptorTable(KiIdtDescriptor
);
318 /* Initialize the boot TSS */
320 TssEntry
= &KiBootGdt
[KGDT_TSS
/ sizeof(KGDTENTRY
)];
321 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
322 TssEntry
->HighWord
.Bits
.Pres
= 1;
323 TssEntry
->HighWord
.Bits
.Dpl
= 0;
324 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
325 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
326 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
328 /* Copy the Loader Block Data locally since Low-Memory will be wiped */
329 memcpy(&KeRosLoaderBlock
, LoaderBlock
, sizeof(ROS_LOADER_PARAMETER_BLOCK
));
330 memcpy(&KeLoaderModules
[1],
331 (PVOID
)KeRosLoaderBlock
.ModsAddr
,
332 sizeof(LOADER_MODULE
) * KeRosLoaderBlock
.ModsCount
);
333 KeRosLoaderBlock
.ModsCount
++;
334 KeRosLoaderBlock
.ModsAddr
= (ULONG
)&KeLoaderModules
;
336 /* Check for BIOS memory map */
337 KeMemoryMapRangeCount
= 0;
338 if (KeRosLoaderBlock
.Flags
& MB_FLAGS_MMAP_INFO
)
340 /* We have a memory map from the nice BIOS */
341 size
= *((PULONG
)(KeRosLoaderBlock
.MmapAddr
- sizeof(ULONG
)));
344 /* Map it until we run out of size */
345 while (i
< KeRosLoaderBlock
.MmapLength
)
347 /* Copy into the Kernel Memory Map */
348 memcpy (&KeMemoryMap
[KeMemoryMapRangeCount
],
349 (PVOID
)(KeRosLoaderBlock
.MmapAddr
+ i
),
350 sizeof(ADDRESS_RANGE
));
352 /* Increase Memory Map Count */
353 KeMemoryMapRangeCount
++;
360 KeRosLoaderBlock
.MmapLength
= KeMemoryMapRangeCount
*
361 sizeof(ADDRESS_RANGE
);
362 KeRosLoaderBlock
.MmapAddr
= (ULONG
)KeMemoryMap
;
366 /* Nothing from BIOS */
367 KeRosLoaderBlock
.MmapLength
= 0;
368 KeRosLoaderBlock
.MmapAddr
= (ULONG
)KeMemoryMap
;
371 /* Save the Base Address */
372 MmSystemRangeStart
= (PVOID
)KeRosLoaderBlock
.KernelBase
;
374 /* Set the Command Line */
375 strcpy(KeLoaderCommandLine
, (PCHAR
)LoaderBlock
->CommandLine
);
376 KeRosLoaderBlock
.CommandLine
= (ULONG
)KeLoaderCommandLine
;
378 /* Write the first Module (the Kernel) */
379 strcpy(KeLoaderModuleStrings
[0], "ntoskrnl.exe");
380 KeLoaderModules
[0].String
= (ULONG
)KeLoaderModuleStrings
[0];
381 KeLoaderModules
[0].ModStart
= KERNEL_BASE
;
384 NtHeader
= RtlImageNtHeader((PVOID
)KeLoaderModules
[0].ModStart
);
385 OptHead
= &NtHeader
->OptionalHeader
;
387 /* Set Kernel Ending */
388 KeLoaderModules
[0].ModEnd
= KeLoaderModules
[0].ModStart
+
389 PAGE_ROUND_UP((ULONG
)OptHead
->SizeOfImage
);
391 /* Create a block for each module */
392 for (i
= 1; i
< KeRosLoaderBlock
.ModsCount
; i
++)
394 /* Check if we have to copy the path or not */
395 if ((s
= strrchr((PCHAR
)KeLoaderModules
[i
].String
, '/')) != 0)
397 strcpy(KeLoaderModuleStrings
[i
], s
+ 1);
401 strcpy(KeLoaderModuleStrings
[i
], (PCHAR
)KeLoaderModules
[i
].String
);
404 /* Substract the base Address in Physical Memory */
405 KeLoaderModules
[i
].ModStart
-= 0x200000;
407 /* Add the Kernel Base Address in Virtual Memory */
408 KeLoaderModules
[i
].ModStart
+= KERNEL_BASE
;
410 /* Substract the base Address in Physical Memory */
411 KeLoaderModules
[i
].ModEnd
-= 0x200000;
413 /* Add the Kernel Base Address in Virtual Memory */
414 KeLoaderModules
[i
].ModEnd
+= KERNEL_BASE
;
416 /* Select the proper String */
417 KeLoaderModules
[i
].String
= (ULONG
)KeLoaderModuleStrings
[i
];
420 /* Choose last module address as the final kernel address */
421 LastKernelAddress
= PAGE_ROUND_UP(KeLoaderModules
[KeRosLoaderBlock
.
422 ModsCount
- 1].ModEnd
);
424 /* Select the HAL Base */
425 HalBase
= KeLoaderModules
[1].ModStart
;
427 /* Choose Driver Base */
428 DriverBase
= LastKernelAddress
;
429 LdrHalBase
= (ULONG_PTR
)DriverBase
;
431 /* Initialize Module Management */
432 LdrInitModuleManagement();
434 /* Load HAL.DLL with the PE Loader */
435 LdrSafePEProcessModule((PVOID
)HalBase
,
442 // HACK HACK HACK WHEN WILL YOU PEOPLE FIX FREELDR?!?!?!
443 // FREELDR SENDS US AN ***INVALID*** HAL PE HEADER!!!
444 // WE READ IT IN LdrInitModuleManagement ABOVE!!!
445 // WE SET .SizeOfImage TO A *GARBAGE* VALUE!!!
447 // This dirty hack fixes it, and should make symbol lookup work too.
449 HalModuleObject
.SizeOfImage
= RtlImageNtHeader((PVOID
)HalModuleObject
.
451 OptionalHeader
.SizeOfImage
;
453 /* Increase the last kernel address with the size of HAL */
454 LastKernelAddress
+= PAGE_ROUND_UP(DriverSize
);
456 /* Now select the final beginning and ending Kernel Addresses */
457 FirstKrnlPhysAddr
= KeLoaderModules
[0].ModStart
- KERNEL_BASE
+ 0x200000;
458 LastKrnlPhysAddr
= LastKernelAddress
- KERNEL_BASE
+ 0x200000;
461 KeInitExceptions(); // ONCE HACK BELOW IS GONE, MOVE TO KISYSTEMSTARTUP!
462 KeInitInterrupts(); // ROS HACK DEPRECATED SOON BY NEW HAL
464 /* Load the Kernel with the PE Loader */
465 LdrSafePEProcessModule((PVOID
)KERNEL_BASE
,
470 /* Sets up the VDM Data */
473 /* Convert the loader block */
474 KiRosFrldrLpbToNtLpb(&KeRosLoaderBlock
, &NtLoaderBlock
);
476 /* Do general System Startup */
477 KiSystemStartup(NtLoaderBlock
);