3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2005 Alex Ionescu <alex@relsoft.net>
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.
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.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <elf/reactos.h>
25 #include "ppcmmu/mmu.h"
30 /* We'll check this to see if we're in OFW land */
31 extern of_proxy ofproxy
;
33 PVOID KernelMemory
= NULL
;
35 /* Bits to shift to convert a Virtual Address into an Offset in the Page Table */
38 /* Bits to shift to convert a Virtual Address into an Offset in the Page Directory */
40 #define PDE_SHIFT_PAE 18
42 #define STARTUP_BASE 0xC0000000
43 #define HYPERSPACE_BASE 0xC0400000
44 #define HYPERSPACE_PAE_BASE 0xC0800000
45 #define APIC_BASE 0xFEC00000
46 #define KPCR_BASE 0xFF000000
48 #define LowMemPageTableIndex 0
49 #define StartupPageTableIndex (STARTUP_BASE >> 22)
50 #define HyperspacePageTableIndex (HYPERSPACE_BASE >> 22)
51 #define KpcrPageTableIndex (KPCR_BASE >> 22)
52 #define ApicPageTableIndex (APIC_BASE >> 22)
54 #define BAT_GRANULARITY (64 * 1024)
55 #define KernelMemorySize (8 * 1024 * 1024)
56 #define XROUNDUP(x,n) ((((ULONG)x) + ((n) - 1)) & (~((n) - 1)))
58 #define TAG_MBOOT 'oobM'
60 char reactos_module_strings
[64][256]; // Array to hold module names
62 /* Load Address of Next Module */
63 ULONG_PTR NextModuleBase
= 0;
65 /* Currently Opened Module */
66 PLOADER_MODULE CurrentModule
= NULL
;
68 /* Unrelocated Kernel Base in Virtual Memory */
71 /* Wether PAE is to be used or not */
72 BOOLEAN PaeModeEnabled
;
74 /* Kernel Entrypoint in Physical Memory */
75 ULONG_PTR KernelEntryPoint
;
77 /* Dummy to bring in memmove */
78 PVOID memmove_dummy
= memmove
;
82 LdrGetModuleObject(PCHAR ModuleName
);
86 LdrPEFixupImports(IN PVOID DllBase
,
89 VOID
PpcInitializeMmu(int max
);
91 /* FUNCTIONS *****************************************************************/
97 * Prepares the system for loading the Kernel.
100 * Magic - Multiboot Magic
110 typedef void (*KernelEntryFn
)( void * );
112 int MmuPageMiss(int trapCode
, ppc_trap_frame_t
*trap
)
115 printf("TRAP %x\n", trapCode
);
116 for( i
= 0; i
< 40; i
++ )
117 printf("r[%d] %x\n", i
, trap
->gpr
[i
]);
122 typedef struct _ppc_map_set_t
{
125 ppc_map_info_t
*info
;
128 extern int mmu_handle
;
129 paddr_t
MmuTranslate(paddr_t possibly_virtual
)
133 /* Openfirmware takes liberties with boot-time memory.
134 * if you're in a unitary kernel, it's not as difficult, but since
135 * we rely on loading things into virtual space from here, we need
136 * to detect the mappings so far.
139 args
[0] = possibly_virtual
;
140 args
[1] = 1; /* Marker to tell we want a physical addr */
141 return (paddr_t
)ofw_callmethod_ret("translate", mmu_handle
, 2, args
, 3);
145 /* Other booters don't remap ram */
146 return possibly_virtual
;
152 FrLdrAddPageMapping(ppc_map_set_t
*set
, int proc
, paddr_t phys
, vaddr_t virt
)
155 paddr_t page
= ROUND_DOWN(phys
, (1<<PFN_SHIFT
));
158 virt
= ROUND_DOWN(page
, (1<<PFN_SHIFT
));
160 virt
= ROUND_DOWN(virt
, (1<<PFN_SHIFT
));
162 page
= MmuTranslate(page
);
164 //printf("Mapping virt [%x] to phys [%x (from) %x]\n", virt, page, phys);
166 for( j
= 0; j
< set
->usecount
; j
++ )
168 if(set
->info
[j
].addr
== page
) return;
174 set
->info
= MmAllocateMemory(0x80 * sizeof(*set
->info
));
176 else if (set
->mapsize
<= set
->usecount
)
178 ppc_map_info_t
*newinfo
= MmAllocateMemory(set
->mapsize
* 2 * sizeof(*set
->info
));
179 memcpy(newinfo
, set
->info
, set
->mapsize
* sizeof(*set
->info
));
180 MmFreeMemory(set
->info
);
185 set
->info
[set
->usecount
].flags
= MMU_ALL_RW
;
186 set
->info
[set
->usecount
].proc
= proc
;
187 set
->info
[set
->usecount
].addr
= virt
;
188 set
->info
[set
->usecount
].phys
= page
;
192 extern int _start
[], _end
[];
196 FrLdrStartup(ULONG Magic
)
198 ULONG_PTR i
, tmp
, OldModCount
= 0;
200 CHAR ModulesTreated
[64] = { 0 };
201 ULONG NumberOfEntries
= 0, UsedEntries
= 0;
202 PPAGE_LOOKUP_TABLE_ITEM FreeLdrMap
= MmGetMemoryMap(&NumberOfEntries
);
203 ppc_map_set_t memmap
= { };
205 printf("FrLdrStartup\n");
208 __asm__("mfmsr %0" : "=r" (tmp
));
210 __asm__("mtmsr %0" : : "r" (tmp
));
212 while(OldModCount
!= LoaderBlock
.ModsCount
)
214 printf("Added %d modules last pass\n",
215 LoaderBlock
.ModsCount
- OldModCount
);
217 OldModCount
= LoaderBlock
.ModsCount
;
219 for(i
= 0; i
< LoaderBlock
.ModsCount
; i
++)
221 if (!ModulesTreated
[i
])
223 ModulesTreated
[i
] = 1;
224 ModHeader
= ((PCHAR
)reactos_modules
[i
].ModStart
);
225 if(ModHeader
[0] == 'M' && ModHeader
[1] == 'Z')
227 ((PVOID
)reactos_modules
[i
].ModStart
,
228 (PCHAR
)reactos_modules
[i
].String
);
233 printf("Starting mmu\n");
237 printf("Allocating vsid 0 (kernel)\n");
238 MmuAllocVsid(0, 0xff00);
240 /* We'll use vsid 1 for freeldr (expendable) */
241 printf("Allocating vsid 1 (freeldr)\n");
242 MmuAllocVsid(1, 0xff);
244 printf("Mapping Freeldr Code (%x-%x)\n", _start
, _end
);
246 /* Map memory zones */
248 for( i
= (int)_start
;
250 i
+= (1<<PFN_SHIFT
) ) {
251 FrLdrAddPageMapping(&memmap
, 1, i
, 0);
254 printf("KernelBase %x\n", KernelBase
);
256 /* Heap pages -- this gets the entire freeldr heap */
257 for( i
= 0; i
< NumberOfEntries
; i
++ ) {
259 if (FreeLdrMap
[i
].PageAllocated
== LoaderSystemCode
) {
261 if (tmp
>= (ULONG
)KernelMemory
&&
262 tmp
< (ULONG
)KernelMemory
+ KernelMemorySize
) {
263 FrLdrAddPageMapping(&memmap
, 0, tmp
, KernelBase
+ tmp
- (ULONG
)KernelMemory
);
265 FrLdrAddPageMapping(&memmap
, 1, tmp
, 0);
270 MmuMapPage(memmap
.info
, memmap
.usecount
);
272 printf("Finished Mapping the Freeldr Heap (used %d pages)\n", UsedEntries
);
274 printf("Setting initial segments\n");
276 MmuSetVsid(8, 16, 0);
278 printf("Segments set!\n");
280 MmuTurnOn((KernelEntryFn
)KernelEntryPoint
, &LoaderBlock
);
290 * Configures PAE on a MP System, and sets the PDBR if it's supported, or if
294 * Magic - Multiboot Magic
305 FrLdrSetupPae(ULONG Magic
)
313 * Gets the Kernel Base to use.
321 * Sets both the FreeLdr internal variable as well as the one which
322 * will be used by the Kernel.
327 FrLdrGetKernelBase(VOID
)
331 /* Default kernel base at 2GB */
332 KernelBase
= 0x80800000;
335 LoaderBlock
.KernelBase
= 0x80000000;
337 /* Read Command Line */
338 p
= (PCHAR
)LoaderBlock
.CommandLine
;
339 while ((p
= strchr(p
, '/')) != NULL
) {
342 if (!_strnicmp(p
+ 1, "3GB", 3)) {
344 /* Make sure there's nothing following it */
345 if (p
[4] == ' ' || p
[4] == 0) {
348 KernelBase
= 0xE0000000;
349 LoaderBlock
.KernelBase
= 0xC0000000;
361 * Determines whether PAE mode should be enabled or not.
375 FrLdrGetPaeMode(VOID
)
380 * FrLdrSetupPageDirectory
383 * Sets up the ReactOS Startup Page Directory.
392 * We are setting PDEs, but using the equivalent (for our purpose) PTE structure.
393 * As such, please note that PageFrameNumber == PageEntryNumber.
398 FrLdrSetupPageDirectory(VOID
)
406 * Loads the indicated elf image as PE. The target will appear to be
407 * a PE image whose ImageBase has ever been KernelAddr.
410 * Image -- File to load
411 * ImageName -- Name of image for the modules list
412 * MemLoadAddr -- Freeldr address of module
413 * KernelAddr -- Kernel address of module
415 #define ELF_SECTION(n) ((Elf32_Shdr*)(sptr + (n * shsize)))
416 #define COFF_FIRST_SECTION(h) ((PIMAGE_SECTION_HEADER) ((DWORD)h+FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader)+(SWAPW(((PIMAGE_NT_HEADERS)(h))->FileHeader.SizeOfOptionalHeader))))
420 FrLdrMapModule(FILE *KernelImage
, PCHAR ImageName
, PCHAR MemLoadAddr
, ULONG KernelAddr
)
422 PIMAGE_DOS_HEADER ImageHeader
= 0;
423 PIMAGE_NT_HEADERS NtHeader
= 0;
424 PIMAGE_SECTION_HEADER Section
;
428 PLOADER_MODULE ModuleData
;
430 int shsize
, shnum
, relsize
, SectionAddr
= 0;
434 LARGE_INTEGER Position
;
437 TempName
= strrchr(ImageName
, '\\');
438 if(TempName
) TempName
++; else TempName
= (PSTR
)ImageName
;
439 ModuleData
= LdrGetModuleObject(TempName
);
447 KernelAddr
= (ULONG
)NextModuleBase
- (ULONG
)KernelMemory
+ KernelBase
;
449 MemLoadAddr
= (PCHAR
)NextModuleBase
;
451 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
452 //printf("Loading file (elf at %x)\n", KernelAddr);
454 /* Load the first 1024 bytes of the kernel image so we can read the PE header */
455 if (ArcRead(KernelImage
, &ehdr
, sizeof(ehdr
), NULL
) != ESUCCESS
) {
457 /* Fail if we couldn't read */
458 printf("Couldn't read the elf header\n");
462 /* Start by getting elf headers */
463 //phsize = ehdr.e_phentsize;
464 //phnum = ehdr.e_phnum;
465 shsize
= ehdr
.e_shentsize
;
466 shnum
= ehdr
.e_shnum
;
467 sptr
= (PCHAR
)FrLdrTempAlloc(shnum
* shsize
, TAG_MBOOT
);
469 /* Read section headers */
470 Position
.QuadPart
= ehdr
.e_shoff
;
471 ArcSeek(KernelImage
, &Position
, SeekAbsolute
);
472 ArcRead(KernelImage
, sptr
, shsize
* shnum
, NULL
);
474 /* Now we'll get the PE Header */
475 for( i
= 0; i
< shnum
; i
++ )
477 shdr
= ELF_SECTION(i
);
480 /* Find the PE Header */
481 if (shdr
->sh_type
== TYPE_PEHEADER
)
483 Position
.QuadPart
= shdr
->sh_offset
;
484 ArcSeek(KernelImage
, &Position
, SeekAbsolute
);
485 ArcRead(KernelImage
, MemLoadAddr
, shdr
->sh_size
, NULL
);
486 ImageHeader
= (PIMAGE_DOS_HEADER
)MemLoadAddr
;
487 NtHeader
= (PIMAGE_NT_HEADERS
)((PCHAR
)MemLoadAddr
+ SWAPD(ImageHeader
->e_lfanew
));
489 printf("NtHeader at %x\n", SWAPD(ImageHeader
->e_lfanew
));
490 printf("SectionAlignment %x\n",
491 SWAPD(NtHeader
->OptionalHeader
.SectionAlignment
));
492 SectionAddr
= ROUND_UP
493 (shdr
->sh_size
, SWAPD(NtHeader
->OptionalHeader
.SectionAlignment
));
494 printf("Header ends at %x\n", SectionAddr
);
502 printf("No peheader section encountered :-(\n");
508 printf("DOS SIG: %s\n", (PCHAR
)MemLoadAddr
);
512 /* Save the Image Base */
513 NtHeader
->OptionalHeader
.ImageBase
= SWAPD(KernelAddr
);
515 /* Load the file image */
516 Section
= COFF_FIRST_SECTION(NtHeader
);
517 SectionCount
= SWAPW(NtHeader
->FileHeader
.NumberOfSections
);
519 /* Walk each section */
520 for (i
=0; i
< SectionCount
; i
++, Section
++)
522 shdr
= ELF_SECTION((SWAPD(Section
->PointerToRawData
)+1));
524 shdr
->sh_addr
= SectionAddr
= SWAPD(Section
->VirtualAddress
);
525 shdr
->sh_addr
+= KernelAddr
;
527 Section
->PointerToRawData
= SWAPD((Section
->VirtualAddress
- KernelAddr
));
529 if (shdr
->sh_type
!= SHT_NOBITS
)
532 printf("Loading section %d at %x (real: %x:%d)\n", i
, KernelAddr
+ SectionAddr
, MemLoadAddr
+SectionAddr
, shdr
->sh_size
);
533 Position
.QuadPart
= shdr
->sh_offset
;
534 ArcSeek(KernelImage
, &Position
, SeekAbsolute
);
535 ArcRead(KernelImage
, MemLoadAddr
+ SectionAddr
, shdr
->sh_size
, NULL
);
540 printf("BSS section %d at %x\n", i
, KernelAddr
+ SectionAddr
);
541 memset(MemLoadAddr
+ SectionAddr
, 0,
542 ROUND_UP(shdr
->sh_size
,
543 SWAPD(NtHeader
->OptionalHeader
.SectionAlignment
)));
547 ImageSize
= SWAPD(NtHeader
->OptionalHeader
.SizeOfImage
);
548 printf("Total image size is %x\n", ImageSize
);
550 /* Handle relocation sections */
551 for (i
= 0; i
< shnum
; i
++) {
552 Elf32_Rela reloc
= { };
555 int numreloc
, relstart
, targetSection
;
557 PCHAR RelocSection
, SymbolSection
;
559 shdr
= ELF_SECTION(i
);
560 /* Only relocs here */
561 if((shdr
->sh_type
!= SHT_REL
) &&
562 (shdr
->sh_type
!= SHT_RELA
)) continue;
564 relstart
= shdr
->sh_offset
;
565 relsize
= shdr
->sh_type
== SHT_RELA
? 12 : 8;
566 numreloc
= shdr
->sh_size
/ relsize
;
567 targetSection
= shdr
->sh_info
;
569 if (!ELF_SECTION(targetSection
)->sh_addr
) continue;
571 RelocSection
= FrLdrTempAlloc(shdr
->sh_size
, TAG_MBOOT
);
572 Position
.QuadPart
= relstart
;
573 ArcSeek(KernelImage
, &Position
, SeekAbsolute
);
574 ArcRead(KernelImage
, RelocSection
, shdr
->sh_size
, NULL
);
576 /* Get the symbol section */
577 shdr
= ELF_SECTION(shdr
->sh_link
);
579 SymbolSection
= FrLdrTempAlloc(shdr
->sh_size
, TAG_MBOOT
);
580 Position
.QuadPart
= shdr
->sh_offset
;
581 ArcSeek(KernelImage
, &Position
, SeekAbsolute
);
582 ArcRead(KernelImage
, SymbolSection
, shdr
->sh_size
, NULL
);
584 for(j
= 0; j
< numreloc
; j
++)
589 memcpy(&reloc
, RelocSection
+ (j
* relsize
), sizeof(reloc
));
592 memcpy(&symbol
, SymbolSection
+ (ELF32_R_SYM(reloc
.r_info
) * sizeof(symbol
)), sizeof(symbol
));
594 /* Compute addends */
595 S
= symbol
.st_value
+ ELF_SECTION(symbol
.st_shndx
)->sh_addr
;
597 P
= reloc
.r_offset
+ ELF_SECTION(targetSection
)->sh_addr
;
600 printf("Symbol[%d] %d -> %d(%x:%x) -> %x(+%x)@%x\n",
601 ELF32_R_TYPE(reloc
.r_info
),
602 ELF32_R_SYM(reloc
.r_info
),
604 ELF_SECTION(symbol
.st_shndx
)->sh_addr
,
611 Target32
= (ULONG
*)(((PCHAR
)MemLoadAddr
) + (P
- KernelAddr
));
612 Target16
= (USHORT
*)Target32
;
614 switch (ELF32_R_TYPE(reloc
.r_info
))
622 *Target32
= S
+ A
- P
;
624 case R_PPC_UADDR32
: /* Special: Treat as RVA */
625 *Target32
= S
+ A
- KernelAddr
;
628 *Target32
= (ADDR24_MASK
& (S
+A
)) | (*Target32
& ~ADDR24_MASK
);
631 *Target32
= (ADDR24_MASK
& (S
+A
-P
)) | (*Target32
& ~ADDR24_MASK
);
633 case R_PPC_ADDR16_LO
:
636 case R_PPC_ADDR16_HA
:
637 *Target16
= (S
+ A
+ 0x8000) >> 16;
644 printf("reloc[%d:%x]: (type %x sym %d val %d) off %x add %x (old %x new %x)\n",
646 ((ULONG
)Target32
) - ((ULONG
)MemLoadAddr
),
647 ELF32_R_TYPE(reloc
.r_info
),
648 ELF32_R_SYM(reloc
.r_info
),
650 reloc
.r_offset
, reloc
.r_addend
,
655 FrLdrTempFree(SymbolSection
, TAG_MBOOT
);
656 FrLdrTempFree(RelocSection
, TAG_MBOOT
);
659 FrLdrTempFree(sptr
, TAG_MBOOT
);
661 ModuleData
->ModStart
= (ULONG
)MemLoadAddr
;
662 /* Increase the next Load Base */
663 NextModuleBase
= ROUND_UP((ULONG
)MemLoadAddr
+ ImageSize
, PAGE_SIZE
);
664 ModuleData
->ModEnd
= NextModuleBase
;
665 ModuleData
->String
= (ULONG
)MmAllocateMemory(strlen(ImageName
)+1);
666 strcpy((PCHAR
)ModuleData
->String
, ImageName
);
667 printf("Module %s (%x-%x) next at %x\n",
669 ModuleData
->ModStart
,
672 LoaderBlock
.ModsCount
++;
682 * Maps the Kernel into memory, does PE Section Mapping, initializes the
683 * uninitialized data sections, and relocates the image.
686 * KernelImage - FILE Structure representing the ntoskrnl image file.
689 * TRUE if the Kernel was mapped.
697 FrLdrMapKernel(FILE *KernelImage
)
699 /* Get Kernel Base */
700 FrLdrGetKernelBase();
702 /* Allocate kernel memory */
703 KernelMemory
= MmAllocateMemory(KernelMemorySize
);
705 return FrLdrMapModule(KernelImage
, "ntoskrnl.exe", KernelMemory
, KernelBase
);
710 FrLdrLoadModule(FILE *ModuleImage
,
715 FILEINFORMATION FileInfo
;
716 ULONG LocalModuleSize
;
717 ULONG_PTR ThisModuleBase
= NextModuleBase
;
718 PLOADER_MODULE ModuleData
;
722 /* Get current module data structure and module name string array */
723 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
725 /* Get only the Module Name */
728 TempName
= strchr(ModuleName
, '\\');
731 ModuleName
= TempName
+ 1;
735 NameBuffer
= reactos_module_strings
[LoaderBlock
.ModsCount
];
737 /* Get Module Size */
738 Status
= ArcGetFileInformation(ModuleImage
, &FileInfo
);
739 if (Status
!= ESUCCESS
|| FileInfo
.EndingAddress
.HighPart
!= 0)
742 LocalModuleSize
= FileInfo
.EndingAddress
.LowPart
;
744 /* Fill out Module Data Structure */
745 ModuleData
->ModStart
= NextModuleBase
;
746 ModuleData
->ModEnd
= NextModuleBase
+ LocalModuleSize
;
749 strcpy(NameBuffer
, ModuleName
);
750 ModuleData
->String
= (ULONG_PTR
)NameBuffer
;
752 /* Load the file image */
753 ArcRead(ModuleImage
, (PVOID
)NextModuleBase
, LocalModuleSize
, NULL
);
755 /* Move to next memory block and increase Module Count */
756 NextModuleBase
= ROUND_UP(ModuleData
->ModEnd
, PAGE_SIZE
);
757 LoaderBlock
.ModsCount
++;
759 /* Return Module Size if required */
760 if (ModuleSize
!= NULL
) {
761 *ModuleSize
= LocalModuleSize
;
764 printf("Module %s (%x-%x) next at %x\n",
766 ModuleData
->ModStart
,
770 return ThisModuleBase
;
775 FrLdrMapImage(IN
FILE *Image
, IN PCHAR ShortName
, IN ULONG ImageType
)
779 printf("Loading image %s (type %d)\n", ShortName
, ImageType
);
783 if(FrLdrMapKernel(Image
))
784 Result
= (PVOID
)KernelMemory
;
788 PVOID ModuleBase
= (PVOID
)NextModuleBase
;
790 if(FrLdrMapModule(Image
, ShortName
, 0, 0))
798 FrLdrCreateModule(PCSTR ModuleName
)
800 PLOADER_MODULE ModuleData
;
803 /* Get current module data structure and module name string array */
804 ModuleData
= &reactos_modules
[LoaderBlock
.ModsCount
];
805 NameBuffer
= reactos_module_strings
[LoaderBlock
.ModsCount
];
807 /* Set up the structure */
808 ModuleData
->ModStart
= NextModuleBase
;
809 ModuleData
->ModEnd
= -1;
812 strcpy(NameBuffer
, ModuleName
);
813 ModuleData
->String
= (ULONG_PTR
)NameBuffer
;
815 /* Set the current Module */
816 CurrentModule
= ModuleData
;
818 /* Return Module Base Address */
819 return(ModuleData
->ModStart
);
824 FrLdrCloseModule(ULONG_PTR ModuleBase
,
827 PLOADER_MODULE ModuleData
= CurrentModule
;
829 /* Make sure a module is opened */
832 /* Make sure this is the right module and that it hasn't been closed */
833 if ((ModuleBase
== ModuleData
->ModStart
) && (ModuleData
->ModEnd
== MAXULONG_PTR
)) {
835 /* Close the Module */
836 ModuleData
->ModEnd
= ModuleData
->ModStart
+ ModuleSize
;
838 /* Set the next Module Base and increase the number of modules */
839 NextModuleBase
= ROUND_UP(ModuleData
->ModEnd
, PAGE_SIZE
);
840 LoaderBlock
.ModsCount
++;
842 /* Close the currently opened module */
843 CurrentModule
= NULL
;