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 50KB! */
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 NLS_DATA_BLOCK BldrNlsDataBlock
; // 0x9BDC
39 SETUP_LOADER_BLOCK BldrSetupBlock
; // 0x9BE8
40 ARC_DISK_INFORMATION BldrArcDiskInfo
; // 0x9F34
41 CHAR BldrArcNames
[32][256]; // 0x9F3C
42 ARC_DISK_SIGNATURE BldrDiskInfo
[32]; // 0xBF3C
45 /* FUNCTIONS *****************************************************************/
49 KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock
,
50 IN PLOADER_PARAMETER_BLOCK
*NtLoaderBlock
)
52 PLOADER_PARAMETER_BLOCK LoaderBlock
;
53 PLDR_DATA_TABLE_ENTRY LdrEntry
;
54 PMEMORY_ALLOCATION_DESCRIPTOR MdEntry
;
55 PLOADER_MODULE RosEntry
;
59 PCHAR BootPath
, HalPath
;
60 CHAR CommandLine
[256];
61 PARC_DISK_SIGNATURE RosDiskInfo
, ArcDiskInfo
;
62 PIMAGE_NT_HEADERS NtHeader
;
64 /* First get some kernel-loader globals */
65 AcpiTableDetected
= (RosLoaderBlock
->Flags
& MB_FLAGS_ACPI_TABLE
) ? TRUE
: FALSE
;
66 MmFreeLdrMemHigher
= RosLoaderBlock
->MemHigher
;
67 MmFreeLdrPageDirectoryEnd
= RosLoaderBlock
->PageDirectoryEnd
;
69 /* Set the NT Loader block and initialize it */
70 *NtLoaderBlock
= LoaderBlock
= &BldrLoaderBlock
;
71 RtlZeroMemory(LoaderBlock
, sizeof(LOADER_PARAMETER_BLOCK
));
73 /* Set the NLS Data block */
74 LoaderBlock
->NlsData
= &BldrNlsDataBlock
;
76 /* Set the ARC Data block */
77 LoaderBlock
->ArcDiskInformation
= &BldrArcDiskInfo
;
79 /* Assume this is from FreeLDR's SetupLdr */
80 LoaderBlock
->SetupLdrBlock
= &BldrSetupBlock
;
82 /* Setup the list heads */
83 InitializeListHead(&LoaderBlock
->LoadOrderListHead
);
84 InitializeListHead(&LoaderBlock
->MemoryDescriptorListHead
);
85 InitializeListHead(&LoaderBlock
->BootDriverListHead
);
86 InitializeListHead(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
);
88 /* Loop boot driver list */
89 for (i
= 0; i
< RosLoaderBlock
->ModsCount
; i
++)
91 /* Get the ROS loader entry */
92 RosEntry
= &RosLoaderBlock
->ModsAddr
[i
];
93 DriverName
= (PCHAR
)RosEntry
->String
;
94 ModStart
= (PVOID
)RosEntry
->ModStart
;
95 ModSize
= RosEntry
->ModEnd
- (ULONG_PTR
)ModStart
;
97 /* Check if this is any of the NLS files */
98 if (!_stricmp(DriverName
, "ansi.nls"))
101 LoaderBlock
->NlsData
->AnsiCodePageData
= ModStart
;
103 /* Create an MD for it */
104 MdEntry
= &BldrMemoryDescriptors
[i
];
105 MdEntry
->MemoryType
= LoaderNlsData
;
106 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
107 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
108 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
109 &MdEntry
->ListEntry
);
112 else if (!_stricmp(DriverName
, "oem.nls"))
115 LoaderBlock
->NlsData
->OemCodePageData
= ModStart
;
117 /* Create an MD for it */
118 MdEntry
= &BldrMemoryDescriptors
[i
];
119 MdEntry
->MemoryType
= LoaderNlsData
;
120 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
121 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
122 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
123 &MdEntry
->ListEntry
);
126 else if (!_stricmp(DriverName
, "casemap.nls"))
128 /* Unicode Code page */
129 LoaderBlock
->NlsData
->UnicodeCodePageData
= ModStart
;
131 /* Create an MD for it */
132 MdEntry
= &BldrMemoryDescriptors
[i
];
133 MdEntry
->MemoryType
= LoaderNlsData
;
134 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
135 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
136 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
137 &MdEntry
->ListEntry
);
141 /* Check if this is the SYSTEM hive */
142 if (!(_stricmp(DriverName
, "system")) ||
143 !(_stricmp(DriverName
, "system.hiv")))
145 /* Save registry data */
146 LoaderBlock
->RegistryBase
= ModStart
;
147 LoaderBlock
->RegistryLength
= ModSize
;
149 /* Disable setup mode */
150 LoaderBlock
->SetupLdrBlock
= NULL
;
152 /* Create an MD for it */
153 MdEntry
= &BldrMemoryDescriptors
[i
];
154 MdEntry
->MemoryType
= LoaderRegistryData
;
155 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
156 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
157 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
158 &MdEntry
->ListEntry
);
162 /* Check if this is the HARDWARE hive */
163 if (!(_stricmp(DriverName
, "hardware")) ||
164 !(_stricmp(DriverName
, "hardware.hiv")))
166 /* Create an MD for it */
167 MdEntry
= &BldrMemoryDescriptors
[i
];
168 MdEntry
->MemoryType
= LoaderRegistryData
;
169 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
170 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
171 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
172 &MdEntry
->ListEntry
);
176 /* Check if this is the kernel */
177 if (!(_stricmp(DriverName
, "ntoskrnl.exe")))
179 /* Create an MD for it */
180 MdEntry
= &BldrMemoryDescriptors
[i
];
181 MdEntry
->MemoryType
= LoaderSystemCode
;
182 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
183 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
184 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
185 &MdEntry
->ListEntry
);
187 else if (!(_stricmp(DriverName
, "hal.dll")))
189 /* Create an MD for the HAL */
190 MdEntry
= &BldrMemoryDescriptors
[i
];
191 MdEntry
->MemoryType
= LoaderHalCode
;
192 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
193 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
194 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
195 &MdEntry
->ListEntry
);
199 /* Create an MD for any driver */
200 MdEntry
= &BldrMemoryDescriptors
[i
];
201 MdEntry
->MemoryType
= LoaderBootDriver
;
202 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
203 MdEntry
->PageCount
= ModSize
>> PAGE_SHIFT
;
204 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
205 &MdEntry
->ListEntry
);
208 /* Setup the loader entry */
209 LdrEntry
= &BldrModules
[i
];
210 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
212 /* Convert driver name from ANSI to Unicode */
213 for (j
= 0; j
< strlen(DriverName
); j
++)
215 BldrModuleStrings
[i
][j
] = DriverName
[j
];
218 /* Setup driver name */
219 RtlInitUnicodeString(&LdrEntry
->BaseDllName
, BldrModuleStrings
[i
]);
220 RtlInitUnicodeString(&LdrEntry
->FullDllName
, BldrModuleStrings
[i
]);
222 /* Copy data from Freeldr Module Entry */
223 LdrEntry
->DllBase
= ModStart
;
224 LdrEntry
->SizeOfImage
= ModSize
;
226 /* Copy additional data */
227 NtHeader
= RtlImageNtHeader(ModStart
);
228 LdrEntry
->EntryPoint
= RVA(ModStart
,
230 OptionalHeader
.AddressOfEntryPoint
);
232 /* Initialize other data */
233 LdrEntry
->LoadCount
= 1;
234 LdrEntry
->Flags
= LDRP_IMAGE_DLL
|
235 LDRP_ENTRY_PROCESSED
;
236 if (RosEntry
->Reserved
) LdrEntry
->Flags
|= LDRP_ENTRY_INSERTED
;
238 /* Insert it into the loader block */
239 InsertTailList(&LoaderBlock
->LoadOrderListHead
,
240 &LdrEntry
->InLoadOrderLinks
);
243 /* Setup command line */
244 LoaderBlock
->LoadOptions
= BldrCommandLine
;
245 strcpy(BldrCommandLine
, RosLoaderBlock
->CommandLine
);
247 /* Setup the extension block */
248 LoaderBlock
->Extension
= &BldrExtensionBlock
;
249 LoaderBlock
->Extension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
250 LoaderBlock
->Extension
->MajorVersion
= 5;
251 LoaderBlock
->Extension
->MinorVersion
= 2;
253 /* Now setup the setup block if we have one */
254 if (LoaderBlock
->SetupLdrBlock
)
256 /* All we'll setup right now is the flag for text-mode setup */
257 LoaderBlock
->SetupLdrBlock
->Flags
= 1;
260 /* Make a copy of the command line */
261 strcpy(CommandLine
, LoaderBlock
->LoadOptions
);
263 /* Find the first \, separating the ARC path from NT path */
264 BootPath
= strchr(CommandLine
, '\\');
265 *BootPath
= ANSI_NULL
;
266 strncpy(BldrArcBootPath
, CommandLine
, 63);
267 LoaderBlock
->ArcBootDeviceName
= BldrArcBootPath
;
269 /* The rest of the string is the NT path */
270 HalPath
= strchr(BootPath
+ 1, ' ');
271 *HalPath
= ANSI_NULL
;
272 BldrNtBootPath
[0] = '\\';
273 strncat(BldrNtBootPath
, BootPath
+ 1, 63);
274 strcat(BldrNtBootPath
,"\\");
275 LoaderBlock
->NtBootPathName
= BldrNtBootPath
;
277 /* Set the HAL paths */
278 strncpy(BldrArcHalPath
, BldrArcBootPath
, 63);
279 LoaderBlock
->ArcHalDeviceName
= BldrArcHalPath
;
280 strcpy(BldrNtHalPath
, "\\");
281 LoaderBlock
->NtHalPathName
= BldrNtHalPath
;
283 /* Use this new command line */
284 strncpy(LoaderBlock
->LoadOptions
, HalPath
+ 2, 255);
286 /* Parse it and change every slash to a space */
287 BootPath
= LoaderBlock
->LoadOptions
;
288 do {if (*BootPath
== '/') *BootPath
= ' ';} while (*BootPath
++);
290 /* Now let's loop ARC disk information */
291 for (i
= 0; i
< RosLoaderBlock
->DrivesCount
; i
++)
293 /* Get the ROS loader entry */
294 RosDiskInfo
= &RosLoaderBlock
->DrivesAddr
[i
];
296 /* Get the ARC structure */
297 ArcDiskInfo
= &BldrDiskInfo
[i
];
299 /* Copy the data over */
300 ArcDiskInfo
->Signature
= RosDiskInfo
->Signature
;
301 ArcDiskInfo
->CheckSum
= RosDiskInfo
->CheckSum
;
303 /* Copy the ARC Name */
304 strcpy(BldrArcNames
[i
], RosDiskInfo
->ArcName
);
305 ArcDiskInfo
->ArcName
= BldrArcNames
[i
];
307 /* Insert into the list */
308 InsertTailList(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
,
309 &ArcDiskInfo
->ListEntry
);
315 KiRosPrepareForSystemStartup(IN ULONG Dummy
,
316 IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock
)
319 PLOADER_PARAMETER_BLOCK NtLoaderBlock
;
323 /* Load the GDT and IDT */
324 Ke386SetGlobalDescriptorTable(KiGdtDescriptor
);
325 Ke386SetInterruptDescriptorTable(KiIdtDescriptor
);
327 /* Initialize the boot TSS */
329 TssEntry
= &KiBootGdt
[KGDT_TSS
/ sizeof(KGDTENTRY
)];
330 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
331 TssEntry
->HighWord
.Bits
.Pres
= 1;
332 TssEntry
->HighWord
.Bits
.Dpl
= 0;
333 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
334 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
335 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
337 /* Save pointer to ROS Block */
338 KeRosLoaderBlock
= LoaderBlock
;
340 /* Save the Base Address */
341 MmSystemRangeStart
= (PVOID
)KeRosLoaderBlock
->KernelBase
;
343 /* Convert every driver address to virtual memory */
344 for (i
= 3; i
< KeRosLoaderBlock
->ModsCount
; i
++)
346 /* Subtract the base Address in Physical Memory */
347 KeRosLoaderBlock
->ModsAddr
[i
].ModStart
-= 0x200000;
349 /* Add the Kernel Base Address in Virtual Memory */
350 KeRosLoaderBlock
->ModsAddr
[i
].ModStart
+= KSEG0_BASE
;
352 /* Subtract the base Address in Physical Memory */
353 KeRosLoaderBlock
->ModsAddr
[i
].ModEnd
-= 0x200000;
355 /* Add the Kernel Base Address in Virtual Memory */
356 KeRosLoaderBlock
->ModsAddr
[i
].ModEnd
+= KSEG0_BASE
;
359 /* Save memory manager data */
360 MmFreeLdrLastKernelAddress
= PAGE_ROUND_UP(KeRosLoaderBlock
->
361 ModsAddr
[KeRosLoaderBlock
->
364 MmFreeLdrFirstKrnlPhysAddr
= KeRosLoaderBlock
->ModsAddr
[0].ModStart
-
365 KSEG0_BASE
+ 0x200000;
366 MmFreeLdrLastKrnlPhysAddr
= MmFreeLdrLastKernelAddress
-
367 KSEG0_BASE
+ 0x200000;
369 /* Set up the VDM Data */
372 /* Convert the loader block */
373 KiRosFrldrLpbToNtLpb(KeRosLoaderBlock
, &NtLoaderBlock
);
375 /* Do general System Startup */
376 KiSystemStartup(NtLoaderBlock
);