Copy i8042prt driver from 0.3.1 branch to trunk
[reactos.git] / reactos / ntoskrnl / ke / freeldr.c
1 /*
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)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 /* FreeLDR Module Data */
18 LOADER_MODULE KeLoaderModules[64];
19 ULONG KeLoaderModuleCount;
20 static CHAR KeLoaderModuleStrings[64][256];
21 PLOADER_MODULE CachedModules[MaximumCachedModuleType];
22
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;
31
32 /* FreeLDR Loader Data */
33 ROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock;
34 static CHAR KeLoaderCommandLine[256];
35 BOOLEAN AcpiTableDetected;
36
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;
41
42 /* NT Loader Data */
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;
55
56 /* FUNCTIONS *****************************************************************/
57
58 VOID
59 NTAPI
60 KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
61 IN PLOADER_PARAMETER_BLOCK *NtLoaderBlock)
62 {
63 PLOADER_PARAMETER_BLOCK LoaderBlock;
64 PLDR_DATA_TABLE_ENTRY LdrEntry;
65 PMEMORY_ALLOCATION_DESCRIPTOR MdEntry;
66 PLOADER_MODULE RosEntry;
67 ULONG i, j, ModSize;
68 PVOID ModStart;
69 PCHAR DriverName;
70 PCHAR BootPath, HalPath;
71 CHAR CommandLine[256];
72
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;
80
81 /* Set the NT Loader block and initialize it */
82 *NtLoaderBlock = LoaderBlock = &BldrLoaderBlock;
83 RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
84
85 /* Set the NLS Data block */
86 LoaderBlock->NlsData = &BldrNlsDataBlock;
87
88 /* Assume this is from FreeLDR's SetupLdr */
89 LoaderBlock->SetupLdrBlock = &BldrSetupBlock;
90
91 /* Setup the list heads */
92 InitializeListHead(&LoaderBlock->LoadOrderListHead);
93 InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
94 InitializeListHead(&LoaderBlock->BootDriverListHead);
95
96 /* Loop boot driver list */
97 for (i = 0; i < KeLoaderModuleCount; i++)
98 {
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;
104
105 /* Check if this is any of the NLS files */
106 if (!_stricmp(DriverName, "ansi.nls"))
107 {
108 /* ANSI Code page */
109 LoaderBlock->NlsData->AnsiCodePageData = ModStart;
110
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);
118 continue;
119 }
120 else if (!_stricmp(DriverName, "oem.nls"))
121 {
122 /* OEM Code page */
123 LoaderBlock->NlsData->OemCodePageData = ModStart;
124
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);
132 continue;
133 }
134 else if (!_stricmp(DriverName, "casemap.nls"))
135 {
136 /* Unicode Code page */
137 LoaderBlock->NlsData->UnicodeCodePageData = ModStart;
138
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);
146 continue;
147 }
148
149 /* Check if this is the SYSTEM hive */
150 if (!(_stricmp(DriverName, "system")) ||
151 !(_stricmp(DriverName, "system.hiv")))
152 {
153 /* Save registry data */
154 LoaderBlock->RegistryBase = ModStart;
155 LoaderBlock->RegistryLength = ModSize;
156
157 /* Disable setup mode */
158 LoaderBlock->SetupLdrBlock = NULL;
159
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);
167 continue;
168 }
169
170 /* Check if this is the HARDWARE hive */
171 if (!(_stricmp(DriverName, "hardware")) ||
172 !(_stricmp(DriverName, "hardware.hiv")))
173 {
174 /* Save registry data */
175 LoaderBlock->RegistryBase = ModStart;
176 LoaderBlock->RegistryLength = ModSize;
177
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);
185 continue;
186 }
187
188 /* Setup the loader entry */
189 LdrEntry = &BldrModules[i];
190 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
191
192 /* Convert driver name from ANSI to Unicode */
193 for (j = 0; j < strlen(DriverName); j++)
194 {
195 BldrModuleStrings[i][j] = DriverName[j];
196 }
197
198 /* Setup driver name */
199 RtlInitUnicodeString(&LdrEntry->BaseDllName, BldrModuleStrings[i]);
200 RtlInitUnicodeString(&LdrEntry->FullDllName, BldrModuleStrings[i]);
201
202 /* Copy data from Freeldr Module Entry */
203 LdrEntry->DllBase = ModStart;
204 LdrEntry->SizeOfImage = ModSize;
205
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;
211
212 /* Insert it into the loader block */
213 InsertTailList(&LoaderBlock->LoadOrderListHead,
214 &LdrEntry->InLoadOrderLinks);
215
216 /* Check if this is the kernel */
217 if (!(_stricmp(DriverName, "ntoskrnl.exe")))
218 {
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);
226 }
227 else if (!(_stricmp(DriverName, "hal.dll")))
228 {
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);
236 }
237 else
238 {
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);
246 }
247 }
248
249 /* Setup command line */
250 LoaderBlock->LoadOptions = BldrCommandLine;
251 strcpy(BldrCommandLine, KeLoaderCommandLine);
252
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;
258
259 /* Now setup the setup block if we have one */
260 if (LoaderBlock->SetupLdrBlock)
261 {
262 /* All we'll setup right now is the flag for text-mode setup */
263 LoaderBlock->SetupLdrBlock->Flags = 1;
264 }
265
266 /* Make a copy of the command line */
267 strcpy(CommandLine, LoaderBlock->LoadOptions);
268
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;
274
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;
282
283 /* Set the HAL paths */
284 strncpy(BldrArcHalPath, BldrArcBootPath, 63);
285 LoaderBlock->ArcHalDeviceName = BldrArcHalPath;
286 strcpy(BldrNtHalPath, "\\");
287 LoaderBlock->NtHalPathName = BldrNtHalPath;
288
289 /* Use this new command line */
290 strncpy(LoaderBlock->LoadOptions, HalPath + 2, 255);
291
292 /* Parse it and change every slash to a space */
293 BootPath = LoaderBlock->LoadOptions;
294 do {if (*BootPath == '/') *BootPath = ' ';} while (*BootPath++);
295 }
296
297 VOID
298 FASTCALL
299 KiRosPrepareForSystemStartup(IN ULONG Dummy,
300 IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock)
301 {
302 ULONG i;
303 ULONG size;
304 ULONG HalBase;
305 ULONG DriverBase;
306 ULONG DriverSize;
307 PIMAGE_NT_HEADERS NtHeader;
308 PIMAGE_OPTIONAL_HEADER OptHead;
309 PLOADER_PARAMETER_BLOCK NtLoaderBlock;
310 CHAR* s;
311 PKTSS Tss;
312 PKGDTENTRY TssEntry;
313
314 /* Load the GDT and IDT */
315 Ke386SetGlobalDescriptorTable(KiGdtDescriptor);
316 Ke386SetInterruptDescriptorTable(KiIdtDescriptor);
317
318 /* Initialize the boot TSS */
319 Tss = &KiBootTss;
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);
327
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;
335
336 /* Check for BIOS memory map */
337 KeMemoryMapRangeCount = 0;
338 if (KeRosLoaderBlock.Flags & MB_FLAGS_MMAP_INFO)
339 {
340 /* We have a memory map from the nice BIOS */
341 size = *((PULONG)(KeRosLoaderBlock.MmapAddr - sizeof(ULONG)));
342 i = 0;
343
344 /* Map it until we run out of size */
345 while (i < KeRosLoaderBlock.MmapLength)
346 {
347 /* Copy into the Kernel Memory Map */
348 memcpy (&KeMemoryMap[KeMemoryMapRangeCount],
349 (PVOID)(KeRosLoaderBlock.MmapAddr + i),
350 sizeof(ADDRESS_RANGE));
351
352 /* Increase Memory Map Count */
353 KeMemoryMapRangeCount++;
354
355 /* Increase Size */
356 i += size;
357 }
358
359 /* Save data */
360 KeRosLoaderBlock.MmapLength = KeMemoryMapRangeCount *
361 sizeof(ADDRESS_RANGE);
362 KeRosLoaderBlock.MmapAddr = (ULONG)KeMemoryMap;
363 }
364 else
365 {
366 /* Nothing from BIOS */
367 KeRosLoaderBlock.MmapLength = 0;
368 KeRosLoaderBlock.MmapAddr = (ULONG)KeMemoryMap;
369 }
370
371 /* Save the Base Address */
372 MmSystemRangeStart = (PVOID)KeRosLoaderBlock.KernelBase;
373
374 /* Set the Command Line */
375 strcpy(KeLoaderCommandLine, (PCHAR)LoaderBlock->CommandLine);
376 KeRosLoaderBlock.CommandLine = (ULONG)KeLoaderCommandLine;
377
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;
382
383 /* Read PE Data */
384 NtHeader = RtlImageNtHeader((PVOID)KeLoaderModules[0].ModStart);
385 OptHead = &NtHeader->OptionalHeader;
386
387 /* Set Kernel Ending */
388 KeLoaderModules[0].ModEnd = KeLoaderModules[0].ModStart +
389 PAGE_ROUND_UP((ULONG)OptHead->SizeOfImage);
390
391 /* Create a block for each module */
392 for (i = 1; i < KeRosLoaderBlock.ModsCount; i++)
393 {
394 /* Check if we have to copy the path or not */
395 if ((s = strrchr((PCHAR)KeLoaderModules[i].String, '/')) != 0)
396 {
397 strcpy(KeLoaderModuleStrings[i], s + 1);
398 }
399 else
400 {
401 strcpy(KeLoaderModuleStrings[i], (PCHAR)KeLoaderModules[i].String);
402 }
403
404 /* Substract the base Address in Physical Memory */
405 KeLoaderModules[i].ModStart -= 0x200000;
406
407 /* Add the Kernel Base Address in Virtual Memory */
408 KeLoaderModules[i].ModStart += KERNEL_BASE;
409
410 /* Substract the base Address in Physical Memory */
411 KeLoaderModules[i].ModEnd -= 0x200000;
412
413 /* Add the Kernel Base Address in Virtual Memory */
414 KeLoaderModules[i].ModEnd += KERNEL_BASE;
415
416 /* Select the proper String */
417 KeLoaderModules[i].String = (ULONG)KeLoaderModuleStrings[i];
418 }
419
420 /* Choose last module address as the final kernel address */
421 LastKernelAddress = PAGE_ROUND_UP(KeLoaderModules[KeRosLoaderBlock.
422 ModsCount - 1].ModEnd);
423
424 /* Select the HAL Base */
425 HalBase = KeLoaderModules[1].ModStart;
426
427 /* Choose Driver Base */
428 DriverBase = LastKernelAddress;
429 LdrHalBase = (ULONG_PTR)DriverBase;
430
431 /* Initialize Module Management */
432 LdrInitModuleManagement();
433
434 /* Load HAL.DLL with the PE Loader */
435 LdrSafePEProcessModule((PVOID)HalBase,
436 (PVOID)DriverBase,
437 (PVOID)KERNEL_BASE,
438 &DriverSize);
439
440 //
441 //
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!!!
446 //
447 // This dirty hack fixes it, and should make symbol lookup work too.
448 //
449 HalModuleObject.SizeOfImage = RtlImageNtHeader((PVOID)HalModuleObject.
450 DllBase)->
451 OptionalHeader.SizeOfImage;
452
453 /* Increase the last kernel address with the size of HAL */
454 LastKernelAddress += PAGE_ROUND_UP(DriverSize);
455
456 /* Now select the final beginning and ending Kernel Addresses */
457 FirstKrnlPhysAddr = KeLoaderModules[0].ModStart - KERNEL_BASE + 0x200000;
458 LastKrnlPhysAddr = LastKernelAddress - KERNEL_BASE + 0x200000;
459
460 /* Setup the IDT */
461 KeInitExceptions(); // ONCE HACK BELOW IS GONE, MOVE TO KISYSTEMSTARTUP!
462 KeInitInterrupts(); // ROS HACK DEPRECATED SOON BY NEW HAL
463
464 /* Load the Kernel with the PE Loader */
465 LdrSafePEProcessModule((PVOID)KERNEL_BASE,
466 (PVOID)KERNEL_BASE,
467 (PVOID)DriverBase,
468 &DriverSize);
469
470 /* Sets up the VDM Data */
471 NtEarlyInitVdm();
472
473 /* Convert the loader block */
474 KiRosFrldrLpbToNtLpb(&KeRosLoaderBlock, &NtLoaderBlock);
475
476 /* Do general System Startup */
477 KiSystemStartup(NtLoaderBlock);
478 }
479
480 /* EOF */