From: Art Yerkes Date: Sun, 4 Dec 2005 12:13:48 +0000 (+0000) Subject: PowerPC support drop in freeldr, from my branch. X-Git-Tag: backups/ros-branch-0_2_9@19949~77 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=7e8e7b9634b305bd96089b6510b3399cc5bb9a48;ds=sidebyside PowerPC support drop in freeldr, from my branch. Some stuff not working, but disk IO now implemented. Get boot partition either from boot-device env var or from cmd line. Needs some work to build with the new tools. svn path=/trunk/; revision=19857 --- diff --git a/reactos/boot/freeldr/bootsect/ofwboot.s b/reactos/boot/freeldr/bootsect/ofwboot.s index 36e0434de55..0ec81eba33b 100644 --- a/reactos/boot/freeldr/bootsect/ofwboot.s +++ b/reactos/boot/freeldr/bootsect/ofwboot.s @@ -61,9 +61,10 @@ _begin: li %r9,0x12 /* BATL(0, BAT_M, BAT_PP_RW) */ mtibatl 0,%r9 mtdbatl 0,%r9 - li %r9,0x1ffe /* BATU(0, BAT_BL_256M, BAT_Vs) */ - mtibatu 0,%r9 - mtdbatu 0,%r9 + li %r10,0x1ffe /* BATU(0, BAT_BL_256M, BAT_Vs) */ + mtibatu 0,%r10 + mtdbatu 0,%r10 + isync li %r8,0x3030 @@ -93,6 +94,8 @@ _begin: bl ofw_print_eol + bl setup_exc + /* Zero CTR */ mtcr %r31 @@ -630,6 +633,53 @@ ofw_finddevice: /* Return */ blr +ofw_open: + /* Reserve stack space ... + * 20 bytes for the ofw call, + * r8, r9, and lr */ + subi %r1,%r1,32 + + /* Store r8, r9, lr */ + stw %r8,20(%r1) + stw %r9,24(%r1) + mflr %r8 + stw %r8,28(%r1) + + /* Get open name */ + lis %r8,0xe00000@ha + addi %r9,%r8,ofw_open_name - _start + stw %r9,0(%r1) + + /* 1 Argument and 1 return */ + li %r9,1 + stw %r9,4(%r1) + stw %r9,8(%r1) + + stw %r3,12(%r1) + + /* Load up the call address */ + lwz %r9,ofw_call_addr - _start(%r8) + mtlr %r9 + + /* Set argument */ + mr %r3,%r1 + + /* Fire */ + blrl + + lwz %r3,16(%r1) + + /* Restore registers */ + lwz %r8,28(%r1) + mtlr %r8 + lwz %r9,24(%r1) + lwz %r8,20(%r1) + + addi %r1,%r1,32 + + /* Return */ + blr + ofw_getprop_hook: /* Reserve stack space: * 32 bytes for the ofw call @@ -889,7 +939,224 @@ ofw_exit_loop: /* Fire */ blrl /* No return from exit */ + +ofw_child: + /* Reserve stack space ... + * 20 bytes for the ofw call, + * r8, r9, and lr */ + subi %r1,%r1,32 + + /* Store r8, r9, lr */ + stw %r8,20(%r1) + stw %r9,24(%r1) + mflr %r8 + stw %r8,28(%r1) + + /* Get child name */ + lis %r8,0xe00000@ha + addi %r9,%r8,ofw_child_name - _start + stw %r9,0(%r1) + + /* 1 Argument and 1 return */ + li %r9,1 + stw %r9,4(%r1) + stw %r9,8(%r1) + + stw %r3,12(%r1) + + /* Load up the call address */ + lwz %r9,ofw_call_addr - _start(%r8) + mtlr %r9 + + /* Set argument */ + mr %r3,%r1 + + /* Fire */ + blrl + + lwz %r3,16(%r1) + + /* Restore registers */ + lwz %r8,28(%r1) + mtlr %r8 + lwz %r9,24(%r1) + lwz %r8,20(%r1) + + addi %r1,%r1,32 + + /* Return */ + blr + +ofw_peer: + /* Reserve stack space ... + * 20 bytes for the ofw call, + * r8, r9, and lr */ + subi %r1,%r1,32 + + /* Store r8, r9, lr */ + stw %r8,20(%r1) + stw %r9,24(%r1) + mflr %r8 + stw %r8,28(%r1) + + /* Get peer name */ + lis %r8,0xe00000@ha + addi %r9,%r8,ofw_peer_name - _start + stw %r9,0(%r1) + + /* 1 Argument and 1 return */ + li %r9,1 + stw %r9,4(%r1) + stw %r9,8(%r1) + + stw %r3,12(%r1) + + /* Load up the call address */ + lwz %r9,ofw_call_addr - _start(%r8) + mtlr %r9 + + /* Set argument */ + mr %r3,%r1 + + /* Fire */ + blrl + + lwz %r3,16(%r1) + + /* Restore registers */ + lwz %r8,28(%r1) + mtlr %r8 + lwz %r9,24(%r1) + lwz %r8,20(%r1) + + addi %r1,%r1,32 + + /* Return */ + blr + +ofw_seek: + /* Reserve stack space ... + * 20 bytes for the ofw call, + * r8, r9, and lr */ + subi %r1,%r1,32 + + /* Store r8, r9, lr */ + stw %r8,20(%r1) + stw %r9,24(%r1) + mflr %r8 + stw %r8,28(%r1) + + /* Get peer name */ + lis %r8,0xe00000@ha + addi %r9,%r8,ofw_seek_name - _start + stw %r9,0(%r1) + + /* 3 Arguments and 1 return */ + li %r9,3 + stw %r9,4(%r1) + li %r9,1 + stw %r9,8(%r1) + + stw %r3,12(%r1) + stw %r4,16(%r1) + stw %r5,20(%r1) + + /* Load up the call address */ + lwz %r9,ofw_call_addr - _start(%r8) + mtlr %r9 + + /* Set argument */ + mr %r3,%r1 + + /* Fire */ + blrl + + lwz %r3,16(%r1) + + /* Restore registers */ + lwz %r8,28(%r1) + mtlr %r8 + lwz %r9,24(%r1) + lwz %r8,20(%r1) + + addi %r1,%r1,32 + + /* Return */ + blr + + +setup_exc: + subi %r1,%r1,32 + + stw %r3,0(%r1) + mflr %r3 + stw %r3,4(%r1) + stw %r8,8(%r1) + stw %r9,12(%r1) + stw %r10,16(%r1) + stw %r12,20(%r1) + + lis %r8,0xe00000@ha + xor %r12,%r12,%r12 + addi %r12,%r12,0x300 + addi %r9,%r8,dsi_exc - _start + addi %r10,%r8,dsi_end - _start + +copy_loop: + cmp 0,0,%r9,%r10 + beq ret_setup_exc + + mr %r3,%r12 + bl ofw_print_number + bl ofw_print_space + + lwz %r3,0(%r9) + stw %r3,0(%r12) + + bl ofw_print_number + bl ofw_print_eol + + addi %r12,%r12,4 + addi %r9,%r9,4 + b copy_loop + +ret_setup_exc: + mfmsr %r12 + andi. %r12,%r12,0xffbf + mtmsr %r12 + + lwz %r12,20(%r1) + lwz %r10,16(%r1) + lwz %r9,12(%r1) + lwz %r8,8(%r1) + + lwz %r3,4(%r1) + mtlr %r3 + lwz %r3,0(%r1) + + blr + +dsi_exc: + subi %r1,%r1,16 + + stw %r0,0(%r1) + stw %r3,4(%r1) + + mfsrr0 %r3 + addi %r3,%r3,4 + mtsrr0 %r3 + + /* mfsrr1 %r3 */ + /* ori %r3,%r3,2 */ + /* mtsrr1 %r3 */ + lwz %r3,4(%r1) + lwz %r0,0(%r1) + + addi %r1,%r1,16 + rfi +dsi_end: + .org 0x1000 freeldr_banner: .ascii "ReactOS OpenFirmware Boot Program\r\n\0" @@ -899,7 +1166,6 @@ freeldr_halt: freeldr_reg_init: .ascii "r\0" - freeldr_reg_lr: .ascii "lr \0" freeldr_reg_cr: @@ -933,6 +1199,18 @@ ofw_read_name: ofw_exit_name: .ascii "exit\0" +ofw_open_name: + .ascii "open\0" + +ofw_child_name: + .ascii "child\0" + +ofw_peer_name: + .ascii "peer\0" + +ofw_seek_name: + .ascii "seek\0" + ofw_chosen_name: .ascii "/chosen\0" @@ -954,6 +1232,10 @@ ofw_functions: .long ofw_print_regs .long ofw_print_string .long ofw_print_number + .long ofw_open + .long ofw_child + .long ofw_peer + .long ofw_seek .org 0x2000 stack: diff --git a/reactos/boot/freeldr/freeldr/arch/powerpc/boot.s b/reactos/boot/freeldr/freeldr/arch/powerpc/boot.s index 30c1f1c3e18..a507daafab4 100644 --- a/reactos/boot/freeldr/freeldr/arch/powerpc/boot.s +++ b/reactos/boot/freeldr/freeldr/arch/powerpc/boot.s @@ -1,3 +1,3 @@ .extern PpcInit _start: - b PpcInit + b PpcInit+4 diff --git a/reactos/boot/freeldr/freeldr/arch/powerpc/mach.c b/reactos/boot/freeldr/freeldr/arch/powerpc/mach.c index efd6addc775..401f0607f86 100644 --- a/reactos/boot/freeldr/freeldr/arch/powerpc/mach.c +++ b/reactos/boot/freeldr/freeldr/arch/powerpc/mach.c @@ -22,20 +22,18 @@ extern void BootMain( char * ); extern char *GetFreeLoaderVersionString(); -ULONG BootPartition = 0; -ULONG BootDrive = 0; - of_proxy ofproxy; void *PageDirectoryStart, *PageDirectoryEnd; -static int chosen_package, stdin_handle; +static int chosen_package, stdin_handle, part_handle = -1; BOOLEAN AcpiPresent = FALSE; -char BootPath[0x100]; +char BootPath[0x100] = { 0 }, BootPart[0x100] = { 0 }, CmdLine[0x100] = { 0 }; +jmp_buf jmp; -void le_swap( const void *start_addr_v, - const void *end_addr_v, +void le_swap( const void *start_addr_v, + const void *end_addr_v, const void *target_addr_v ) { - long *start_addr = (long *)ROUND_DOWN((long)start_addr_v,8), - *end_addr = (long *)ROUND_UP((long)end_addr_v,8), + long *start_addr = (long *)ROUND_DOWN((long)start_addr_v,8), + *end_addr = (long *)ROUND_UP((long)end_addr_v,8), *target_addr = (long *)ROUND_DOWN((long)target_addr_v,8); long tmp; while( start_addr <= end_addr ) { @@ -68,6 +66,7 @@ int ofw_getprop( int package, const char *name, void *buffer, int buflen ) { return ret; } +/* Since this is from external storage, it doesn't need swapping */ int ofw_write( int handle, const char *data, int len ) { int ret; le_swap( data, data + len, data ); @@ -77,12 +76,15 @@ int ofw_write( int handle, const char *data, int len ) { return ret; } +/* Since this is from external storage, it doesn't need swapping */ int ofw_read( int handle, const char *data, int len ) { int ret; + le_swap( data, data + len, data ); ret = ofproxy ( 12, (void *)handle, (char *)data, (void *)len, NULL ); le_swap( data, data + len, data ); + return ret; } @@ -105,14 +107,75 @@ void ofw_print_number( int num ) { ofproxy( 28, (void *)num, NULL, NULL, NULL ); } +int ofw_open( const char *name ) { + int ret, len; + + len = strlen(name); + le_swap( name, name + len, name ); + ret = ofproxy( 32, (char *)name, NULL, NULL, NULL ); + le_swap( name, name + len, name ); + return ret; +} + +int ofw_child( int package ) { + return ofproxy( 36, (void *)package, NULL, NULL, NULL ); +} + +int ofw_peer( int package ) { + return ofproxy( 40, (void *)package, NULL, NULL, NULL ); +} + +int ofw_seek( int handle, long long location ) { + return ofproxy( 44, (void *)handle, (void *)(int)(location >> 32), (void *)(int)location, NULL ); +} + void PpcPutChar( int ch ) { char buf[3]; - if( ch == 0x0a ) { buf[0] = 0x0d; buf[1] = 0x0a; } + if( ch == 0x0a ) { buf[0] = 0x0d; buf[1] = 0x0a; } else { buf[0] = ch; buf[1] = 0; } buf[2] = 0; ofw_print_string( buf ); } +int PpcFindDevice( int depth, int parent, char *devname, int *nth ) { + static char buf[256]; + int next = 0; + int gotname = 0; + int match = 0; + int i; + + next = ofw_child( parent ); + + //printf( "next = %x\n", next ); + + gotname = ofw_getprop(parent, "name", buf, 256); + + //printf( "gotname = %d\n", gotname ); + + match = !strncmp(buf, devname, strlen(devname)); + + if( !nth && match ) return parent; + else if( match ) *nth--; + + for( i = 0; i < depth; i++ ) PpcPutChar( ' ' ); + + if( depth == 1 ) { + if( gotname > 0 ) { + printf( "%c Name: %s\n", match ? '*' : ' ', buf ); + } else { + printf( "- No name attribute for %x\n", parent ); + } + } + + while( !match && next ) { + i = PpcFindDevice( depth+1, next, devname, nth ); + if( i ) return i; + next = ofw_peer( next ); + } + + return 0; +} + BOOL PpcConsKbHit() { return TRUE; } @@ -167,12 +230,12 @@ BOOL PpcVideoIsPaletteFixed() { return FALSE; } -VOID PpcVideoSetPaletteColor( UCHAR Color, +VOID PpcVideoSetPaletteColor( UCHAR Color, UCHAR Red, UCHAR Green, UCHAR Blue ) { printf( "SetPaletteColor(%x,%x,%x,%x)\n", Color, Red, Green, Blue ); } -VOID PpcVideoGetPaletteColor( UCHAR Color, +VOID PpcVideoGetPaletteColor( UCHAR Color, UCHAR *Red, UCHAR *Green, UCHAR *Blue ) { printf( "GetPaletteColor(%x)\n", Color); } @@ -198,16 +261,74 @@ ULONG PpcGetMemoryMap( PBIOS_MEMORY_MAP BiosMemoryMap, BiosMemoryMap[0].BaseAddress = 0; BiosMemoryMap[0].Length = 32 * 1024 * 1024; /* Assume 32 meg for now */ - printf( "Returning memory map (%dk total)\n", + printf( "Returning memory map (%dk total)\n", (int)BiosMemoryMap[0].Length / 1024 ); return 1; } +/* Strategy: + * + * For now, it'll be easy enough to use the boot command line as our boot path. + * Treat it as the path of a disk partition. We might even be able to get + * away with grabbing a partition image by tftp in this scenario. + */ + +BOOL PpcDiskGetBootVolume( PULONG DriveNumber, PULONGLONG StartSector, PULONGLONG SectorCount, int *FsType ) { + *DriveNumber = 0; + *StartSector = 0; + *SectorCount = 0; + *FsType = FS_FAT; + return TRUE; +} + +BOOL PpcDiskGetSystemVolume( char *SystemPath, + char *RemainingPath, + PULONG Device, + PULONG DriveNumber, + PULONGLONG StartSector, + PULONGLONG SectorCount, + int *FsType ) { + return FALSE; +} + +BOOL PpcDiskGetBootPath( char *OutBootPath, unsigned Size ) { + strncpy( OutBootPath, BootPath, Size ); + return TRUE; +} + +VOID PpcDiskGetBootDevice( PULONG BootDevice ) { + BootDevice[0] = BootDevice[1] = 0; +} + +BOOL PpcDiskBootingFromFloppy(VOID) { + return FALSE; +} + BOOL PpcDiskReadLogicalSectors( ULONG DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer ) { - printf("DiskReadLogicalSectors\n"); - return FALSE; + int rlen = 0; + + if( part_handle == -1 ) { + part_handle = ofw_open( BootPart ); + + if( part_handle == -1 ) { + printf("Could not open any disk devices we know about\n"); + return FALSE; + } + } + + if( part_handle == -1 ) { + printf("Got partition handle %x\n", part_handle); + return FALSE; + } + + if( ofw_seek( part_handle, SectorNumber * 512 ) ) { + printf("Seek to %x failed\n", SectorNumber * 512); + return FALSE; + } + rlen = ofw_read( part_handle, Buffer, SectorCount * 512 ); + return rlen > 0; } BOOL PpcDiskGetPartitionEntry( ULONG DriveNumber, ULONG PartitionNumber, @@ -218,24 +339,32 @@ BOOL PpcDiskGetPartitionEntry( ULONG DriveNumber, ULONG PartitionNumber, BOOL PpcDiskGetDriveGeometry( ULONG DriveNumber, PGEOMETRY DriveGeometry ) { printf("GetGeometry(%d)\n", DriveNumber); - return FALSE; + DriveGeometry->BytesPerSector = 512; + DriveGeometry->Heads = 16; + DriveGeometry->Sectors = 63; + return TRUE; } ULONG PpcDiskGetCacheableBlockCount( ULONG DriveNumber ) { printf("GetCacheableBlockCount\n"); - return 0; + return 1; } -VOID PpcRTCGetCurrentDateTime( PULONG Hear, PULONG Month, PULONG Day, +VOID PpcRTCGetCurrentDateTime( PULONG Hear, PULONG Month, PULONG Day, PULONG Hour, PULONG Minute, PULONG Second ) { printf("RTCGeturrentDateTime\n"); } VOID PpcHwDetect() { + printf("PpcHwDetect\n"); } +typedef unsigned int uint32_t; + void PpcInit( of_proxy the_ofproxy ) { + int len; ofproxy = the_ofproxy; + chosen_package = ofw_finddevice( "/chosen" ); ofw_getprop( chosen_package, "stdin", @@ -246,8 +375,8 @@ void PpcInit( of_proxy the_ofproxy ) { MachVtbl.ConsPutChar = PpcPutChar; MachVtbl.ConsKbHit = PpcConsKbHit; MachVtbl.ConsGetCh = PpcConsGetCh; - - printf("chosen_package = %x\n", chosen_package); + + printf( "stdin_handle is %x\n", stdin_handle ); MachVtbl.VideoClearScreen = PpcVideoClearScreen; MachVtbl.VideoSetDisplayMode = PpcVideoSetDisplayMode; @@ -256,7 +385,7 @@ void PpcInit( of_proxy the_ofproxy ) { MachVtbl.VideoSetTextCursorPosition = PpcVideoSetTextCursorPosition; MachVtbl.VideoHideShowTextCursor = PpcVideoHideShowTextCursor; MachVtbl.VideoPutChar = PpcVideoPutChar; - MachVtbl.VideoCopyOffScreenBufferToVRAM = + MachVtbl.VideoCopyOffScreenBufferToVRAM = PpcVideoCopyOffScreenBufferToVRAM; MachVtbl.VideoIsPaletteFixed = PpcVideoIsPaletteFixed; MachVtbl.VideoSetPaletteColor = PpcVideoSetPaletteColor; @@ -266,6 +395,11 @@ void PpcInit( of_proxy the_ofproxy ) { MachVtbl.GetMemoryMap = PpcGetMemoryMap; + MachVtbl.DiskGetBootVolume = PpcDiskGetBootVolume; + MachVtbl.DiskGetSystemVolume = PpcDiskGetSystemVolume; + MachVtbl.DiskGetBootPath = PpcDiskGetBootPath; + MachVtbl.DiskGetBootDevice = PpcDiskGetBootDevice; + MachVtbl.DiskBootingFromFloppy = PpcDiskBootingFromFloppy; MachVtbl.DiskReadLogicalSectors = PpcDiskReadLogicalSectors; MachVtbl.DiskGetPartitionEntry = PpcDiskGetPartitionEntry; MachVtbl.DiskGetDriveGeometry = PpcDiskGetDriveGeometry; @@ -276,24 +410,57 @@ void PpcInit( of_proxy the_ofproxy ) { MachVtbl.HwDetect = PpcHwDetect; printf( "FreeLDR version [%s]\n", GetFreeLoaderVersionString() ); - BootMain("freeldr-ppc"); -} -void MachInit(const char *CmdLine) { - int len; - printf( "Determining boot device:\n" ); - len = ofw_getprop(chosen_package, "bootpath", - BootPath, sizeof(BootPath)); - printf( "Got %d bytes of path\n", len ); - BootPath[len] = 0; - printf( "Boot Path: %s\n", BootPath ); + len = ofw_getprop(chosen_package, "bootargs", + CmdLine, sizeof(CmdLine)); + + if( len < 0 ) len = 0; + CmdLine[len] = 0; - printf( "FreeLDR starting\n" ); + BootMain( CmdLine ); } -void FrLdrSetupPageDirectory() { +void MachInit(char *CmdLine) { + int len, i; + char *sep; + + BootPart[0] = 0; + BootPath[0] = 0; + + printf( "Determining boot device: [%s]\n", CmdLine ); + + printf( "Boot Args: %s\n", CmdLine ); + sep = NULL; + for( i = 0; i < strlen(CmdLine); i++ ) { + if( strncmp(CmdLine + i, "boot=", 5) == 0) { + strcpy(BootPart, CmdLine + i + 5); + sep = strchr(BootPart, ' '); + if( sep ) + *sep = 0; + break; + } + } + + if( strlen(BootPart) == 0 ) { + len = ofw_getprop(chosen_package, "bootpath", + BootPath, sizeof(BootPath)); + + if( len < 0 ) len = 0; + BootPath[len] = 0; + printf( "Boot Path: %s\n", BootPath ); + + sep = strrchr(BootPath, ','); + + strcpy(BootPart, BootPath); + if( sep ) { + BootPart[sep - BootPath] = 0; + } + } + + printf( "FreeLDR starting (boot partition: %s)\n", BootPart ); } +/* Compatibility functions that don't do much */ void beep() { } @@ -303,3 +470,18 @@ UCHAR STDCALL READ_PORT_UCHAR(PUCHAR Address) { void WRITE_PORT_UCHAR(PUCHAR Address, UCHAR Value) { } + +void DiskStopFloppyMotor() { +} + +void BootOldLinuxKernel( unsigned long size ) { + ofw_exit(); +} + +void BootNewLinuxKernel() { + ofw_exit(); +} + +void ChainLoadBiosBootSectorCode() { + ofw_exit(); +} diff --git a/reactos/boot/freeldr/freeldr/arch/powerpc/mboot.c b/reactos/boot/freeldr/freeldr/arch/powerpc/mboot.c new file mode 100644 index 00000000000..550a4c71dae --- /dev/null +++ b/reactos/boot/freeldr/freeldr/arch/powerpc/mboot.c @@ -0,0 +1,661 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: Freeloader + * FILE: boot/freeldr/freeldr/multiboot.c + * PURPOSE: ReactOS Loader + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + * Hartmut Birr - SMP/PAE Code + */ + +#include +#include + +#define NDEBUG +#include + +/* Base Addres of Kernel in Physical Memory */ +#define KERNEL_BASE_PHYS 0x200000 + +/* Bits to shift to convert a Virtual Address into an Offset in the Page Table */ +#define PFN_SHIFT 12 + +/* Bits to shift to convert a Virtual Address into an Offset in the Page Directory */ +#define PDE_SHIFT 20 +#define PDE_SHIFT_PAE 18 + + +/* Converts a Relative Address read from the Kernel into a Physical Address */ +#define RaToPa(p) \ + (ULONG_PTR)((ULONG_PTR)p + KERNEL_BASE_PHYS) + +/* Converts a Phsyical Address Pointer into a Page Frame Number */ +#define PaPtrToPfn(p) \ + (((ULONG_PTR)&p) >> PFN_SHIFT) + +/* Converts a Phsyical Address into a Page Frame Number */ +#define PaToPfn(p) \ + ((p) >> PFN_SHIFT) + +#define STARTUP_BASE 0xF0000000 +#define HYPERSPACE_BASE 0xF0800000 +#define APIC_BASE 0xFEC00000 +#define KPCR_BASE 0xFF000000 + +#define LowMemPageTableIndex 0 +#define StartupPageTableIndex (STARTUP_BASE >> 20) / sizeof(HARDWARE_PTE_X86) +#define HyperspacePageTableIndex (HYPERSPACE_BASE >> 20) / sizeof(HARDWARE_PTE_X86) +#define KpcrPageTableIndex (KPCR_BASE >> 20) / sizeof(HARDWARE_PTE_X86) +#define ApicPageTableIndex (APIC_BASE >> 20) / sizeof(HARDWARE_PTE_X86) + +#define LowMemPageTableIndexPae 0 +#define StartupPageTableIndexPae (STARTUP_BASE >> 21) +#define HyperspacePageTableIndexPae (HYPERSPACE_BASE >> 21) +#define KpcrPageTableIndexPae (KPCR_BASE >> 21) +#define ApicPageTableIndexPae (APIC_BASE >> 21) + + +#define KernelEntryPoint (KernelEntry - KERNEL_BASE_PHYS) + KernelBase + +/* Load Address of Next Module */ +ULONG_PTR NextModuleBase = 0; + +/* Currently Opened Module */ +PFRLDR_MODULE CurrentModule = NULL; + +/* Unrelocated Kernel Base in Virtual Memory */ +ULONG_PTR KernelBase; + +/* Wether PAE is to be used or not */ +BOOLEAN PaeModeEnabled; + +/* Kernel Entrypoint in Physical Memory */ +ULONG_PTR KernelEntry; + +/* FUNCTIONS *****************************************************************/ + +/*++ + * FrLdrStartup + * INTERNAL + * + * Prepares the system for loading the Kernel. + * + * Params: + * Magic - Multiboot Magic + * + * Returns: + * None. + * + * Remarks: + * None. + * + *--*/ +VOID +STDCALL +FrLdrStartup(ULONG Magic) +{ +#if 0 + /* Disable Interrupts */ + KeArchDisableInterrupts(); + + /* Re-initalize EFLAGS */ + KeArchEraseFlags(); + + /* Initialize the page directory */ + FrLdrSetupPageDirectory(); +#endif +} + +/*++ + * FrLdrGetKernelBase + * INTERNAL + * + * Gets the Kernel Base to use. + * + * Params: + * + * Returns: + * None. + * + * Remarks: + * Sets both the FreeLdr internal variable as well as the one which + * will be used by the Kernel. + * + *--*/ +VOID +FASTCALL +FrLdrGetKernelBase(VOID) +{ + PCHAR p; + + /* Read Command Line */ + p = (PCHAR)LoaderBlock.CommandLine; + while ((p = strchr(p, '/')) != NULL) { + + /* Find "/3GB" */ + if (!strnicmp(p + 1, "3GB", 3)) { + + /* Make sure there's nothing following it */ + if (p[4] == ' ' || p[4] == 0) { + + /* Use 3GB */ + KernelBase = 0xC0000000; + } + } + + p++; + } + + /* Set KernelBase */ + LoaderBlock.KernelBase = KernelBase; +} + +/*++ + * FrLdrSetupPageDirectory + * INTERNAL + * + * Sets up the ReactOS Startup Page Directory. + * + * Params: + * None. + * + * Returns: + * None. + * + * Remarks: + * We are setting PDEs, but using the equvivalent (for our purpose) PTE structure. + * As such, please note that PageFrameNumber == PageEntryNumber. + * + *--*/ +VOID +FASTCALL +FrLdrSetupPageDirectory(VOID) +{ +#if 0 + PPAGE_DIRECTORY_X86 PageDir; + PPAGE_DIRECTORY_TABLE_X64 PageDirTablePae; + PPAGE_DIRECTORY_X64 PageDirPae; + ULONG KernelPageTableIndex; + ULONG i; + + if (PaeModeEnabled) { + + /* Get the Kernel Table Index */ + KernelPageTableIndex = (KernelBase >> 21); + + /* Get the Startup Page Directory Table */ + PageDirTablePae = (PPAGE_DIRECTORY_TABLE_X64)&startup_pagedirectorytable_pae; + + /* Get the Startup Page Directory */ + PageDirPae = (PPAGE_DIRECTORY_X64)&startup_pagedirectory_pae; + + /* Set the Startup page directory table */ + for (i = 0; i < 4; i++) + { + PageDirTablePae->Pde[i].Valid = 1; + PageDirTablePae->Pde[i].PageFrameNumber = PaPtrToPfn(startup_pagedirectory_pae) + i; + } + + /* Set up the Low Memory PDE */ + for (i = 0; i < 2; i++) + { + PageDirPae->Pde[LowMemPageTableIndexPae + i].Valid = 1; + PageDirPae->Pde[LowMemPageTableIndexPae + i].Write = 1; + PageDirPae->Pde[LowMemPageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(lowmem_pagetable_pae) + i; + } + + /* Set up the Kernel PDEs */ + for (i = 0; i < 3; i++) + { + PageDirPae->Pde[KernelPageTableIndex + i].Valid = 1; + PageDirPae->Pde[KernelPageTableIndex + i].Write = 1; + PageDirPae->Pde[KernelPageTableIndex + i].PageFrameNumber = PaPtrToPfn(kernel_pagetable_pae) + i; + } + + /* Set up the Startup PDE */ + for (i = 0; i < 4; i++) + { + PageDirPae->Pde[StartupPageTableIndexPae + i].Valid = 1; + PageDirPae->Pde[StartupPageTableIndexPae + i].Write = 1; + PageDirPae->Pde[StartupPageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(startup_pagedirectory_pae) + i; + } + + /* Set up the Hyperspace PDE */ + for (i = 0; i < 2; i++) + { + PageDirPae->Pde[HyperspacePageTableIndexPae + i].Valid = 1; + PageDirPae->Pde[HyperspacePageTableIndexPae + i].Write = 1; + PageDirPae->Pde[HyperspacePageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(hyperspace_pagetable_pae) + i; + } + + /* Set up the Apic PDE */ + for (i = 0; i < 2; i++) + { + PageDirPae->Pde[ApicPageTableIndexPae + i].Valid = 1; + PageDirPae->Pde[ApicPageTableIndexPae + i].Write = 1; + PageDirPae->Pde[ApicPageTableIndexPae + i].PageFrameNumber = PaPtrToPfn(apic_pagetable_pae) + i; + } + + /* Set up the KPCR PDE */ + PageDirPae->Pde[KpcrPageTableIndexPae].Valid = 1; + PageDirPae->Pde[KpcrPageTableIndexPae].Write = 1; + PageDirPae->Pde[KpcrPageTableIndexPae].PageFrameNumber = PaPtrToPfn(kpcr_pagetable_pae); + + /* Set up Low Memory PTEs */ + PageDirPae = (PPAGE_DIRECTORY_X64)&lowmem_pagetable_pae; + for (i=0; i<1024; i++) { + + PageDirPae->Pde[i].Valid = 1; + PageDirPae->Pde[i].Write = 1; + PageDirPae->Pde[i].Owner = 1; + PageDirPae->Pde[i].PageFrameNumber = i; + } + + /* Set up Kernel PTEs */ + PageDirPae = (PPAGE_DIRECTORY_X64)&kernel_pagetable_pae; + for (i=0; i<1536; i++) { + + PageDirPae->Pde[i].Valid = 1; + PageDirPae->Pde[i].Write = 1; + PageDirPae->Pde[i].PageFrameNumber = PaToPfn(KERNEL_BASE_PHYS) + i; + } + + /* Set up APIC PTEs */ + PageDirPae = (PPAGE_DIRECTORY_X64)&apic_pagetable_pae; + PageDirPae->Pde[0].Valid = 1; + PageDirPae->Pde[0].Write = 1; + PageDirPae->Pde[0].CacheDisable = 1; + PageDirPae->Pde[0].WriteThrough = 1; + PageDirPae->Pde[0].PageFrameNumber = PaToPfn(APIC_BASE); + PageDirPae->Pde[0x200].Valid = 1; + PageDirPae->Pde[0x200].Write = 1; + PageDirPae->Pde[0x200].CacheDisable = 1; + PageDirPae->Pde[0x200].WriteThrough = 1; + PageDirPae->Pde[0x200].PageFrameNumber = PaToPfn(APIC_BASE + KERNEL_BASE_PHYS); + + /* Set up KPCR PTEs */ + PageDirPae = (PPAGE_DIRECTORY_X64)&kpcr_pagetable_pae; + PageDirPae->Pde[0].Valid = 1; + PageDirPae->Pde[0].Write = 1; + PageDirPae->Pde[0].PageFrameNumber = 1; + + } else { + + /* Get the Kernel Table Index */ + KernelPageTableIndex = (KernelBase >> PDE_SHIFT) / sizeof(HARDWARE_PTE_X86); + + /* Get the Startup Page Directory */ + PageDir = (PPAGE_DIRECTORY_X86)&startup_pagedirectory; + + /* Set up the Low Memory PDE */ + PageDir->Pde[LowMemPageTableIndex].Valid = 1; + PageDir->Pde[LowMemPageTableIndex].Write = 1; + PageDir->Pde[LowMemPageTableIndex].PageFrameNumber = PaPtrToPfn(lowmem_pagetable); + + /* Set up the Kernel PDEs */ + PageDir->Pde[KernelPageTableIndex].Valid = 1; + PageDir->Pde[KernelPageTableIndex].Write = 1; + PageDir->Pde[KernelPageTableIndex].PageFrameNumber = PaPtrToPfn(kernel_pagetable); + PageDir->Pde[KernelPageTableIndex + 1].Valid = 1; + PageDir->Pde[KernelPageTableIndex + 1].Write = 1; + PageDir->Pde[KernelPageTableIndex + 1].PageFrameNumber = PaPtrToPfn(kernel_pagetable + 4096); + + /* Set up the Startup PDE */ + PageDir->Pde[StartupPageTableIndex].Valid = 1; + PageDir->Pde[StartupPageTableIndex].Write = 1; + PageDir->Pde[StartupPageTableIndex].PageFrameNumber = PaPtrToPfn(startup_pagedirectory); + + /* Set up the Hyperspace PDE */ + PageDir->Pde[HyperspacePageTableIndex].Valid = 1; + PageDir->Pde[HyperspacePageTableIndex].Write = 1; + PageDir->Pde[HyperspacePageTableIndex].PageFrameNumber = PaPtrToPfn(hyperspace_pagetable); + + /* Set up the Apic PDE */ + PageDir->Pde[ApicPageTableIndex].Valid = 1; + PageDir->Pde[ApicPageTableIndex].Write = 1; + PageDir->Pde[ApicPageTableIndex].PageFrameNumber = PaPtrToPfn(apic_pagetable); + + /* Set up the KPCR PDE */ + PageDir->Pde[KpcrPageTableIndex].Valid = 1; + PageDir->Pde[KpcrPageTableIndex].Write = 1; + PageDir->Pde[KpcrPageTableIndex].PageFrameNumber = PaPtrToPfn(kpcr_pagetable); + + /* Set up Low Memory PTEs */ + PageDir = (PPAGE_DIRECTORY_X86)&lowmem_pagetable; + for (i=0; i<1024; i++) { + + PageDir->Pde[i].Valid = 1; + PageDir->Pde[i].Write = 1; + PageDir->Pde[i].Owner = 1; + PageDir->Pde[i].PageFrameNumber = PaToPfn(i * PAGE_SIZE); + } + + /* Set up Kernel PTEs */ + PageDir = (PPAGE_DIRECTORY_X86)&kernel_pagetable; + for (i=0; i<1536; i++) { + + PageDir->Pde[i].Valid = 1; + PageDir->Pde[i].Write = 1; + PageDir->Pde[i].PageFrameNumber = PaToPfn(KERNEL_BASE_PHYS + i * PAGE_SIZE); + } + + /* Set up APIC PTEs */ + PageDir = (PPAGE_DIRECTORY_X86)&apic_pagetable; + PageDir->Pde[0].Valid = 1; + PageDir->Pde[0].Write = 1; + PageDir->Pde[0].CacheDisable = 1; + PageDir->Pde[0].WriteThrough = 1; + PageDir->Pde[0].PageFrameNumber = PaToPfn(APIC_BASE); + PageDir->Pde[0x200].Valid = 1; + PageDir->Pde[0x200].Write = 1; + PageDir->Pde[0x200].CacheDisable = 1; + PageDir->Pde[0x200].WriteThrough = 1; + PageDir->Pde[0x200].PageFrameNumber = PaToPfn(APIC_BASE + KERNEL_BASE_PHYS); + + /* Set up KPCR PTEs */ + PageDir = (PPAGE_DIRECTORY_X86)&kpcr_pagetable; + PageDir->Pde[0].Valid = 1; + PageDir->Pde[0].Write = 1; + PageDir->Pde[0].PageFrameNumber = 1; + } + return; +#endif +} + +/*++ + * FrLdrMapKernel + * INTERNAL + * + * Maps the Kernel into memory, does PE Section Mapping, initalizes the + * uninitialized data sections, and relocates the image. + * + * Params: + * KernelImage - FILE Structure representing the ntoskrnl image file. + * + * Returns: + * TRUE if the Kernel was mapped. + * + * Remarks: + * None. + * + *--*/ +BOOL +STDCALL +FrLdrMapKernel(FILE *KernelImage) +{ +#if 0 + PIMAGE_DOS_HEADER ImageHeader; + PIMAGE_NT_HEADERS NtHeader; + PIMAGE_SECTION_HEADER Section; + ULONG SectionCount; + ULONG ImageSize; + ULONG_PTR SourceSection; + ULONG_PTR TargetSection; + ULONG SectionSize; + LONG i; + PIMAGE_DATA_DIRECTORY RelocationDDir; + PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd; + ULONG Count; + ULONG_PTR Address, MaxAddress; + PUSHORT TypeOffset; + ULONG_PTR Delta; + PUSHORT ShortPtr; + PULONG LongPtr; + + /* Allocate 1024 bytes for PE Header */ + ImageHeader = (PIMAGE_DOS_HEADER)MmAllocateMemory(1024); + + /* Make sure it was succesful */ + if (ImageHeader == NULL) { + + return FALSE; + } + + /* Load the first 1024 bytes of the kernel image so we can read the PE header */ + if (!FsReadFile(KernelImage, 1024, NULL, ImageHeader)) { + + /* Fail if we couldn't read */ + MmFreeMemory(ImageHeader); + return FALSE; + } + + /* Now read the MZ header to get the offset to the PE Header */ + NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)ImageHeader + ImageHeader->e_lfanew); + + /* Get Kernel Base */ + KernelBase = NtHeader->OptionalHeader.ImageBase; + FrLdrGetKernelBase(); + + /* Save Entrypoint */ + KernelEntry = RaToPa(NtHeader->OptionalHeader.AddressOfEntryPoint); + + /* Save the Image Size */ + ImageSize = NtHeader->OptionalHeader.SizeOfImage; + + /* Free the Header */ + MmFreeMemory(ImageHeader); + + /* Set the file pointer to zero */ + FsSetFilePointer(KernelImage, 0); + + /* Load the file image */ + FsReadFile(KernelImage, ImageSize, NULL, (PVOID)KERNEL_BASE_PHYS); + + /* Reload the NT Header */ + NtHeader = (PIMAGE_NT_HEADERS)((PCHAR)KERNEL_BASE_PHYS + ImageHeader->e_lfanew); + + /* Load the first section */ + Section = IMAGE_FIRST_SECTION(NtHeader); + SectionCount = NtHeader->FileHeader.NumberOfSections - 1; + + /* Now go to the last section */ + Section += SectionCount; + + /* Walk each section backwards */ + for (i=SectionCount; i >= 0; i--, Section--) { + + /* Get the disk location and the memory location, and the size */ + SourceSection = RaToPa(Section->PointerToRawData); + TargetSection = RaToPa(Section->VirtualAddress); + SectionSize = Section->SizeOfRawData; + + /* If the section is already mapped correctly, go to the next */ + if (SourceSection == TargetSection) continue; + + /* Load it into memory */ + memmove((PVOID)TargetSection, (PVOID)SourceSection, SectionSize); + + /* Check for unitilizated data */ + if (Section->SizeOfRawData < Section->Misc.VirtualSize) { + + /* Zero it out */ + memset((PVOID)RaToPa(Section->VirtualAddress + Section->SizeOfRawData), + 0, + Section->Misc.VirtualSize - Section->SizeOfRawData); + } + } + + /* Get the Relocation Data Directory */ + RelocationDDir = &NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + + /* Get the Relocation Section Start and End*/ + RelocationDir = (PIMAGE_BASE_RELOCATION)(KERNEL_BASE_PHYS + RelocationDDir->VirtualAddress); + RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDDir->Size); + + /* Calculate Difference between Real Base and Compiled Base*/ + Delta = KernelBase - NtHeader->OptionalHeader.ImageBase;; + + /* Determine how far we shoudl relocate */ + MaxAddress = KERNEL_BASE_PHYS + ImageSize; + + /* Relocate until we've processed all the blocks */ + while (RelocationDir < RelocationEnd && RelocationDir->SizeOfBlock > 0) { + + /* See how many Relocation Blocks we have */ + Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT); + + /* Calculate the Address of this Directory */ + Address = KERNEL_BASE_PHYS + RelocationDir->VirtualAddress; + + /* Calculate the Offset of the Type */ + TypeOffset = (PUSHORT)(RelocationDir + 1); + + for (i = 0; i < Count; i++) { + + ShortPtr = (PUSHORT)(Address + (*TypeOffset & 0xFFF)); + + /* Don't relocate after the end of the loaded driver */ + if ((ULONG_PTR)ShortPtr >= MaxAddress) break; + + switch (*TypeOffset >> 12) { + + case IMAGE_REL_BASED_ABSOLUTE: + break; + + case IMAGE_REL_BASED_HIGH: + *ShortPtr += HIWORD(Delta); + break; + + case IMAGE_REL_BASED_LOW: + *ShortPtr += LOWORD(Delta); + break; + + case IMAGE_REL_BASED_HIGHLOW: + LongPtr = (PULONG)ShortPtr; + *LongPtr += Delta; + break; + } + + TypeOffset++; + } + + /* Move to the next Relocation Table */ + RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + RelocationDir->SizeOfBlock); + } + + /* Increase the next Load Base */ + NextModuleBase = ROUND_UP(KERNEL_BASE_PHYS + ImageSize, PAGE_SIZE); + + /* Return Success */ +#endif + return TRUE; +} + +ULONG_PTR +STDCALL +FrLdrLoadModule(FILE *ModuleImage, + LPSTR ModuleName, + PULONG ModuleSize) +{ +#if 0 + ULONG LocalModuleSize; + PFRLDR_MODULE ModuleData; + LPSTR NameBuffer; + LPSTR TempName; + + /* Get current module data structure and module name string array */ + ModuleData = &multiboot_modules[LoaderBlock.ModsCount]; + + /* Get only the Module Name */ + do { + + TempName = strchr(ModuleName, '\\'); + + if(TempName) { + ModuleName = TempName + 1; + } + + } while(TempName); + NameBuffer = multiboot_module_strings[LoaderBlock.ModsCount]; + + /* Get Module Size */ + LocalModuleSize = FsGetFileSize(ModuleImage); + + /* Fill out Module Data Structure */ + ModuleData->ModuleStart = NextModuleBase; + ModuleData->ModuleEnd = NextModuleBase + LocalModuleSize; + + /* Save name */ + strcpy(NameBuffer, ModuleName); + ModuleData->ModuleName = NameBuffer; + + /* Load the file image */ + FsReadFile(ModuleImage, LocalModuleSize, NULL, (PVOID)NextModuleBase); + + /* Move to next memory block and increase Module Count */ + NextModuleBase = ROUND_UP(ModuleData->ModuleEnd, PAGE_SIZE); + LoaderBlock.ModsCount++; + + /* Return Module Size if required */ + if (ModuleSize != NULL) { + *ModuleSize = LocalModuleSize; + } + + return(ModuleData->ModuleStart); +#else + return 0; +#endif +} + +ULONG_PTR +STDCALL +FrLdrCreateModule(LPSTR ModuleName) +{ +#if 0 + PFRLDR_MODULE ModuleData; + LPSTR NameBuffer; + + /* Get current module data structure and module name string array */ + ModuleData = &multiboot_modules[LoaderBlock.ModsCount]; + NameBuffer = multiboot_module_strings[LoaderBlock.ModsCount]; + + /* Set up the structure */ + ModuleData->ModuleStart = NextModuleBase; + ModuleData->ModuleEnd = -1; + + /* Copy the name */ + strcpy(NameBuffer, ModuleName); + ModuleData->ModuleName = NameBuffer; + + /* Set the current Module */ + CurrentModule = ModuleData; + + /* Return Module Base Address */ + return(ModuleData->ModuleStart); +#else + return 0; +#endif +} + +BOOL +STDCALL +FrLdrCloseModule(ULONG_PTR ModuleBase, + ULONG ModuleSize) +{ +#if 0 + PFRLDR_MODULE ModuleData = CurrentModule; + + /* Make sure a module is opened */ + if (ModuleData) { + + /* Make sure this is the right module and that it hasn't been closed */ + if ((ModuleBase == ModuleData->ModuleStart) && (ModuleData->ModuleEnd == -1)) { + + /* Close the Module */ + ModuleData->ModuleEnd = ModuleData->ModuleStart + ModuleSize; + + /* Set the next Module Base and increase the number of modules */ + NextModuleBase = ROUND_UP(ModuleData->ModuleEnd, PAGE_SIZE); + LoaderBlock.ModsCount++; + + /* Close the currently opened module */ + CurrentModule = NULL; + + /* Success */ + return(TRUE); + } + } + + /* Failure path */ +#endif + return(FALSE); +}