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 *****************************************************************/
16 /* GLOBALS *******************************************************************/
18 /* FreeLDR Module Data */
19 LOADER_MODULE KeLoaderModules
[64];
20 ULONG KeLoaderModuleCount
;
21 static CHAR KeLoaderModuleStrings
[64][256];
23 /* FreeLDR Memory Data */
24 ADDRESS_RANGE KeMemoryMap
[64];
25 ULONG KeMemoryMapRangeCount
;
26 ULONG_PTR MmFreeLdrFirstKrnlPhysAddr
, MmFreeLdrLastKrnlPhysAddr
;
27 ULONG_PTR MmFreeLdrLastKernelAddress
;
28 ULONG MmFreeLdrMemHigher
;
29 ULONG MmFreeLdrPageDirectoryEnd
;
31 /* FreeLDR Loader Data */
32 ROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock
;
33 static CHAR KeLoaderCommandLine
[256];
34 BOOLEAN AcpiTableDetected
;
36 /* FreeLDR PE Hack Data */
37 extern LDR_DATA_TABLE_ENTRY HalModuleObject
;
40 LOADER_PARAMETER_BLOCK BldrLoaderBlock
;
41 LOADER_PARAMETER_EXTENSION BldrExtensionBlock
;
42 CHAR BldrCommandLine
[256];
43 CHAR BldrArcBootPath
[64];
44 CHAR BldrArcHalPath
[64];
45 CHAR BldrNtHalPath
[64];
46 CHAR BldrNtBootPath
[64];
47 LDR_DATA_TABLE_ENTRY BldrModules
[64];
48 MEMORY_ALLOCATION_DESCRIPTOR BldrMemoryDescriptors
[64];
49 WCHAR BldrModuleStrings
[64][260];
50 NLS_DATA_BLOCK BldrNlsDataBlock
;
51 SETUP_LOADER_BLOCK BldrSetupBlock
;
52 struct _boot_infos_t
*BootInfo
;
56 boot_infos_t PpcEarlybootInfo
;
59 #define KSEG0_BASE 0x80000000
61 /* FUNCTIONS *****************************************************************/
65 KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock
,
66 IN PLOADER_PARAMETER_BLOCK
*NtLoaderBlock
)
68 PLOADER_PARAMETER_BLOCK LoaderBlock
;
69 PLDR_DATA_TABLE_ENTRY LdrEntry
;
70 PMEMORY_ALLOCATION_DESCRIPTOR MdEntry
;
71 PLOADER_MODULE RosEntry
;
75 PCHAR BootPath
, HalPath
;
76 CHAR CommandLine
[256];
78 /* First get some kernel-loader globals */
79 AcpiTableDetected
= (RosLoaderBlock
->Flags
& MB_FLAGS_ACPI_TABLE
) ? TRUE
: FALSE
;
80 MmFreeLdrMemHigher
= RosLoaderBlock
->MemHigher
;
81 MmFreeLdrPageDirectoryEnd
= RosLoaderBlock
->PageDirectoryEnd
;
82 KeLoaderModuleCount
= RosLoaderBlock
->ModsCount
;
84 /* Set the NT Loader block and initialize it */
85 *NtLoaderBlock
= LoaderBlock
= &BldrLoaderBlock
;
86 RtlZeroMemory(LoaderBlock
, sizeof(LOADER_PARAMETER_BLOCK
));
88 /* Set the NLS Data block */
89 LoaderBlock
->NlsData
= &BldrNlsDataBlock
;
91 /* Assume this is from FreeLDR's SetupLdr */
92 LoaderBlock
->SetupLdrBlock
= &BldrSetupBlock
;
94 /* Setup the list heads */
95 InitializeListHead(&LoaderBlock
->LoadOrderListHead
);
96 InitializeListHead(&LoaderBlock
->MemoryDescriptorListHead
);
97 InitializeListHead(&LoaderBlock
->BootDriverListHead
);
99 /* Loop boot driver list */
100 for (i
= 0; i
< KeLoaderModuleCount
; i
++)
102 /* Get the ROS loader entry */
103 RosEntry
= &KeLoaderModules
[i
];
104 DriverName
= (PCHAR
)RosEntry
->String
;
105 ModStart
= (PVOID
)RosEntry
->ModStart
;
106 ModSize
= RosEntry
->ModEnd
- (ULONG_PTR
)ModStart
;
108 /* Check if this is any of the NLS files */
109 if (!_stricmp(DriverName
, "ansi.nls"))
112 LoaderBlock
->NlsData
->AnsiCodePageData
= ModStart
;
114 /* Create an MD for it */
115 MdEntry
= &BldrMemoryDescriptors
[i
];
116 MdEntry
->MemoryType
= LoaderNlsData
;
117 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
118 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
119 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
120 &MdEntry
->ListEntry
);
123 else if (!_stricmp(DriverName
, "oem.nls"))
126 LoaderBlock
->NlsData
->OemCodePageData
= ModStart
;
128 /* Create an MD for it */
129 MdEntry
= &BldrMemoryDescriptors
[i
];
130 MdEntry
->MemoryType
= LoaderNlsData
;
131 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
132 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
133 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
134 &MdEntry
->ListEntry
);
137 else if (!_stricmp(DriverName
, "casemap.nls"))
139 /* Unicode Code page */
140 LoaderBlock
->NlsData
->UnicodeCodePageData
= ModStart
;
142 /* Create an MD for it */
143 MdEntry
= &BldrMemoryDescriptors
[i
];
144 MdEntry
->MemoryType
= LoaderNlsData
;
145 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
146 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
147 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
148 &MdEntry
->ListEntry
);
152 /* Check if this is the SYSTEM hive */
153 if (!(_stricmp(DriverName
, "system")) ||
154 !(_stricmp(DriverName
, "system.hiv")))
156 /* Save registry data */
157 LoaderBlock
->RegistryBase
= ModStart
;
158 LoaderBlock
->RegistryLength
= ModSize
;
160 /* Disable setup mode */
161 LoaderBlock
->SetupLdrBlock
= NULL
;
163 /* Create an MD for it */
164 MdEntry
= &BldrMemoryDescriptors
[i
];
165 MdEntry
->MemoryType
= LoaderRegistryData
;
166 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
167 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
168 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
169 &MdEntry
->ListEntry
);
173 /* Check if this is the HARDWARE hive */
174 if (!(_stricmp(DriverName
, "hardware")) ||
175 !(_stricmp(DriverName
, "hardware.hiv")))
177 /* Create an MD for it */
178 MdEntry
= &BldrMemoryDescriptors
[i
];
179 MdEntry
->MemoryType
= LoaderRegistryData
;
180 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
181 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
182 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
183 &MdEntry
->ListEntry
);
187 /* Setup the loader entry */
188 LdrEntry
= &BldrModules
[i
];
189 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
191 /* Convert driver name from ANSI to Unicode */
192 for (j
= 0; j
< strlen(DriverName
); j
++)
194 BldrModuleStrings
[i
][j
] = DriverName
[j
];
197 /* Setup driver name */
198 RtlInitUnicodeString(&LdrEntry
->BaseDllName
, BldrModuleStrings
[i
]);
199 RtlInitUnicodeString(&LdrEntry
->FullDllName
, BldrModuleStrings
[i
]);
201 /* Copy data from Freeldr Module Entry */
202 LdrEntry
->DllBase
= ModStart
;
203 LdrEntry
->SizeOfImage
= ModSize
;
205 /* Initialize other data */
206 LdrEntry
->LoadCount
= 1;
207 LdrEntry
->Flags
= LDRP_IMAGE_DLL
|
208 LDRP_ENTRY_PROCESSED
;
209 if (RosEntry
->Reserved
) LdrEntry
->Flags
|= LDRP_ENTRY_INSERTED
;
211 /* Insert it into the loader block */
212 InsertTailList(&LoaderBlock
->LoadOrderListHead
,
213 &LdrEntry
->InLoadOrderLinks
);
215 /* Check if this is the kernel */
216 if (!(_stricmp(DriverName
, "ntoskrnl.exe")))
218 /* Create an MD for it */
219 MdEntry
= &BldrMemoryDescriptors
[i
];
220 MdEntry
->MemoryType
= LoaderSystemCode
;
221 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
222 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
223 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
224 &MdEntry
->ListEntry
);
226 else if (!(_stricmp(DriverName
, "hal.dll")))
228 /* The HAL actually gets loaded somewhere else */
229 ModStart
= HalModuleObject
.DllBase
;
231 /* Create an MD for the HAL */
232 MdEntry
= &BldrMemoryDescriptors
[i
];
233 MdEntry
->MemoryType
= LoaderHalCode
;
234 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
235 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
236 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
237 &MdEntry
->ListEntry
);
241 /* Create an MD for any driver */
242 MdEntry
= &BldrMemoryDescriptors
[i
];
243 MdEntry
->MemoryType
= LoaderBootDriver
;
244 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
245 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
246 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
247 &MdEntry
->ListEntry
);
251 /* Setup command line */
252 LoaderBlock
->LoadOptions
= BldrCommandLine
;
253 strcpy(BldrCommandLine
, KeLoaderCommandLine
);
255 /* Setup the extension block */
256 LoaderBlock
->Extension
= &BldrExtensionBlock
;
257 LoaderBlock
->Extension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
258 LoaderBlock
->Extension
->MajorVersion
= 5;
259 LoaderBlock
->Extension
->MinorVersion
= 2;
261 /* Now setup the setup block if we have one */
262 if (LoaderBlock
->SetupLdrBlock
)
264 /* All we'll setup right now is the flag for text-mode setup */
265 LoaderBlock
->SetupLdrBlock
->Flags
= 1;
268 /* Make a copy of the command line */
269 strcpy(CommandLine
, LoaderBlock
->LoadOptions
);
271 /* Find the first \, separating the ARC path from NT path */
272 BootPath
= strchr(CommandLine
, '\\');
273 *BootPath
= ANSI_NULL
;
274 strncpy(BldrArcBootPath
, CommandLine
, 63);
275 LoaderBlock
->ArcBootDeviceName
= BldrArcBootPath
;
277 /* The rest of the string is the NT path */
278 HalPath
= strchr(BootPath
+ 1, ' ');
279 *HalPath
= ANSI_NULL
;
280 BldrNtBootPath
[0] = '\\';
281 strncat(BldrNtBootPath
, BootPath
+ 1, 63);
282 strcat(BldrNtBootPath
,"\\");
283 LoaderBlock
->NtBootPathName
= BldrNtBootPath
;
285 /* Set the HAL paths */
286 strncpy(BldrArcHalPath
, BldrArcBootPath
, 63);
287 LoaderBlock
->ArcHalDeviceName
= BldrArcHalPath
;
288 strcpy(BldrNtHalPath
, "\\");
289 LoaderBlock
->NtHalPathName
= BldrNtHalPath
;
291 /* Use this new command line */
292 strncpy(LoaderBlock
->LoadOptions
, HalPath
+ 2, 255);
294 /* Parse it and change every slash to a space */
295 BootPath
= LoaderBlock
->LoadOptions
;
296 do {if (*BootPath
== '/') *BootPath
= ' ';} while (*BootPath
++);
301 KiRosPrepareForSystemStartup(IN ULONG Dummy
,
302 IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock
)
306 ULONG StartKernelBase
;
310 PLOADER_PARAMETER_BLOCK NtLoaderBlock
;
318 __asm__("ori 0,0,0");
319 char *nk
= "ntoskrnl is here";
320 boot_infos_t
*XBootInfo
= (boot_infos_t
*)LoaderBlock
->ArchExtra
;
321 memcpy(&PpcEarlybootInfo
, XBootInfo
, sizeof(PpcEarlybootInfo
));
322 PpcEarlybootInfo
.dispFont
= BootDigits
;
323 BootInfo
= (struct _boot_infos_t
*)&PpcEarlybootInfo
;
324 DrawNumber(BootInfo
, 0x1234abcd, 10, 100);
325 DrawNumber(BootInfo
, (ULONG
)nk
, 10 , 150);
326 DrawString(BootInfo
, nk
, 100, 150);
327 __asm__("ori 0,0,0");
332 /* Load the GDT and IDT */
333 Ke386SetGlobalDescriptorTable(KiGdtDescriptor
);
334 Ke386SetInterruptDescriptorTable(KiIdtDescriptor
);
336 /* Initialize the boot TSS */
338 TssEntry
= &KiBootGdt
[KGDT_TSS
/ sizeof(KGDTENTRY
)];
339 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
340 TssEntry
->HighWord
.Bits
.Pres
= 1;
341 TssEntry
->HighWord
.Bits
.Dpl
= 0;
342 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
343 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
344 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
347 DrawNumber(BootInfo
, 0xb0071f03, 190, 90);
348 DrawNumber(BootInfo
, (ULONG
)BootInfo
, 190, 100);
350 /* Copy the Loader Block Data locally since Low-Memory will be wiped */
351 memcpy(&KeRosLoaderBlock
, LoaderBlock
, sizeof(ROS_LOADER_PARAMETER_BLOCK
));
352 memcpy(&KeLoaderModules
[0],
353 (PVOID
)KeRosLoaderBlock
.ModsAddr
,
354 sizeof(LOADER_MODULE
) * KeRosLoaderBlock
.ModsCount
);
355 KeRosLoaderBlock
.ModsAddr
= (ULONG
)&KeLoaderModules
;
357 /* Check for BIOS memory map */
358 KeMemoryMapRangeCount
= 0;
359 if (KeRosLoaderBlock
.Flags
& MB_FLAGS_MMAP_INFO
)
361 /* We have a memory map from the nice BIOS */
362 size
= *((PULONG
)(KeRosLoaderBlock
.MmapAddr
- sizeof(ULONG
)));
365 /* Map it until we run out of size */
366 while (i
< KeRosLoaderBlock
.MmapLength
)
368 /* Copy into the Kernel Memory Map */
369 memcpy (&KeMemoryMap
[KeMemoryMapRangeCount
],
370 (PVOID
)(KeRosLoaderBlock
.MmapAddr
+ i
),
371 sizeof(ADDRESS_RANGE
));
373 /* Increase Memory Map Count */
374 KeMemoryMapRangeCount
++;
381 KeRosLoaderBlock
.MmapLength
= KeMemoryMapRangeCount
*
382 sizeof(ADDRESS_RANGE
);
383 KeRosLoaderBlock
.MmapAddr
= (ULONG
)KeMemoryMap
;
387 /* Nothing from BIOS */
388 KeRosLoaderBlock
.MmapLength
= 0;
389 KeRosLoaderBlock
.MmapAddr
= (ULONG
)KeMemoryMap
;
392 /* Save the Base Address */
393 MmSystemRangeStart
= (PVOID
)KeRosLoaderBlock
.KernelBase
;
395 /* Set the Command Line */
396 strcpy(KeLoaderCommandLine
, (PCHAR
)LoaderBlock
->CommandLine
);
397 KeRosLoaderBlock
.CommandLine
= (ULONG
)KeLoaderCommandLine
;
399 /* Get the address of ntoskrnl in openfirmware memory */
400 StartKernelBase
= KeLoaderModules
[0].ModStart
;
402 /* Create a block for each module */
403 for (i
= 0; i
< KeRosLoaderBlock
.ModsCount
; i
++)
405 /* Check if we have to copy the path or not */
406 if ((s
= strrchr((PCHAR
)KeLoaderModules
[i
].String
, '/')) != 0)
408 strcpy(KeLoaderModuleStrings
[i
], s
+ 1);
412 strcpy(KeLoaderModuleStrings
[i
], (PCHAR
)KeLoaderModules
[i
].String
);
417 DrawNumber(BootInfo
, KeLoaderModules
[i
].ModStart
, 10, 200);
418 DrawNumber(BootInfo
, KeLoaderModules
[i
].ModEnd
- KeLoaderModules
[i
].ModStart
, 100, 200);
419 DrawNumber(BootInfo
, KeLoaderModules
[i
].ModEnd
, 190, 200);
420 DrawNumber(BootInfo
, KeLoaderModules
[i
+1].ModStart
, 10, 210);
421 DrawNumber(BootInfo
, KeLoaderModules
[i
+1].ModEnd
- KeLoaderModules
[i
+1].ModStart
, 100, 210);
422 DrawNumber(BootInfo
, KeLoaderModules
[i
+1].ModEnd
, 190, 210);
424 KeLoaderModules
[i
].ModStart
+= KSEG0_BASE
- StartKernelBase
;
425 KeLoaderModules
[i
].ModEnd
+= KSEG0_BASE
- StartKernelBase
;
427 /* Substract the base Address in Physical Memory */
428 KeLoaderModules
[i
].ModStart
-= 0x200000;
430 /* Add the Kernel Base Address in Virtual Memory */
431 KeLoaderModules
[i
].ModStart
+= KSEG0_BASE
;
433 /* Substract the base Address in Physical Memory */
434 KeLoaderModules
[i
].ModEnd
-= 0x200000;
436 /* Add the Kernel Base Address in Virtual Memory */
437 KeLoaderModules
[i
].ModEnd
+= KSEG0_BASE
;
440 /* Select the proper String */
441 KeLoaderModules
[i
].String
= (ULONG
)KeLoaderModuleStrings
[i
];
444 /* Choose last module address as the final kernel address */
445 MmFreeLdrLastKernelAddress
=
446 PAGE_ROUND_UP(KeLoaderModules
[KeRosLoaderBlock
.ModsCount
- 1].ModEnd
);
449 /* Select the HAL Base */
450 HalBase
= KeLoaderModules
[1].ModStart
;
452 /* Choose Driver Base */
453 DriverBase
= MmFreeLdrLastKernelAddress
;
454 LdrHalBase
= (ULONG_PTR
)DriverBase
;
456 HalBase
= KeLoaderModules
[1].ModStart
;
457 DriverBase
= MmFreeLdrLastKernelAddress
;
458 LdrHalBase
= KeLoaderModules
[1].ModStart
;
461 /* Initialize Module Management */
462 LdrInitModuleManagement((PVOID
)KeLoaderModules
[0].ModStart
);
464 /* Load HAL.DLL with the PE Loader */
465 LdrSafePEProcessModule((PVOID
)HalBase
,
467 (PVOID
)KeLoaderModules
[0].ModStart
,
472 // HACK HACK HACK WHEN WILL YOU PEOPLE FIX FREELDR?!?!?!
473 // FREELDR SENDS US AN ***INVALID*** HAL PE HEADER!!!
474 // WE READ IT IN LdrInitModuleManagement ABOVE!!!
475 // WE SET .SizeOfImage TO A *GARBAGE* VALUE!!!
477 // This dirty hack fixes it, and should make symbol lookup work too.
479 HalModuleObject
.SizeOfImage
= RtlImageNtHeader((PVOID
)HalModuleObject
.
481 OptionalHeader
.SizeOfImage
;
483 /* Increase the last kernel address with the size of HAL */
484 MmFreeLdrLastKernelAddress
+= PAGE_ROUND_UP(DriverSize
);
487 /* Now select the final beginning and ending Kernel Addresses */
488 MmFreeLdrFirstKrnlPhysAddr
= KeLoaderModules
[0].ModStart
-
489 KSEG0_BASE
+ 0x200000;
490 MmFreeLdrLastKrnlPhysAddr
= MmFreeLdrLastKernelAddress
-
491 KSEG0_BASE
+ 0x200000;
495 KeInitExceptions(); // ONCE HACK BELOW IS GONE, MOVE TO KISYSTEMSTARTUP!
496 KeInitInterrupts(); // ROS HACK DEPRECATED SOON BY NEW HAL
498 /* Load the Kernel with the PE Loader */
499 LdrSafePEProcessModule((PVOID
)KeLoaderModules
[0].ModStart
,
500 (PVOID
)KeLoaderModules
[0].ModStart
,
504 /* Sets up the VDM Data */
509 /* Convert the loader block */
510 KiRosFrldrLpbToNtLpb(&KeRosLoaderBlock
, &NtLoaderBlock
);
512 /* Do general System Startup */
513 KiSystemStartup(NtLoaderBlock
);