374b633191ca8898ab5b315e59842f57f1846eed
[reactos.git] / reactos / boot / freeldr / freeldr / arch / powerpc / mboot.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2005 Alex Ionescu <alex@relsoft.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <freeldr.h>
22
23 #include <of_call.h>
24
25 #define NDEBUG
26 #include <debug.h>
27
28 static PVOID KernelMemory = 0;
29
30 /* Bits to shift to convert a Virtual Address into an Offset in the Page Table */
31 #define PFN_SHIFT 12
32
33 /* Bits to shift to convert a Virtual Address into an Offset in the Page Directory */
34 #define PDE_SHIFT 22
35 #define PDE_SHIFT_PAE 18
36
37
38 /* Converts a Relative Address read from the Kernel into a Physical Address */
39 ULONG RaToPa(ULONG p) {
40 return ofw_virt2phys((ULONG)(p + KernelMemory), 1);
41 }
42
43 /* Converts a Phsyical Address Pointer into a Page Frame Number */
44 #define PaPtrToPfn(p) \
45 (((ULONG_PTR)&p) >> PFN_SHIFT)
46
47 /* Converts a Phsyical Address into a Page Frame Number */
48 #define PaToPfn(p) \
49 ((p) >> PFN_SHIFT)
50
51 #define STARTUP_BASE 0xC0000000
52 #define HYPERSPACE_BASE 0xC0400000
53 #define HYPERSPACE_PAE_BASE 0xC0800000
54 #define APIC_BASE 0xFEC00000
55 #define KPCR_BASE 0xFF000000
56
57 #define LowMemPageTableIndex 0
58 #define StartupPageTableIndex (STARTUP_BASE >> 22)
59 #define HyperspacePageTableIndex (HYPERSPACE_BASE >> 22)
60 #define KpcrPageTableIndex (KPCR_BASE >> 22)
61 #define ApicPageTableIndex (APIC_BASE >> 22)
62
63 #define LowMemPageTableIndexPae 0
64 #define StartupPageTableIndexPae (STARTUP_BASE >> 21)
65 #define HyperspacePageTableIndexPae (HYPERSPACE_PAE_BASE >> 21)
66 #define KpcrPageTableIndexPae (KPCR_BASE >> 21)
67 #define ApicPageTableIndexPae (APIC_BASE >> 21)
68
69
70 #define KernelEntryPoint (KernelEntry - KERNEL_BASE_PHYS) + KernelBase
71
72 /* Load Address of Next Module */
73 ULONG_PTR NextModuleBase = 0;
74
75 /* Currently Opened Module */
76 PLOADER_MODULE CurrentModule = NULL;
77
78 /* Unrelocated Kernel Base in Virtual Memory */
79 ULONG_PTR KernelBase;
80
81 /* Wether PAE is to be used or not */
82 BOOLEAN PaeModeEnabled;
83
84 /* Kernel Entrypoint in Physical Memory */
85 ULONG_PTR KernelEntry;
86
87 /* FUNCTIONS *****************************************************************/
88
89 /*++
90 * FrLdrStartup
91 * INTERNAL
92 *
93 * Prepares the system for loading the Kernel.
94 *
95 * Params:
96 * Magic - Multiboot Magic
97 *
98 * Returns:
99 * None.
100 *
101 * Remarks:
102 * None.
103 *
104 *--*/
105 VOID
106 NTAPI
107 FrLdrStartup(ULONG Magic)
108 {
109 }
110
111 /*++
112 * FrLdrSetupPae
113 * INTERNAL
114 *
115 * Configures PAE on a MP System, and sets the PDBR if it's supported, or if
116 * the system is UP.
117 *
118 * Params:
119 * Magic - Multiboot Magic
120 *
121 * Returns:
122 * None.
123 *
124 * Remarks:
125 * None.
126 *
127 *--*/
128 VOID
129 FASTCALL
130 FrLdrSetupPae(ULONG Magic)
131 {
132 }
133
134 /*++
135 * FrLdrGetKernelBase
136 * INTERNAL
137 *
138 * Gets the Kernel Base to use.
139 *
140 * Params:
141 *
142 * Returns:
143 * None.
144 *
145 * Remarks:
146 * Sets both the FreeLdr internal variable as well as the one which
147 * will be used by the Kernel.
148 *
149 *--*/
150 static VOID
151 FASTCALL
152 FrLdrGetKernelBase(VOID)
153 {
154 PCHAR p;
155
156 /* Set KernelBase */
157 LoaderBlock.KernelBase = KernelBase;
158
159 /* Read Command Line */
160 p = (PCHAR)LoaderBlock.CommandLine;
161 while ((p = strchr(p, '/')) != NULL) {
162
163 /* Find "/3GB" */
164 if (!_strnicmp(p + 1, "3GB", 3)) {
165
166 /* Make sure there's nothing following it */
167 if (p[4] == ' ' || p[4] == 0) {
168
169 /* Use 3GB */
170 KernelBase = 0xE0000000;
171 LoaderBlock.KernelBase = 0xC0000000;
172 }
173 }
174
175 p++;
176 }
177 }
178
179 /*++
180 * FrLdrGetPaeMode
181 * INTERNAL
182 *
183 * Determines whether PAE mode shoudl be enabled or not.
184 *
185 * Params:
186 * None.
187 *
188 * Returns:
189 * None.
190 *
191 * Remarks:
192 * None.
193 *
194 *--*/
195 VOID
196 FASTCALL
197 FrLdrGetPaeMode(VOID)
198 {
199 }
200
201 /*++
202 * FrLdrSetupPageDirectory
203 * INTERNAL
204 *
205 * Sets up the ReactOS Startup Page Directory.
206 *
207 * Params:
208 * None.
209 *
210 * Returns:
211 * None.
212 *
213 * Remarks:
214 * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
215 * As such, please note that PageFrameNumber == PageEntryNumber.
216 *
217 *--*/
218 VOID
219 FASTCALL
220 FrLdrSetupPageDirectory(VOID)
221 {
222 }
223
224 /*++
225 * FrLdrMapKernel
226 * INTERNAL
227 *
228 * Maps the Kernel into memory, does PE Section Mapping, initalizes the
229 * uninitialized data sections, and relocates the image.
230 *
231 * Params:
232 * KernelImage - FILE Structure representing the ntoskrnl image file.
233 *
234 * Returns:
235 * TRUE if the Kernel was mapped.
236 *
237 * Remarks:
238 * None.
239 *
240 *--*/
241 BOOLEAN
242 NTAPI
243 FrLdrMapKernel(FILE *KernelImage)
244 {
245 PIMAGE_DOS_HEADER ImageHeader;
246 PIMAGE_NT_HEADERS NtHeader;
247 PIMAGE_SECTION_HEADER Section;
248 ULONG SectionCount;
249 ULONG ImageSize;
250 ULONG_PTR SourceSection;
251 ULONG_PTR TargetSection;
252 ULONG SectionSize;
253 INT i;
254 PIMAGE_DATA_DIRECTORY RelocationDDir;
255 PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
256 ULONG Count;
257 ULONG_PTR Address, MaxAddress;
258 PUSHORT TypeOffset;
259 ULONG_PTR Delta;
260 PUSHORT ShortPtr;
261 PULONG LongPtr;
262
263 /* Allocate 1024 bytes for PE Header */
264 ImageHeader = (PIMAGE_DOS_HEADER)MmAllocateMemory(1024);
265
266 /* Make sure it was succesful */
267 if (ImageHeader == NULL) {
268
269 return FALSE;
270 }
271
272 /* Load the first 1024 bytes of the kernel image so we can read the PE header */
273 if (!FsReadFile(KernelImage, 1024, NULL, ImageHeader)) {
274
275 /* Fail if we couldn't read */
276 MmFreeMemory(ImageHeader);
277 return FALSE;
278 }
279
280 /* Now read the MZ header to get the offset to the PE Header */
281 NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)ImageHeader + ImageHeader->e_lfanew);
282
283 /* Get Kernel Base */
284 KernelBase = NtHeader->OptionalHeader.ImageBase;
285 FrLdrGetKernelBase();
286
287 printf("About to do RaToPa(%x)\n",
288 NtHeader->OptionalHeader.AddressOfEntryPoint);
289 /* Save Entrypoint */
290 KernelEntry = RaToPa(NtHeader->OptionalHeader.AddressOfEntryPoint);
291 printf("RaToPa -> %x\n", KernelEntry);
292
293 /* Save the Image Size */
294 ImageSize = NtHeader->OptionalHeader.SizeOfImage;
295
296 /* Free the Header */
297 MmFreeMemory(ImageHeader);
298
299 /* Set the file pointer to zero */
300 FsSetFilePointer(KernelImage, 0);
301
302 /* Allocate kernel memory */
303 KernelMemory = MmAllocateMemory(ImageSize);
304
305 /* Load the file image */
306 FsReadFile(KernelImage, ImageSize, NULL, KernelMemory);
307
308 /* Reload the NT Header */
309 NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)KernelMemory + ImageHeader->e_lfanew);
310
311 /* Load the first section */
312 Section = IMAGE_FIRST_SECTION(NtHeader);
313 SectionCount = NtHeader->FileHeader.NumberOfSections - 1;
314
315 /* Now go to the last section */
316 Section += SectionCount;
317
318 /* Walk each section backwards */
319 for (i=(INT)SectionCount; i >= 0; i--, Section--) {
320
321 /* Get the disk location and the memory location, and the size */
322 SourceSection = RaToPa(Section->PointerToRawData);
323 TargetSection = RaToPa(Section->VirtualAddress);
324 SectionSize = Section->SizeOfRawData;
325
326 /* If the section is already mapped correctly, go to the next */
327 if (SourceSection == TargetSection) continue;
328
329 /* Load it into memory */
330 memmove((PVOID)TargetSection, (PVOID)SourceSection, SectionSize);
331
332 /* Check for unitilizated data */
333 if (Section->SizeOfRawData < Section->Misc.VirtualSize) {
334
335 /* Zero it out */
336 memset((PVOID)RaToPa(Section->VirtualAddress + Section->SizeOfRawData),
337 0,
338 Section->Misc.VirtualSize - Section->SizeOfRawData);
339 }
340 }
341
342 /* Get the Relocation Data Directory */
343 RelocationDDir = &NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
344
345 /* Get the Relocation Section Start and End*/
346 RelocationDir = (PIMAGE_BASE_RELOCATION)(KernelMemory + RelocationDDir->VirtualAddress);
347 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDDir->Size);
348
349 /* Calculate Difference between Real Base and Compiled Base*/
350 Delta = KernelBase - NtHeader->OptionalHeader.ImageBase;
351
352 /* Determine how far we shoudl relocate */
353 MaxAddress = (ULONG)KernelMemory + ImageSize;
354
355 /* Relocate until we've processed all the blocks */
356 while (RelocationDir < RelocationEnd && RelocationDir->SizeOfBlock > 0) {
357
358 /* See how many Relocation Blocks we have */
359 Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
360
361 /* Calculate the Address of this Directory */
362 Address = (ULONG)KernelMemory + RelocationDir->VirtualAddress;
363
364 /* Calculate the Offset of the Type */
365 TypeOffset = (PUSHORT)(RelocationDir + 1);
366
367 for (i = 0; i < (INT)Count; i++) {
368
369 ShortPtr = (PUSHORT)(Address + (*TypeOffset & 0xFFF));
370
371 switch (*TypeOffset >> 12) {
372
373 case IMAGE_REL_BASED_ABSOLUTE:
374 break;
375
376 case IMAGE_REL_BASED_HIGH:
377 *ShortPtr += HIWORD(Delta);
378 break;
379
380 case IMAGE_REL_BASED_LOW:
381 *ShortPtr += LOWORD(Delta);
382 break;
383
384 case IMAGE_REL_BASED_HIGHLOW:
385 LongPtr = (PULONG)ShortPtr;
386 *LongPtr += Delta;
387 break;
388 }
389
390 TypeOffset++;
391 }
392
393 /* Move to the next Relocation Table */
394 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDir->SizeOfBlock);
395 }
396
397 /* Increase the next Load Base */
398 NextModuleBase = ROUND_UP((ULONG)KernelMemory + ImageSize, PAGE_SIZE);
399
400 /* Return Success */
401 return TRUE;
402 }
403
404 ULONG_PTR
405 NTAPI
406 FrLdrLoadModule(FILE *ModuleImage,
407 LPCSTR ModuleName,
408 PULONG ModuleSize)
409 {
410 ULONG LocalModuleSize;
411 PLOADER_MODULE ModuleData;
412 LPSTR NameBuffer;
413 LPSTR TempName;
414
415 /* Get current module data structure and module name string array */
416 ModuleData = &reactos_modules[LoaderBlock.ModsCount];
417
418 /* Get only the Module Name */
419 do {
420
421 TempName = strchr(ModuleName, '\\');
422
423 if(TempName) {
424 ModuleName = TempName + 1;
425 }
426
427 } while(TempName);
428 NameBuffer = reactos_module_strings[LoaderBlock.ModsCount];
429
430 /* Get Module Size */
431 LocalModuleSize = FsGetFileSize(ModuleImage);
432
433 /* Fill out Module Data Structure */
434 ModuleData->ModStart = NextModuleBase;
435 ModuleData->ModEnd = NextModuleBase + LocalModuleSize;
436
437 /* Save name */
438 strcpy(NameBuffer, ModuleName);
439 ModuleData->String = (ULONG_PTR)NameBuffer;
440
441 /* Load the file image */
442 FsReadFile(ModuleImage, LocalModuleSize, NULL, (PVOID)NextModuleBase);
443
444 /* Move to next memory block and increase Module Count */
445 NextModuleBase = ROUND_UP(ModuleData->ModEnd, PAGE_SIZE);
446 LoaderBlock.ModsCount++;
447
448 /* Return Module Size if required */
449 if (ModuleSize != NULL) {
450 *ModuleSize = LocalModuleSize;
451 }
452
453 return(ModuleData->ModStart);
454 }
455
456 ULONG_PTR
457 NTAPI
458 FrLdrCreateModule(LPCSTR ModuleName)
459 {
460 PLOADER_MODULE ModuleData;
461 LPSTR NameBuffer;
462
463 /* Get current module data structure and module name string array */
464 ModuleData = &reactos_modules[LoaderBlock.ModsCount];
465 NameBuffer = reactos_module_strings[LoaderBlock.ModsCount];
466
467 /* Set up the structure */
468 ModuleData->ModStart = NextModuleBase;
469 ModuleData->ModEnd = -1;
470
471 /* Copy the name */
472 strcpy(NameBuffer, ModuleName);
473 ModuleData->String = (ULONG_PTR)NameBuffer;
474
475 /* Set the current Module */
476 CurrentModule = ModuleData;
477
478 /* Return Module Base Address */
479 return(ModuleData->ModStart);
480 }
481
482 BOOLEAN
483 NTAPI
484 FrLdrCloseModule(ULONG_PTR ModuleBase,
485 ULONG ModuleSize)
486 {
487 PLOADER_MODULE ModuleData = CurrentModule;
488
489 /* Make sure a module is opened */
490 if (ModuleData) {
491
492 /* Make sure this is the right module and that it hasn't been closed */
493 if ((ModuleBase == ModuleData->ModStart) && (ModuleData->ModEnd == (ULONG_PTR)-1)) {
494
495 /* Close the Module */
496 ModuleData->ModEnd = ModuleData->ModStart + ModuleSize;
497
498 /* Set the next Module Base and increase the number of modules */
499 NextModuleBase = ROUND_UP(ModuleData->ModEnd, PAGE_SIZE);
500 LoaderBlock.ModsCount++;
501
502 /* Close the currently opened module */
503 CurrentModule = NULL;
504
505 /* Success */
506 return(TRUE);
507 }
508 }
509
510 /* Failure path */
511 return(FALSE);
512 }