- KiRosFrldrLpbToNtLpb(): Round up to the correct size in pages (I don't see a reason...
[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 Memory Data */
18 ULONG_PTR MmFreeLdrFirstKrnlPhysAddr, MmFreeLdrLastKrnlPhysAddr;
19 ULONG_PTR MmFreeLdrLastKernelAddress;
20 ULONG MmFreeLdrMemHigher;
21 ULONG MmFreeLdrPageDirectoryEnd;
22
23 /* FreeLDR Loader Data */
24 PROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock;
25 BOOLEAN AcpiTableDetected;
26
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
43 // 0xC23C
44
45 /* FUNCTIONS *****************************************************************/
46
47 VOID
48 NTAPI
49 KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
50 IN PLOADER_PARAMETER_BLOCK *NtLoaderBlock)
51 {
52 PLOADER_PARAMETER_BLOCK LoaderBlock;
53 PLDR_DATA_TABLE_ENTRY LdrEntry;
54 PMEMORY_ALLOCATION_DESCRIPTOR MdEntry;
55 PLOADER_MODULE RosEntry;
56 ULONG i, j, ModSize;
57 PVOID ModStart;
58 PCHAR DriverName;
59 PCHAR BootPath, HalPath;
60 CHAR CommandLine[256];
61 PARC_DISK_SIGNATURE RosDiskInfo, ArcDiskInfo;
62 PIMAGE_NT_HEADERS NtHeader;
63
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;
68
69 /* Set the NT Loader block and initialize it */
70 *NtLoaderBlock = LoaderBlock = &BldrLoaderBlock;
71 RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
72
73 /* Set the NLS Data block */
74 LoaderBlock->NlsData = &BldrNlsDataBlock;
75
76 /* Set the ARC Data block */
77 LoaderBlock->ArcDiskInformation = &BldrArcDiskInfo;
78
79 /* Assume this is from FreeLDR's SetupLdr */
80 LoaderBlock->SetupLdrBlock = &BldrSetupBlock;
81
82 /* Setup the list heads */
83 InitializeListHead(&LoaderBlock->LoadOrderListHead);
84 InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
85 InitializeListHead(&LoaderBlock->BootDriverListHead);
86 InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
87
88 /* Loop boot driver list */
89 for (i = 0; i < RosLoaderBlock->ModsCount; i++)
90 {
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;
96
97 /* Check if this is any of the NLS files */
98 if (!_stricmp(DriverName, "ansi.nls"))
99 {
100 /* ANSI Code page */
101 ModStart = (PVOID)((ULONG_PTR)ModStart + (KSEG0_BASE - 0x200000));
102 LoaderBlock->NlsData->AnsiCodePageData = ModStart;
103
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);
111 continue;
112 }
113 else if (!_stricmp(DriverName, "oem.nls"))
114 {
115 /* OEM Code page */
116 ModStart = (PVOID)((ULONG_PTR)ModStart + (KSEG0_BASE - 0x200000));
117 LoaderBlock->NlsData->OemCodePageData = ModStart;
118
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);
126 continue;
127 }
128 else if (!_stricmp(DriverName, "casemap.nls"))
129 {
130 /* Unicode Code page */
131 ModStart = (PVOID)((ULONG_PTR)ModStart + (KSEG0_BASE - 0x200000));
132 LoaderBlock->NlsData->UnicodeCodePageData = ModStart;
133
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);
141 continue;
142 }
143
144 /* Check if this is the SYSTEM hive */
145 if (!(_stricmp(DriverName, "system")) ||
146 !(_stricmp(DriverName, "system.hiv")))
147 {
148 /* Save registry data */
149 ModStart = (PVOID)((ULONG_PTR)ModStart + (KSEG0_BASE - 0x200000));
150 LoaderBlock->RegistryBase = ModStart;
151 LoaderBlock->RegistryLength = ModSize;
152
153 /* Disable setup mode */
154 LoaderBlock->SetupLdrBlock = NULL;
155
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);
163 continue;
164 }
165
166 /* Check if this is the HARDWARE hive */
167 if (!(_stricmp(DriverName, "hardware")) ||
168 !(_stricmp(DriverName, "hardware.hiv")))
169 {
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);
178 continue;
179 }
180
181 /* Check if this is the kernel */
182 if (!(_stricmp(DriverName, "ntoskrnl.exe")))
183 {
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);
191 }
192 else if (!(_stricmp(DriverName, "hal.dll")))
193 {
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);
201 }
202 else
203 {
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);
211 }
212
213 /* Setup the loader entry */
214 LdrEntry = &BldrModules[i];
215 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
216
217 /* Convert driver name from ANSI to Unicode */
218 for (j = 0; j < strlen(DriverName); j++)
219 {
220 BldrModuleStrings[i][j] = DriverName[j];
221 }
222
223 /* Setup driver name */
224 RtlInitUnicodeString(&LdrEntry->BaseDllName, BldrModuleStrings[i]);
225 RtlInitUnicodeString(&LdrEntry->FullDllName, BldrModuleStrings[i]);
226
227 /* Copy data from Freeldr Module Entry */
228 LdrEntry->DllBase = ModStart;
229 LdrEntry->SizeOfImage = ModSize;
230
231 /* Copy additional data */
232 NtHeader = RtlImageNtHeader(ModStart);
233 LdrEntry->EntryPoint = RVA(ModStart,
234 NtHeader->
235 OptionalHeader.AddressOfEntryPoint);
236
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;
242
243 /* Insert it into the loader block */
244 InsertTailList(&LoaderBlock->LoadOrderListHead,
245 &LdrEntry->InLoadOrderLinks);
246 }
247
248 /* Setup command line */
249 LoaderBlock->LoadOptions = BldrCommandLine;
250 strcpy(BldrCommandLine, RosLoaderBlock->CommandLine);
251
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;
257
258 /* Now setup the setup block if we have one */
259 if (LoaderBlock->SetupLdrBlock)
260 {
261 /* All we'll setup right now is the flag for text-mode setup */
262 LoaderBlock->SetupLdrBlock->Flags = 1;
263 }
264
265 /* Make a copy of the command line */
266 strcpy(CommandLine, LoaderBlock->LoadOptions);
267
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;
273
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;
281
282 /* Set the HAL paths */
283 strncpy(BldrArcHalPath, BldrArcBootPath, 63);
284 LoaderBlock->ArcHalDeviceName = BldrArcHalPath;
285 strcpy(BldrNtHalPath, "\\");
286 LoaderBlock->NtHalPathName = BldrNtHalPath;
287
288 /* Use this new command line */
289 strncpy(LoaderBlock->LoadOptions, HalPath + 2, 255);
290
291 /* Parse it and change every slash to a space */
292 BootPath = LoaderBlock->LoadOptions;
293 do {if (*BootPath == '/') *BootPath = ' ';} while (*BootPath++);
294
295 /* Now let's loop ARC disk information */
296 for (i = 0; i < RosLoaderBlock->DrivesCount; i++)
297 {
298 /* Get the ROS loader entry */
299 RosDiskInfo = &RosLoaderBlock->DrivesAddr[i];
300
301 /* Get the ARC structure */
302 ArcDiskInfo = &BldrDiskInfo[i];
303
304 /* Copy the data over */
305 ArcDiskInfo->Signature = RosDiskInfo->Signature;
306 ArcDiskInfo->CheckSum = RosDiskInfo->CheckSum;
307
308 /* Copy the ARC Name */
309 strcpy(BldrArcNames[i], RosDiskInfo->ArcName);
310 ArcDiskInfo->ArcName = BldrArcNames[i];
311
312 /* Insert into the list */
313 InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,
314 &ArcDiskInfo->ListEntry);
315 }
316 }
317
318 VOID
319 FASTCALL
320 KiRosPrepareForSystemStartup(IN ULONG Dummy,
321 IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock)
322 {
323 PLOADER_PARAMETER_BLOCK NtLoaderBlock;
324 PKTSS Tss;
325 PKGDTENTRY TssEntry;
326
327 /* Load the GDT and IDT */
328 Ke386SetGlobalDescriptorTable(KiGdtDescriptor);
329 Ke386SetInterruptDescriptorTable(KiIdtDescriptor);
330
331 /* Initialize the boot TSS */
332 Tss = &KiBootTss;
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);
340
341 /* Save pointer to ROS Block */
342 KeRosLoaderBlock = LoaderBlock;
343
344 /* Save memory manager data */
345 MmFreeLdrLastKernelAddress = PAGE_ROUND_UP(KeRosLoaderBlock->
346 ModsAddr[KeRosLoaderBlock->
347 ModsCount - 1].
348 ModEnd);
349 MmFreeLdrFirstKrnlPhysAddr = KeRosLoaderBlock->ModsAddr[0].ModStart -
350 KSEG0_BASE + 0x200000;
351 MmFreeLdrLastKrnlPhysAddr = MmFreeLdrLastKernelAddress -
352 KSEG0_BASE + 0x200000;
353
354 /* Set up the VDM Data */
355 NtEarlyInitVdm();
356
357 /* Convert the loader block */
358 KiRosFrldrLpbToNtLpb(KeRosLoaderBlock, &NtLoaderBlock);
359
360 /* Do general System Startup */
361 KiSystemStartup(NtLoaderBlock);
362 }
363
364 /* EOF */