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 ModStart
= (PVOID
)((ULONG_PTR
)ModStart
+ (KSEG0_BASE
- 0x200000));
102 LoaderBlock
->NlsData
->AnsiCodePageData
= ModStart
;
104 /* Create an MD for it */
105 MdEntry
= &BldrMemoryDescriptors
[i
];
106 MdEntry
->MemoryType
= LoaderNlsData
;
107 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
108 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1)>> PAGE_SHIFT
;
109 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
110 &MdEntry
->ListEntry
);
113 else if (!_stricmp(DriverName
, "oem.nls"))
116 ModStart
= (PVOID
)((ULONG_PTR
)ModStart
+ (KSEG0_BASE
- 0x200000));
117 LoaderBlock
->NlsData
->OemCodePageData
= ModStart
;
119 /* Create an MD for it */
120 MdEntry
= &BldrMemoryDescriptors
[i
];
121 MdEntry
->MemoryType
= LoaderNlsData
;
122 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
123 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
124 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
125 &MdEntry
->ListEntry
);
128 else if (!_stricmp(DriverName
, "casemap.nls"))
130 /* Unicode Code page */
131 ModStart
= (PVOID
)((ULONG_PTR
)ModStart
+ (KSEG0_BASE
- 0x200000));
132 LoaderBlock
->NlsData
->UnicodeCodePageData
= ModStart
;
134 /* Create an MD for it */
135 MdEntry
= &BldrMemoryDescriptors
[i
];
136 MdEntry
->MemoryType
= LoaderNlsData
;
137 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
138 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
139 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
140 &MdEntry
->ListEntry
);
144 /* Check if this is the SYSTEM hive */
145 if (!(_stricmp(DriverName
, "system")) ||
146 !(_stricmp(DriverName
, "system.hiv")))
148 /* Save registry data */
149 ModStart
= (PVOID
)((ULONG_PTR
)ModStart
+ (KSEG0_BASE
- 0x200000));
150 LoaderBlock
->RegistryBase
= ModStart
;
151 LoaderBlock
->RegistryLength
= ModSize
;
153 /* Disable setup mode */
154 LoaderBlock
->SetupLdrBlock
= NULL
;
156 /* Create an MD for it */
157 MdEntry
= &BldrMemoryDescriptors
[i
];
158 MdEntry
->MemoryType
= LoaderRegistryData
;
159 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
160 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
161 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
162 &MdEntry
->ListEntry
);
166 /* Check if this is the HARDWARE hive */
167 if (!(_stricmp(DriverName
, "hardware")) ||
168 !(_stricmp(DriverName
, "hardware.hiv")))
170 /* Create an MD for it */
171 ModStart
= (PVOID
)((ULONG_PTR
)ModStart
+ (KSEG0_BASE
- 0x200000));
172 MdEntry
= &BldrMemoryDescriptors
[i
];
173 MdEntry
->MemoryType
= LoaderRegistryData
;
174 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
175 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
176 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
177 &MdEntry
->ListEntry
);
181 /* Check if this is the kernel */
182 if (!(_stricmp(DriverName
, "ntoskrnl.exe")))
184 /* Create an MD for it */
185 MdEntry
= &BldrMemoryDescriptors
[i
];
186 MdEntry
->MemoryType
= LoaderSystemCode
;
187 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
188 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
189 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
190 &MdEntry
->ListEntry
);
192 else if (!(_stricmp(DriverName
, "hal.dll")))
194 /* Create an MD for the HAL */
195 MdEntry
= &BldrMemoryDescriptors
[i
];
196 MdEntry
->MemoryType
= LoaderHalCode
;
197 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
198 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
199 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
200 &MdEntry
->ListEntry
);
204 /* Create an MD for any driver */
205 MdEntry
= &BldrMemoryDescriptors
[i
];
206 MdEntry
->MemoryType
= LoaderBootDriver
;
207 MdEntry
->BasePage
= (ULONG_PTR
)ModStart
>> PAGE_SHIFT
;
208 MdEntry
->PageCount
= (ModSize
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
209 InsertTailList(&LoaderBlock
->MemoryDescriptorListHead
,
210 &MdEntry
->ListEntry
);
213 /* Setup the loader entry */
214 LdrEntry
= &BldrModules
[i
];
215 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
217 /* Convert driver name from ANSI to Unicode */
218 for (j
= 0; j
< strlen(DriverName
); j
++)
220 BldrModuleStrings
[i
][j
] = DriverName
[j
];
223 /* Setup driver name */
224 RtlInitUnicodeString(&LdrEntry
->BaseDllName
, BldrModuleStrings
[i
]);
225 RtlInitUnicodeString(&LdrEntry
->FullDllName
, BldrModuleStrings
[i
]);
227 /* Copy data from Freeldr Module Entry */
228 LdrEntry
->DllBase
= ModStart
;
229 LdrEntry
->SizeOfImage
= ModSize
;
231 /* Copy additional data */
232 NtHeader
= RtlImageNtHeader(ModStart
);
233 LdrEntry
->EntryPoint
= RVA(ModStart
,
235 OptionalHeader
.AddressOfEntryPoint
);
237 /* Initialize other data */
238 LdrEntry
->LoadCount
= 1;
239 LdrEntry
->Flags
= LDRP_IMAGE_DLL
|
240 LDRP_ENTRY_PROCESSED
;
241 if (RosEntry
->Reserved
) LdrEntry
->Flags
|= LDRP_ENTRY_INSERTED
;
243 /* Insert it into the loader block */
244 InsertTailList(&LoaderBlock
->LoadOrderListHead
,
245 &LdrEntry
->InLoadOrderLinks
);
248 /* Setup command line */
249 LoaderBlock
->LoadOptions
= BldrCommandLine
;
250 strcpy(BldrCommandLine
, RosLoaderBlock
->CommandLine
);
252 /* Setup the extension block */
253 LoaderBlock
->Extension
= &BldrExtensionBlock
;
254 LoaderBlock
->Extension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
255 LoaderBlock
->Extension
->MajorVersion
= 5;
256 LoaderBlock
->Extension
->MinorVersion
= 2;
258 /* Now setup the setup block if we have one */
259 if (LoaderBlock
->SetupLdrBlock
)
261 /* All we'll setup right now is the flag for text-mode setup */
262 LoaderBlock
->SetupLdrBlock
->Flags
= 1;
265 /* Make a copy of the command line */
266 strcpy(CommandLine
, LoaderBlock
->LoadOptions
);
268 /* Find the first \, separating the ARC path from NT path */
269 BootPath
= strchr(CommandLine
, '\\');
270 *BootPath
= ANSI_NULL
;
271 strncpy(BldrArcBootPath
, CommandLine
, 63);
272 LoaderBlock
->ArcBootDeviceName
= BldrArcBootPath
;
274 /* The rest of the string is the NT path */
275 HalPath
= strchr(BootPath
+ 1, ' ');
276 *HalPath
= ANSI_NULL
;
277 BldrNtBootPath
[0] = '\\';
278 strncat(BldrNtBootPath
, BootPath
+ 1, 63);
279 strcat(BldrNtBootPath
,"\\");
280 LoaderBlock
->NtBootPathName
= BldrNtBootPath
;
282 /* Set the HAL paths */
283 strncpy(BldrArcHalPath
, BldrArcBootPath
, 63);
284 LoaderBlock
->ArcHalDeviceName
= BldrArcHalPath
;
285 strcpy(BldrNtHalPath
, "\\");
286 LoaderBlock
->NtHalPathName
= BldrNtHalPath
;
288 /* Use this new command line */
289 strncpy(LoaderBlock
->LoadOptions
, HalPath
+ 2, 255);
291 /* Parse it and change every slash to a space */
292 BootPath
= LoaderBlock
->LoadOptions
;
293 do {if (*BootPath
== '/') *BootPath
= ' ';} while (*BootPath
++);
295 /* Now let's loop ARC disk information */
296 for (i
= 0; i
< RosLoaderBlock
->DrivesCount
; i
++)
298 /* Get the ROS loader entry */
299 RosDiskInfo
= &RosLoaderBlock
->DrivesAddr
[i
];
301 /* Get the ARC structure */
302 ArcDiskInfo
= &BldrDiskInfo
[i
];
304 /* Copy the data over */
305 ArcDiskInfo
->Signature
= RosDiskInfo
->Signature
;
306 ArcDiskInfo
->CheckSum
= RosDiskInfo
->CheckSum
;
308 /* Copy the ARC Name */
309 strcpy(BldrArcNames
[i
], RosDiskInfo
->ArcName
);
310 ArcDiskInfo
->ArcName
= BldrArcNames
[i
];
312 /* Insert into the list */
313 InsertTailList(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
,
314 &ArcDiskInfo
->ListEntry
);
320 KiRosPrepareForSystemStartup(IN ULONG Dummy
,
321 IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock
)
323 PLOADER_PARAMETER_BLOCK NtLoaderBlock
;
327 /* Load the GDT and IDT */
328 Ke386SetGlobalDescriptorTable(KiGdtDescriptor
);
329 Ke386SetInterruptDescriptorTable(KiIdtDescriptor
);
331 /* Initialize the boot TSS */
333 TssEntry
= &KiBootGdt
[KGDT_TSS
/ sizeof(KGDTENTRY
)];
334 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
335 TssEntry
->HighWord
.Bits
.Pres
= 1;
336 TssEntry
->HighWord
.Bits
.Dpl
= 0;
337 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
338 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
339 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
341 /* Save pointer to ROS Block */
342 KeRosLoaderBlock
= LoaderBlock
;
344 /* Save memory manager data */
345 MmFreeLdrLastKernelAddress
= PAGE_ROUND_UP(KeRosLoaderBlock
->
346 ModsAddr
[KeRosLoaderBlock
->
349 MmFreeLdrFirstKrnlPhysAddr
= KeRosLoaderBlock
->ModsAddr
[0].ModStart
-
350 KSEG0_BASE
+ 0x200000;
351 MmFreeLdrLastKrnlPhysAddr
= MmFreeLdrLastKernelAddress
-
352 KSEG0_BASE
+ 0x200000;
354 /* Set up the VDM Data */
357 /* Convert the loader block */
358 KiRosFrldrLpbToNtLpb(KeRosLoaderBlock
, &NtLoaderBlock
);
360 /* Do general System Startup */
361 KiSystemStartup(NtLoaderBlock
);