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 Memory Data */
18 ULONG_PTR MmFreeLdrFirstKrnlPhysAddr
, MmFreeLdrLastKrnlPhysAddr
;
19 ULONG_PTR MmFreeLdrLastKernelAddress
;
20 ULONG MmFreeLdrMemHigher
;
21 ULONG MmFreeLdrPageDirectoryEnd
;
23 /* FreeLDR Loader Data */
24 PROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock
;
25 BOOLEAN AcpiTableDetected
;
27 /* NT Loader Data. Eats up about 80KB! */
28 LOADER_PARAMETER_BLOCK BldrLoaderBlock
; // 0x0000
29 LOADER_PARAMETER_EXTENSION BldrExtensionBlock
; // 0x0060
30 CHAR BldrCommandLine
[256]; // 0x00DC
31 CHAR BldrArcBootPath
[64]; // 0x01DC
32 CHAR BldrArcHalPath
[64]; // 0x021C
33 CHAR BldrNtHalPath
[64]; // 0x025C
34 CHAR BldrNtBootPath
[64]; // 0x029C
35 LDR_DATA_TABLE_ENTRY BldrModules
[64]; // 0x02DC
36 MEMORY_ALLOCATION_DESCRIPTOR BldrMemoryDescriptors
[64]; // 0x14DC
37 WCHAR BldrModuleStrings
[64][260]; // 0x19DC
38 WCHAR BldrModuleStringsFull
[64][260]; // 0x9BDC
39 NLS_DATA_BLOCK BldrNlsDataBlock
; // 0x11DDC
40 SETUP_LOADER_BLOCK BldrSetupBlock
; // 0x11DE8
41 ARC_DISK_INFORMATION BldrArcDiskInfo
; // 0x12134
42 CHAR BldrArcNames
[32][256]; // 0x1213C
43 ARC_DISK_SIGNATURE BldrDiskInfo
[32]; // 0x1413C
46 /* FUNCTIONS *****************************************************************/
50 KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock
,
51 IN PLOADER_PARAMETER_BLOCK
*NtLoaderBlock
)
53 PLOADER_PARAMETER_BLOCK LoaderBlock
;
54 PLDR_DATA_TABLE_ENTRY LdrEntry
;
55 PMEMORY_ALLOCATION_DESCRIPTOR MdEntry
;
56 PLOADER_MODULE RosEntry
;
60 PCHAR BootPath
, HalPath
;
61 CHAR CommandLine
[256];
62 PARC_DISK_SIGNATURE RosDiskInfo
, ArcDiskInfo
;
63 PIMAGE_NT_HEADERS NtHeader
;
64 WCHAR PathToDrivers
[] = L
"\\SystemRoot\\System32\\drivers\\";
65 WCHAR PathToSystem32
[] = L
"\\SystemRoot\\System32\\";
66 CHAR DriverNameLow
[256];
68 /* First get some kernel-loader globals */
69 AcpiTableDetected
= (RosLoaderBlock
->Flags
& MB_FLAGS_ACPI_TABLE
) ? TRUE
: FALSE
;
70 MmFreeLdrMemHigher
= RosLoaderBlock
->MemHigher
;
71 MmFreeLdrPageDirectoryEnd
= RosLoaderBlock
->PageDirectoryEnd
;
73 /* Set the NT Loader block and initialize it */
74 *NtLoaderBlock
= LoaderBlock
= &BldrLoaderBlock
;
75 RtlZeroMemory(LoaderBlock
, sizeof(LOADER_PARAMETER_BLOCK
));
77 /* Set the NLS Data block */
78 LoaderBlock
->NlsData
= &BldrNlsDataBlock
;
80 /* Set the ARC Data block */
81 LoaderBlock
->ArcDiskInformation
= &BldrArcDiskInfo
;
83 /* Assume this is from FreeLDR's SetupLdr */
84 LoaderBlock
->SetupLdrBlock
= &BldrSetupBlock
;
86 /* Setup the list heads */
87 InitializeListHead(&LoaderBlock
->LoadOrderListHead
);
88 InitializeListHead(&LoaderBlock
->MemoryDescriptorListHead
);
89 InitializeListHead(&LoaderBlock
->BootDriverListHead
);
90 InitializeListHead(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
);
92 /* Loop boot driver list */
93 for (i
= 0; i
< RosLoaderBlock
->ModsCount
; i
++)
95 /* Get the ROS loader entry */
96 RosEntry
= &RosLoaderBlock
->ModsAddr
[i
];
97 DriverName
= (PCHAR
)RosEntry
->String
;
98 ModStart
= (PVOID
)RosEntry
->ModStart
;
99 ModSize
= RosEntry
->ModEnd
- (ULONG_PTR
)ModStart
;
101 /* Check if this is any of the NLS files */
102 if (!_stricmp(DriverName
, "ansi.nls"))
105 ModStart
= (PVOID
)((ULONG_PTR
)ModStart
+ (KSEG0_BASE
- 0x200000));
106 LoaderBlock
->NlsData
->AnsiCodePageData
= ModStart
;
108 /* Create an MD for it */
109 MdEntry
= &BldrMemoryDescriptors
[i
];
110 MdEntry
->MemoryType
= LoaderNlsData
;
111 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
112 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1)>> PAGE_SHIFT
;
113 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
114 &MdEntry
->ListEntry
);
117 else if (!_stricmp(DriverName
, "oem.nls"))
120 ModStart
= (PVOID
)((ULONG_PTR
)ModStart
+ (KSEG0_BASE
- 0x200000));
121 LoaderBlock
->NlsData
->OemCodePageData
= ModStart
;
123 /* Create an MD for it */
124 MdEntry
= &BldrMemoryDescriptors
[i
];
125 MdEntry
->MemoryType
= LoaderNlsData
;
126 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
127 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
128 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
129 &MdEntry
->ListEntry
);
132 else if (!_stricmp(DriverName
, "casemap.nls"))
134 /* Unicode Code page */
135 ModStart
= (PVOID
)((ULONG_PTR
)ModStart
+ (KSEG0_BASE
- 0x200000));
136 LoaderBlock
->NlsData
->UnicodeCodePageData
= ModStart
;
138 /* Create an MD for it */
139 MdEntry
= &BldrMemoryDescriptors
[i
];
140 MdEntry
->MemoryType
= LoaderNlsData
;
141 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
142 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
143 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
144 &MdEntry
->ListEntry
);
148 /* Check if this is the SYSTEM hive */
149 if (!(_stricmp(DriverName
, "system")) ||
150 !(_stricmp(DriverName
, "system.hiv")))
152 /* Save registry data */
153 ModStart
= (PVOID
)((ULONG_PTR
)ModStart
+ (KSEG0_BASE
- 0x200000));
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_SIZE
- 1) >> 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 /* Create an MD for it */
175 ModStart
= (PVOID
)((ULONG_PTR
)ModStart
+ (KSEG0_BASE
- 0x200000));
176 MdEntry
= &BldrMemoryDescriptors
[i
];
177 MdEntry
->MemoryType
= LoaderRegistryData
;
178 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
179 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
180 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
181 &MdEntry
->ListEntry
);
185 /* Check if this is the kernel */
186 if (!(_stricmp(DriverName
, "ntoskrnl.exe")))
188 /* Create an MD for it */
189 MdEntry
= &BldrMemoryDescriptors
[i
];
190 MdEntry
->MemoryType
= LoaderSystemCode
;
191 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
192 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
193 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
194 &MdEntry
->ListEntry
);
196 else if (!(_stricmp(DriverName
, "hal.dll")))
198 /* Create an MD for the HAL */
199 MdEntry
= &BldrMemoryDescriptors
[i
];
200 MdEntry
->MemoryType
= LoaderHalCode
;
201 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
202 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
203 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
204 &MdEntry
->ListEntry
);
208 /* Create an MD for any driver */
209 MdEntry
= &BldrMemoryDescriptors
[i
];
210 MdEntry
->MemoryType
= LoaderBootDriver
;
211 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
212 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
213 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
214 &MdEntry
->ListEntry
);
217 /* Lowercase the drivername so we can check its extension later */
218 strcpy(DriverNameLow
, DriverName
);
219 _strlwr(DriverNameLow
);
221 /* Setup the loader entry */
222 LdrEntry
= &BldrModules
[i
];
223 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
225 /* Convert driver name from ANSI to Unicode */
226 for (j
= 0; j
< strlen(DriverName
); j
++)
228 BldrModuleStrings
[i
][j
] = DriverName
[j
];
231 /* Setup driver name */
232 RtlInitUnicodeString(&LdrEntry
->BaseDllName
, BldrModuleStrings
[i
]);
234 /* Construct a correct full name */
235 BldrModuleStringsFull
[i
][0] = 0;
236 LdrEntry
->FullDllName
.MaximumLength
= 260 * sizeof(WCHAR
);
237 LdrEntry
->FullDllName
.Length
= 0;
238 LdrEntry
->FullDllName
.Buffer
= BldrModuleStringsFull
[i
];
241 if (strstr(DriverNameLow
, ".dll") || strstr(DriverNameLow
, ".exe"))
243 UNICODE_STRING TempString
;
244 RtlInitUnicodeString(&TempString
, PathToSystem32
);
245 RtlAppendUnicodeStringToString(&LdrEntry
->FullDllName
, &TempString
);
249 UNICODE_STRING TempString
;
250 RtlInitUnicodeString(&TempString
, PathToDrivers
);
251 RtlAppendUnicodeStringToString(&LdrEntry
->FullDllName
, &TempString
);
254 /* Append base name of the driver */
255 RtlAppendUnicodeStringToString(&LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
257 /* Copy data from Freeldr Module Entry */
258 LdrEntry
->DllBase
= ModStart
;
259 LdrEntry
->SizeOfImage
= ModSize
;
261 /* Copy additional data */
262 NtHeader
= RtlImageNtHeader(ModStart
);
263 LdrEntry
->EntryPoint
= RVA(ModStart
,
265 OptionalHeader
.AddressOfEntryPoint
);
267 /* Initialize other data */
268 LdrEntry
->LoadCount
= 1;
269 LdrEntry
->Flags
= LDRP_IMAGE_DLL
|
270 LDRP_ENTRY_PROCESSED
;
271 if (RosEntry
->Reserved
) LdrEntry
->Flags
|= LDRP_ENTRY_INSERTED
;
273 /* Insert it into the loader block */
274 InsertTailList(&LoaderBlock
->LoadOrderListHead
,
275 &LdrEntry
->InLoadOrderLinks
);
278 /* Setup command line */
279 LoaderBlock
->LoadOptions
= BldrCommandLine
;
280 strcpy(BldrCommandLine
, RosLoaderBlock
->CommandLine
);
282 /* Setup the extension block */
283 LoaderBlock
->Extension
= &BldrExtensionBlock
;
284 LoaderBlock
->Extension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
285 LoaderBlock
->Extension
->MajorVersion
= 5;
286 LoaderBlock
->Extension
->MinorVersion
= 2;
288 /* Now setup the setup block if we have one */
289 if (LoaderBlock
->SetupLdrBlock
)
291 /* All we'll setup right now is the flag for text-mode setup */
292 LoaderBlock
->SetupLdrBlock
->Flags
= 1;
295 /* Make a copy of the command line */
296 strcpy(CommandLine
, LoaderBlock
->LoadOptions
);
298 /* Find the first \, separating the ARC path from NT path */
299 BootPath
= strchr(CommandLine
, '\\');
300 *BootPath
= ANSI_NULL
;
301 strncpy(BldrArcBootPath
, CommandLine
, 63);
302 LoaderBlock
->ArcBootDeviceName
= BldrArcBootPath
;
304 /* The rest of the string is the NT path */
305 HalPath
= strchr(BootPath
+ 1, ' ');
306 *HalPath
= ANSI_NULL
;
307 BldrNtBootPath
[0] = '\\';
308 strncat(BldrNtBootPath
, BootPath
+ 1, 63);
309 strcat(BldrNtBootPath
,"\\");
310 LoaderBlock
->NtBootPathName
= BldrNtBootPath
;
312 /* Set the HAL paths */
313 strncpy(BldrArcHalPath
, BldrArcBootPath
, 63);
314 LoaderBlock
->ArcHalDeviceName
= BldrArcHalPath
;
315 strcpy(BldrNtHalPath
, "\\");
316 LoaderBlock
->NtHalPathName
= BldrNtHalPath
;
318 /* Use this new command line */
319 strncpy(LoaderBlock
->LoadOptions
, HalPath
+ 2, 255);
321 /* Parse it and change every slash to a space */
322 BootPath
= LoaderBlock
->LoadOptions
;
323 do {if (*BootPath
== '/') *BootPath
= ' ';} while (*BootPath
++);
325 /* Now let's loop ARC disk information */
326 for (i
= 0; i
< RosLoaderBlock
->DrivesCount
; i
++)
328 /* Get the ROS loader entry */
329 RosDiskInfo
= &RosLoaderBlock
->DrivesAddr
[i
];
331 /* Get the ARC structure */
332 ArcDiskInfo
= &BldrDiskInfo
[i
];
334 /* Copy the data over */
335 ArcDiskInfo
->Signature
= RosDiskInfo
->Signature
;
336 ArcDiskInfo
->CheckSum
= RosDiskInfo
->CheckSum
;
338 /* Copy the ARC Name */
339 strcpy(BldrArcNames
[i
], RosDiskInfo
->ArcName
);
340 ArcDiskInfo
->ArcName
= BldrArcNames
[i
];
342 /* Insert into the list */
343 InsertTailList(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
,
344 &ArcDiskInfo
->ListEntry
);
350 KiRosPrepareForSystemStartup(IN ULONG Dummy
,
351 IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock
)
353 PLOADER_PARAMETER_BLOCK NtLoaderBlock
;
358 /* Load the GDT and IDT */
359 Ke386SetGlobalDescriptorTable(*(PKDESCRIPTOR
)&KiGdtDescriptor
.Limit
);
360 Ke386SetInterruptDescriptorTable(*(PKDESCRIPTOR
)&KiIdtDescriptor
.Limit
);
362 /* Initialize the boot TSS */
364 TssEntry
= &KiBootGdt
[KGDT_TSS
/ sizeof(KGDTENTRY
)];
365 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
366 TssEntry
->HighWord
.Bits
.Pres
= 1;
367 TssEntry
->HighWord
.Bits
.Dpl
= 0;
368 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
369 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
370 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
373 /* Save pointer to ROS Block */
374 KeRosLoaderBlock
= LoaderBlock
;
376 /* Save memory manager data */
377 MmFreeLdrLastKernelAddress
= PAGE_ROUND_UP(KeRosLoaderBlock
->
378 ModsAddr
[KeRosLoaderBlock
->
381 MmFreeLdrFirstKrnlPhysAddr
= KeRosLoaderBlock
->ModsAddr
[0].ModStart
-
382 KSEG0_BASE
+ 0x200000;
383 MmFreeLdrLastKrnlPhysAddr
= MmFreeLdrLastKernelAddress
-
384 KSEG0_BASE
+ 0x200000;
387 /* Set up the VDM Data */
391 /* Convert the loader block */
392 KiRosFrldrLpbToNtLpb(KeRosLoaderBlock
, &NtLoaderBlock
);
394 /* Do general System Startup */
395 KiSystemStartup(NtLoaderBlock
);