From 7cd6896619d98b64c2b422bf94591fc6c63f1a2f Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Fri, 25 Jan 2008 11:19:11 +0000 Subject: [PATCH] - Don't store memory allocation descriptors inside the bootloader, since this memory is unmapped in kernelmode. Fixes a pagefault after switching to paged mode. - Store the configuration data in the LPB. svn path=/trunk/; revision=31983 --- reactos/boot/freeldr/freeldr/windows/winldr.c | 1164 +++++------ .../boot/freeldr/freeldr/windows/wlmemory.c | 1795 +++++++++-------- 2 files changed, 1481 insertions(+), 1478 deletions(-) diff --git a/reactos/boot/freeldr/freeldr/windows/winldr.c b/reactos/boot/freeldr/freeldr/windows/winldr.c index 2cfb680c72b..48ec22e41cd 100644 --- a/reactos/boot/freeldr/freeldr/windows/winldr.c +++ b/reactos/boot/freeldr/freeldr/windows/winldr.c @@ -1,582 +1,582 @@ -/* - * FreeLoader - * - * Copyright (C) 1998-2003 Brian Palmer - * Copyright (C) 2006 Aleksey Bragin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#include -#include - -//FIXME: Do a better way to retrieve Arc disk information -extern ULONG reactos_disk_count; -extern ARC_DISK_SIGNATURE reactos_arc_disk_info[]; -extern char reactos_arc_strings[32][256]; - -BOOLEAN -WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock, - IN PCH DllName, - OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry); - -// debug stuff -VOID DumpMemoryAllocMap(VOID); -VOID WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock); -VOID WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock); -VOID WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock); - - -// Init "phase 0" -VOID -AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock) -{ - PLOADER_PARAMETER_BLOCK LoaderBlock; - - /* Allocate and zero-init the LPB */ - LoaderBlock = MmHeapAlloc(sizeof(LOADER_PARAMETER_BLOCK)); - RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK)); - - /* Init three critical lists, used right away */ - InitializeListHead(&LoaderBlock->LoadOrderListHead); - InitializeListHead(&LoaderBlock->MemoryDescriptorListHead); - InitializeListHead(&LoaderBlock->BootDriverListHead); - - /* Alloc space for NLS (it will be converted to VA in WinLdrLoadNLS) */ - LoaderBlock->NlsData = MmHeapAlloc(sizeof(NLS_DATA_BLOCK)); - if (LoaderBlock->NlsData == NULL) - { - UiMessageBox("Failed to allocate memory for NLS table data!"); - return; - } - RtlZeroMemory(LoaderBlock->NlsData, sizeof(NLS_DATA_BLOCK)); - - *OutLoaderBlock = LoaderBlock; -} - -// Init "phase 1" -VOID -WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock, - PCHAR Options, - PCHAR SystemPath, - WORD VersionToBoot) -{ - /* Examples of correct options and paths */ - //CHAR Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200"; - //CHAR Options[] = "/NODEBUG"; - //CHAR SystemRoot[] = "\\WINNT\\"; - //CHAR ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)"; - - CHAR HalPath[] = "\\"; - CHAR SystemRoot[256]; - CHAR ArcBoot[256]; - ULONG i, PathSeparator; - PLOADER_PARAMETER_EXTENSION Extension; - - LoaderBlock->u.I386.CommonDataArea = NULL; // Force No ABIOS support - - /* Construct SystemRoot and ArcBoot from SystemPath */ - PathSeparator = strstr(SystemPath, "\\") - SystemPath; - strncpy(ArcBoot, SystemPath, PathSeparator); - ArcBoot[PathSeparator] = 0; - strcpy(SystemRoot, &SystemPath[PathSeparator]); - strcat(SystemRoot, "\\"); - - DbgPrint((DPRINT_WINDOWS, "ArcBoot: %s\n", ArcBoot)); - DbgPrint((DPRINT_WINDOWS, "SystemRoot: %s\n", SystemRoot)); - DbgPrint((DPRINT_WINDOWS, "Options: %s\n", Options)); - - /* Fill Arc BootDevice */ - LoaderBlock->ArcBootDeviceName = MmHeapAlloc(strlen(ArcBoot)+1); - strcpy(LoaderBlock->ArcBootDeviceName, ArcBoot); - LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName); - - /* Fill Arc HalDevice, it matches ArcBoot path */ - LoaderBlock->ArcHalDeviceName = MmHeapAlloc(strlen(ArcBoot)+1); - strcpy(LoaderBlock->ArcHalDeviceName, ArcBoot); - LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName); - - /* Fill SystemRoot */ - LoaderBlock->NtBootPathName = MmHeapAlloc(strlen(SystemRoot)+1); - strcpy(LoaderBlock->NtBootPathName, SystemRoot); - LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName); - - /* Fill NtHalPathName */ - LoaderBlock->NtHalPathName = MmHeapAlloc(strlen(HalPath)+1); - strcpy(LoaderBlock->NtHalPathName, HalPath); - LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName); - - /* Fill load options */ - LoaderBlock->LoadOptions = MmHeapAlloc(strlen(Options)+1); - strcpy(LoaderBlock->LoadOptions, Options); - LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions); - - /* Arc devices */ - LoaderBlock->ArcDiskInformation = (PARC_DISK_INFORMATION)MmHeapAlloc(sizeof(ARC_DISK_INFORMATION)); - InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead); - - /* Convert ARC disk information from freeldr to a correct format */ - for (i = 0; i < reactos_disk_count; i++) - { - PARC_DISK_SIGNATURE ArcDiskInfo; - - /* Get the ARC structure */ - ArcDiskInfo = (PARC_DISK_SIGNATURE)MmHeapAlloc(sizeof(ARC_DISK_SIGNATURE)); - RtlZeroMemory(ArcDiskInfo, sizeof(ARC_DISK_SIGNATURE)); - - /* Copy the data over */ - ArcDiskInfo->Signature = reactos_arc_disk_info[i].Signature; - ArcDiskInfo->CheckSum = reactos_arc_disk_info[i].CheckSum; - - /* Copy the ARC Name */ - ArcDiskInfo->ArcName = (PCHAR)MmHeapAlloc(sizeof(CHAR)*256); - strcpy(ArcDiskInfo->ArcName, reactos_arc_disk_info[i].ArcName); - ArcDiskInfo->ArcName = (PCHAR)PaToVa(ArcDiskInfo->ArcName); - - /* Mark partition table as valid */ - ArcDiskInfo->ValidPartitionTable = TRUE; - - /* Insert into the list */ - InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead, - &ArcDiskInfo->ListEntry); - } - - /* Convert all list's to Virtual address */ - - /* Convert the ArcDisks list to virtual address */ - List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead); - LoaderBlock->ArcDiskInformation = PaToVa(LoaderBlock->ArcDiskInformation); - - /* Convert configuration entries to VA */ - ConvertConfigToVA(LoaderBlock->ConfigurationRoot); - LoaderBlock->ConfigurationRoot = PaToVa(LoaderBlock->ConfigurationRoot); - - /* Convert all DTE into virtual addresses */ - List_PaToVa(&LoaderBlock->LoadOrderListHead); - - /* this one will be converted right before switching to - virtual paging mode */ - //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead); - - /* Convert list of boot drivers */ - List_PaToVa(&LoaderBlock->BootDriverListHead); - - /* Initialize Extension now */ - Extension = MmHeapAlloc(sizeof(LOADER_PARAMETER_EXTENSION)); - if (Extension == NULL) - { - UiMessageBox("Failed to allocate LPB Extension!"); - return; - } - RtlZeroMemory(Extension, sizeof(LOADER_PARAMETER_EXTENSION)); - - /* Save size and version information */ - Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION); - Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8; - Extension->MinorVersion = VersionToBoot & 0xFF; - - - LoaderBlock->Extension = PaToVa(Extension); -} - -// Last step before going virtual -void WinLdrSetupForNt(PLOADER_PARAMETER_BLOCK LoaderBlock, - PVOID *GdtIdt, - ULONG *PcrBasePage, - ULONG *TssBasePage) -{ - ULONG TssSize; - ULONG TssPages; - ULONG_PTR Pcr = 0; - ULONG_PTR Tss = 0; - ULONG BlockSize, NumPages; - - LoaderBlock->u.I386.CommonDataArea = NULL;//CommonDataArea; - //LoaderBlock->u.I386.MachineType = MachineType; //FIXME: MachineType? - - /* Allocate 2 pages for PCR */ - Pcr = (ULONG_PTR)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE, LoaderStartupPcrPage); - *PcrBasePage = Pcr >> MM_PAGE_SHIFT; - - if (Pcr == 0) - { - UiMessageBox("Can't allocate PCR\n"); - return; - } - - /* Allocate TSS */ - TssSize = (sizeof(KTSS) + MM_PAGE_SIZE) & ~(MM_PAGE_SIZE - 1); - TssPages = TssSize / MM_PAGE_SIZE; - - Tss = (ULONG_PTR)MmAllocateMemoryWithType(TssSize, LoaderMemoryData); - - *TssBasePage = Tss >> MM_PAGE_SHIFT; - - /* Allocate space for new GDT + IDT */ - BlockSize = NUM_GDT*sizeof(KGDTENTRY) + NUM_IDT*sizeof(KIDTENTRY);//FIXME: Use GDT/IDT limits here? - NumPages = (BlockSize + MM_PAGE_SIZE - 1) >> MM_PAGE_SHIFT; - *GdtIdt = (PKGDTENTRY)MmAllocateMemoryWithType(NumPages * MM_PAGE_SIZE, LoaderMemoryData); - - if (*GdtIdt == NULL) - { - UiMessageBox("Can't allocate pages for GDT+IDT!\n"); - return; - } - - /* Zero newly prepared GDT+IDT */ - RtlZeroMemory(*GdtIdt, NumPages << MM_PAGE_SHIFT); -} - -BOOLEAN -WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock, - LPSTR BootPath, - PUNICODE_STRING FilePath, - ULONG Flags, - PLDR_DATA_TABLE_ENTRY *DriverDTE) -{ - CHAR FullPath[1024]; - CHAR DriverPath[1024]; - CHAR DllName[1024]; - PCHAR DriverNamePos; - BOOLEAN Status; - PVOID DriverBase; - - // Separate the path to file name and directory path - sprintf(DriverPath, "%wZ", FilePath); - DriverNamePos = strrchr(DriverPath, '\\'); - if (DriverNamePos != NULL) - { - // Copy the name - strcpy(DllName, DriverNamePos+1); - - // Cut out the name from the path - *(DriverNamePos+1) = 0; - } - - DbgPrint((DPRINT_WINDOWS, "DriverPath: %s, DllName: %s, LPB %p\n", DriverPath, DllName, LoaderBlock)); - - - // Check if driver is already loaded - Status = WinLdrCheckForLoadedDll(LoaderBlock, DllName, DriverDTE); - if (Status) - { - // We've got the pointer to its DTE, just return success - return TRUE; - } - - // It's not loaded, we have to load it - sprintf(FullPath,"%s%wZ", BootPath, FilePath); - Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase); - if (!Status) - return FALSE; - - // Allocate a DTE for it - Status = WinLdrAllocateDataTableEntry(LoaderBlock, DllName, DllName, DriverBase, DriverDTE); - if (!Status) - { - DbgPrint((DPRINT_WINDOWS, "WinLdrAllocateDataTableEntry() failed\n")); - return FALSE; - } - - // Modify any flags, if needed - (*DriverDTE)->Flags |= Flags; - - // Look for any dependencies it may have, and load them too - sprintf(FullPath,"%s%s", BootPath, DriverPath); - Status = WinLdrScanImportDescriptorTable(LoaderBlock, FullPath, *DriverDTE); - if (!Status) - { - DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable() failed for %s\n", - FullPath)); - return FALSE; - } - - return TRUE; -} - -BOOLEAN -WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock, - LPSTR BootPath) -{ - PLIST_ENTRY NextBd; - PBOOT_DRIVER_LIST_ENTRY BootDriver; - BOOLEAN Status; - - // Walk through the boot drivers list - NextBd = LoaderBlock->BootDriverListHead.Flink; - - while (NextBd != &LoaderBlock->BootDriverListHead) - { - BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, ListEntry); - - DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath, - BootDriver->DataTableEntry, &BootDriver->RegistryPath)); - - // Paths are relative (FIXME: Are they always relative?) - - // Load it - Status = WinLdrLoadDeviceDriver(LoaderBlock, BootPath, &BootDriver->FilePath, - 0, &BootDriver->DataTableEntry); - - // If loading failed - cry loudly - //FIXME: Maybe remove it from the list and try to continue? - if (!Status) - { - UiMessageBox("Can't load boot driver!"); - return FALSE; - } - - // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore - BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer); - BootDriver->DataTableEntry = PaToVa(BootDriver->DataTableEntry); - - NextBd = BootDriver->ListEntry.Flink; - } - - return TRUE; -} - -VOID -LoadAndBootWindows(PCSTR OperatingSystemName, WORD OperatingSystemVersion) -{ - CHAR MsgBuffer[256]; - CHAR SystemPath[512], SearchPath[512]; - CHAR FileName[512]; - CHAR BootPath[512]; - CHAR BootOptions[256]; - PVOID NtosBase = NULL, HalBase = NULL, KdComBase = NULL; - BOOLEAN Status; - ULONG SectionId; - ULONG BootDevice; - PLOADER_PARAMETER_BLOCK LoaderBlock, LoaderBlockVA; - KERNEL_ENTRY_POINT KiSystemStartup; - PLDR_DATA_TABLE_ENTRY KernelDTE, HalDTE, KdComDTE = NULL; - // Mm-related things - PVOID GdtIdt; - ULONG PcrBasePage=0; - ULONG TssBasePage=0; - - //sprintf(MsgBuffer,"Booting Microsoft(R) Windows(R) OS version '%04x' is not implemented yet", OperatingSystemVersion); - //UiMessageBox(MsgBuffer); - - // Open the operating system section - // specified in the .ini file - if (!IniOpenSection(OperatingSystemName, &SectionId)) - { - sprintf(MsgBuffer,"Operating System section '%s' not found in freeldr.ini", OperatingSystemName); - UiMessageBox(MsgBuffer); - return; - } - - UiDrawBackdrop(); - UiDrawStatusText("Detecting Hardware..."); - UiDrawProgressBarCenter(1, 100, "Loading Windows..."); - - /* Make sure the system path is set in the .ini file */ - if (!IniReadSettingByName(SectionId, "SystemPath", SystemPath, sizeof(SystemPath))) - { - UiMessageBox("System path not specified for selected operating system."); - return; - } - - /* Read booting options */ - if (!IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions))) - { - /* Nothing read, make the string empty */ - strcpy(BootOptions, ""); - } - - /* Normalize system path */ - if (!MachDiskNormalizeSystemPath(SystemPath, sizeof(SystemPath))) - { - UiMessageBox("Invalid system path"); - return; - } - - /* Let user know we started loading */ - UiDrawStatusText("Loading..."); - - /* Try to open system drive */ - BootDevice = 0xffffffff; - if (!FsOpenSystemVolume(SystemPath, BootPath, &BootDevice)) - { - UiMessageBox("Failed to open boot drive."); - return; - } - - /* append a backslash */ - if ((strlen(BootPath)==0) || - BootPath[strlen(BootPath)] != '\\') - strcat(BootPath, "\\"); - - DbgPrint((DPRINT_WINDOWS,"SystemRoot: '%s'\n", BootPath)); - - /* Allocate and minimalistic-initialize LPB */ - AllocateAndInitLPB(&LoaderBlock); - - /* Detect hardware */ -#if WHEN_MERGE_COMPLETE - MachHwDetect(&LoaderBlock->ConfigurationRoot); -#else - MachHwDetect(); -#endif - - /* Load kernel */ - strcpy(FileName, BootPath); - strcat(FileName, "SYSTEM32\\NTOSKRNL.EXE"); - Status = WinLdrLoadImage(FileName, LoaderSystemCode, &NtosBase); - DbgPrint((DPRINT_WINDOWS, "Ntos loaded with status %d at %p\n", Status, NtosBase)); - - /* Load HAL */ - strcpy(FileName, BootPath); - strcat(FileName, "SYSTEM32\\HAL.DLL"); - Status = WinLdrLoadImage(FileName, LoaderHalCode, &HalBase); - DbgPrint((DPRINT_WINDOWS, "HAL loaded with status %d at %p\n", Status, HalBase)); - - /* Load kernel-debugger support dll */ - if (OperatingSystemVersion > _WIN32_WINNT_WIN2K) - { - strcpy(FileName, BootPath); - strcat(FileName, "SYSTEM32\\KDCOM.DLL"); - Status = WinLdrLoadImage(FileName, LoaderBootDriver, &KdComBase); - DbgPrint((DPRINT_WINDOWS, "KdCom loaded with status %d at %p\n", Status, KdComBase)); - } - - /* Allocate data table entries for above-loaded modules */ - WinLdrAllocateDataTableEntry(LoaderBlock, "ntoskrnl.exe", - "WINNT\\SYSTEM32\\NTOSKRNL.EXE", NtosBase, &KernelDTE); - WinLdrAllocateDataTableEntry(LoaderBlock, "hal.dll", - "WINNT\\SYSTEM32\\HAL.DLL", HalBase, &HalDTE); - if (OperatingSystemVersion > _WIN32_WINNT_WIN2K) - { - WinLdrAllocateDataTableEntry(LoaderBlock, "kdcom.dll", - "WINNT\\SYSTEM32\\KDCOM.DLL", KdComBase, &KdComDTE); - } - - /* Load all referenced DLLs for kernel, HAL and kdcom.dll */ - strcpy(SearchPath, BootPath); - strcat(SearchPath, "SYSTEM32\\"); - WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, KernelDTE); - WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, HalDTE); - if (KdComDTE) - WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, KdComDTE); - - /* Load Hive, and then NLS data, OEM font, and prepare boot drivers list */ - Status = WinLdrLoadAndScanSystemHive(LoaderBlock, BootPath); - DbgPrint((DPRINT_WINDOWS, "SYSTEM hive loaded and scanned with status %d\n", Status)); - - /* Load boot drivers */ - Status = WinLdrLoadBootDrivers(LoaderBlock, BootPath); - DbgPrint((DPRINT_WINDOWS, "Boot drivers loaded with status %d\n", Status)); - - /* Initialize Phase 1 - no drivers loading anymore */ - WinLdrInitializePhase1(LoaderBlock, BootOptions, SystemPath, OperatingSystemVersion); - - /* Alloc PCR, TSS, do magic things with the GDT/IDT */ - WinLdrSetupForNt(LoaderBlock, &GdtIdt, &PcrBasePage, &TssBasePage); - - /* Save entry-point pointer and Loader block VAs */ - KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint; - LoaderBlockVA = PaToVa(LoaderBlock); - - /* "Stop all motors", change videomode */ - DiskStopFloppyMotor(); - MachVideoPrepareForReactOS(FALSE); - - /* Debugging... */ - //DumpMemoryAllocMap(); - - /* Turn on paging mode of CPU*/ - WinLdrTurnOnPaging(LoaderBlock, PcrBasePage, TssBasePage, GdtIdt); - - DbgPrint((DPRINT_WINDOWS, "Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n", - KiSystemStartup, LoaderBlockVA)); - - WinLdrpDumpMemoryDescriptors(LoaderBlockVA); - WinLdrpDumpBootDriver(LoaderBlockVA); - WinLdrpDumpArcDisks(LoaderBlockVA); - - //FIXME: If I substitute this debugging checkpoint, GCC will "optimize away" the code below - //while (1) {}; - /*asm(".intel_syntax noprefix\n"); - asm("test1:\n"); - asm("jmp test1\n"); - asm(".att_syntax\n");*/ - - /* Pass control */ - (*KiSystemStartup)(LoaderBlockVA); - - return; -} - -VOID -WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock) -{ - PLIST_ENTRY NextMd; - PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor; - - NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; - - while (NextMd != &LoaderBlock->MemoryDescriptorListHead) - { - MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry); - - DbgPrint((DPRINT_WINDOWS, "BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage, - MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType)); - - NextMd = MemoryDescriptor->ListEntry.Flink; - } -} - -VOID -WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock) -{ - PLIST_ENTRY NextBd; - PBOOT_DRIVER_LIST_ENTRY BootDriver; - - NextBd = LoaderBlock->BootDriverListHead.Flink; - - while (NextBd != &LoaderBlock->BootDriverListHead) - { - BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, ListEntry); - - DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath, - BootDriver->DataTableEntry, &BootDriver->RegistryPath)); - - NextBd = BootDriver->ListEntry.Flink; - } -} - -VOID -WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock) -{ - PLIST_ENTRY NextBd; - PARC_DISK_SIGNATURE ArcDisk; - - NextBd = LoaderBlock->ArcDiskInformation->DiskSignatureListHead.Flink; - - while (NextBd != &LoaderBlock->ArcDiskInformation->DiskSignatureListHead) - { - ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry); - - DbgPrint((DPRINT_WINDOWS, "ArcDisk %s checksum: 0x%X, signature: 0x%X\n", - ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature)); - - NextBd = ArcDisk->ListEntry.Flink; - } -} - +/* + * FreeLoader + * + * Copyright (C) 1998-2003 Brian Palmer + * Copyright (C) 2006 Aleksey Bragin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include + +//FIXME: Do a better way to retrieve Arc disk information +extern ULONG reactos_disk_count; +extern ARC_DISK_SIGNATURE reactos_arc_disk_info[]; +extern char reactos_arc_strings[32][256]; +extern char reactos_arc_hardware_data[HW_MAX_ARC_HEAP_SIZE]; + +BOOLEAN +WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock, + IN PCH DllName, + OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry); + +// debug stuff +VOID DumpMemoryAllocMap(VOID); +VOID WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock); +VOID WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock); +VOID WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock); + + +// Init "phase 0" +VOID +AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock) +{ + PLOADER_PARAMETER_BLOCK LoaderBlock; + + /* Allocate and zero-init the LPB */ + LoaderBlock = MmHeapAlloc(sizeof(LOADER_PARAMETER_BLOCK)); + RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK)); + + /* Init three critical lists, used right away */ + InitializeListHead(&LoaderBlock->LoadOrderListHead); + InitializeListHead(&LoaderBlock->MemoryDescriptorListHead); + InitializeListHead(&LoaderBlock->BootDriverListHead); + + /* Alloc space for NLS (it will be converted to VA in WinLdrLoadNLS) */ + LoaderBlock->NlsData = MmHeapAlloc(sizeof(NLS_DATA_BLOCK)); + if (LoaderBlock->NlsData == NULL) + { + UiMessageBox("Failed to allocate memory for NLS table data!"); + return; + } + RtlZeroMemory(LoaderBlock->NlsData, sizeof(NLS_DATA_BLOCK)); + + *OutLoaderBlock = LoaderBlock; +} + +// Init "phase 1" +VOID +WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock, + PCHAR Options, + PCHAR SystemPath, + WORD VersionToBoot) +{ + /* Examples of correct options and paths */ + //CHAR Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200"; + //CHAR Options[] = "/NODEBUG"; + //CHAR SystemRoot[] = "\\WINNT\\"; + //CHAR ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)"; + + CHAR HalPath[] = "\\"; + CHAR SystemRoot[256]; + CHAR ArcBoot[256]; + ULONG i, PathSeparator; + PLOADER_PARAMETER_EXTENSION Extension; + + LoaderBlock->u.I386.CommonDataArea = NULL; // Force No ABIOS support + + /* Construct SystemRoot and ArcBoot from SystemPath */ + PathSeparator = strstr(SystemPath, "\\") - SystemPath; + strncpy(ArcBoot, SystemPath, PathSeparator); + ArcBoot[PathSeparator] = 0; + strcpy(SystemRoot, &SystemPath[PathSeparator]); + strcat(SystemRoot, "\\"); + + DbgPrint((DPRINT_WINDOWS, "ArcBoot: %s\n", ArcBoot)); + DbgPrint((DPRINT_WINDOWS, "SystemRoot: %s\n", SystemRoot)); + DbgPrint((DPRINT_WINDOWS, "Options: %s\n", Options)); + + /* Fill Arc BootDevice */ + LoaderBlock->ArcBootDeviceName = MmHeapAlloc(strlen(ArcBoot)+1); + strcpy(LoaderBlock->ArcBootDeviceName, ArcBoot); + LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName); + + /* Fill Arc HalDevice, it matches ArcBoot path */ + LoaderBlock->ArcHalDeviceName = MmHeapAlloc(strlen(ArcBoot)+1); + strcpy(LoaderBlock->ArcHalDeviceName, ArcBoot); + LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName); + + /* Fill SystemRoot */ + LoaderBlock->NtBootPathName = MmHeapAlloc(strlen(SystemRoot)+1); + strcpy(LoaderBlock->NtBootPathName, SystemRoot); + LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName); + + /* Fill NtHalPathName */ + LoaderBlock->NtHalPathName = MmHeapAlloc(strlen(HalPath)+1); + strcpy(LoaderBlock->NtHalPathName, HalPath); + LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName); + + /* Fill load options */ + LoaderBlock->LoadOptions = MmHeapAlloc(strlen(Options)+1); + strcpy(LoaderBlock->LoadOptions, Options); + LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions); + + /* Arc devices */ + LoaderBlock->ArcDiskInformation = (PARC_DISK_INFORMATION)MmHeapAlloc(sizeof(ARC_DISK_INFORMATION)); + InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead); + + /* Convert ARC disk information from freeldr to a correct format */ + for (i = 0; i < reactos_disk_count; i++) + { + PARC_DISK_SIGNATURE ArcDiskInfo; + + /* Get the ARC structure */ + ArcDiskInfo = (PARC_DISK_SIGNATURE)MmHeapAlloc(sizeof(ARC_DISK_SIGNATURE)); + RtlZeroMemory(ArcDiskInfo, sizeof(ARC_DISK_SIGNATURE)); + + /* Copy the data over */ + ArcDiskInfo->Signature = reactos_arc_disk_info[i].Signature; + ArcDiskInfo->CheckSum = reactos_arc_disk_info[i].CheckSum; + + /* Copy the ARC Name */ + ArcDiskInfo->ArcName = (PCHAR)MmHeapAlloc(sizeof(CHAR)*256); + strcpy(ArcDiskInfo->ArcName, reactos_arc_disk_info[i].ArcName); + ArcDiskInfo->ArcName = (PCHAR)PaToVa(ArcDiskInfo->ArcName); + + /* Mark partition table as valid */ + ArcDiskInfo->ValidPartitionTable = TRUE; + + /* Insert into the list */ + InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead, + &ArcDiskInfo->ListEntry); + } + + /* Convert all list's to Virtual address */ + + /* Convert the ArcDisks list to virtual address */ + List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead); + LoaderBlock->ArcDiskInformation = PaToVa(LoaderBlock->ArcDiskInformation); + + /* Convert configuration entries to VA */ + ConvertConfigToVA(LoaderBlock->ConfigurationRoot); + LoaderBlock->ConfigurationRoot = PaToVa(LoaderBlock->ConfigurationRoot); + + /* Convert all DTE into virtual addresses */ + List_PaToVa(&LoaderBlock->LoadOrderListHead); + + /* this one will be converted right before switching to + virtual paging mode */ + //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead); + + /* Convert list of boot drivers */ + List_PaToVa(&LoaderBlock->BootDriverListHead); + + /* Initialize Extension now */ + Extension = MmHeapAlloc(sizeof(LOADER_PARAMETER_EXTENSION)); + if (Extension == NULL) + { + UiMessageBox("Failed to allocate LPB Extension!"); + return; + } + RtlZeroMemory(Extension, sizeof(LOADER_PARAMETER_EXTENSION)); + + /* Save size and version information */ + Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION); + Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8; + Extension->MinorVersion = VersionToBoot & 0xFF; + + + LoaderBlock->Extension = PaToVa(Extension); +} + +// Last step before going virtual +void WinLdrSetupForNt(PLOADER_PARAMETER_BLOCK LoaderBlock, + PVOID *GdtIdt, + ULONG *PcrBasePage, + ULONG *TssBasePage) +{ + ULONG TssSize; + ULONG TssPages; + ULONG_PTR Pcr = 0; + ULONG_PTR Tss = 0; + ULONG BlockSize, NumPages; + + LoaderBlock->u.I386.CommonDataArea = NULL;//CommonDataArea; + //LoaderBlock->u.I386.MachineType = MachineType; //FIXME: MachineType? + + /* Allocate 2 pages for PCR */ + Pcr = (ULONG_PTR)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE, LoaderStartupPcrPage); + *PcrBasePage = Pcr >> MM_PAGE_SHIFT; + + if (Pcr == 0) + { + UiMessageBox("Can't allocate PCR\n"); + return; + } + + /* Allocate TSS */ + TssSize = (sizeof(KTSS) + MM_PAGE_SIZE) & ~(MM_PAGE_SIZE - 1); + TssPages = TssSize / MM_PAGE_SIZE; + + Tss = (ULONG_PTR)MmAllocateMemoryWithType(TssSize, LoaderMemoryData); + + *TssBasePage = Tss >> MM_PAGE_SHIFT; + + /* Allocate space for new GDT + IDT */ + BlockSize = NUM_GDT*sizeof(KGDTENTRY) + NUM_IDT*sizeof(KIDTENTRY);//FIXME: Use GDT/IDT limits here? + NumPages = (BlockSize + MM_PAGE_SIZE - 1) >> MM_PAGE_SHIFT; + *GdtIdt = (PKGDTENTRY)MmAllocateMemoryWithType(NumPages * MM_PAGE_SIZE, LoaderMemoryData); + + if (*GdtIdt == NULL) + { + UiMessageBox("Can't allocate pages for GDT+IDT!\n"); + return; + } + + /* Zero newly prepared GDT+IDT */ + RtlZeroMemory(*GdtIdt, NumPages << MM_PAGE_SHIFT); +} + +BOOLEAN +WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock, + LPSTR BootPath, + PUNICODE_STRING FilePath, + ULONG Flags, + PLDR_DATA_TABLE_ENTRY *DriverDTE) +{ + CHAR FullPath[1024]; + CHAR DriverPath[1024]; + CHAR DllName[1024]; + PCHAR DriverNamePos; + BOOLEAN Status; + PVOID DriverBase; + + // Separate the path to file name and directory path + sprintf(DriverPath, "%wZ", FilePath); + DriverNamePos = strrchr(DriverPath, '\\'); + if (DriverNamePos != NULL) + { + // Copy the name + strcpy(DllName, DriverNamePos+1); + + // Cut out the name from the path + *(DriverNamePos+1) = 0; + } + + DbgPrint((DPRINT_WINDOWS, "DriverPath: %s, DllName: %s, LPB %p\n", DriverPath, DllName, LoaderBlock)); + + + // Check if driver is already loaded + Status = WinLdrCheckForLoadedDll(LoaderBlock, DllName, DriverDTE); + if (Status) + { + // We've got the pointer to its DTE, just return success + return TRUE; + } + + // It's not loaded, we have to load it + sprintf(FullPath,"%s%wZ", BootPath, FilePath); + Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase); + if (!Status) + return FALSE; + + // Allocate a DTE for it + Status = WinLdrAllocateDataTableEntry(LoaderBlock, DllName, DllName, DriverBase, DriverDTE); + if (!Status) + { + DbgPrint((DPRINT_WINDOWS, "WinLdrAllocateDataTableEntry() failed\n")); + return FALSE; + } + + // Modify any flags, if needed + (*DriverDTE)->Flags |= Flags; + + // Look for any dependencies it may have, and load them too + sprintf(FullPath,"%s%s", BootPath, DriverPath); + Status = WinLdrScanImportDescriptorTable(LoaderBlock, FullPath, *DriverDTE); + if (!Status) + { + DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable() failed for %s\n", + FullPath)); + return FALSE; + } + + return TRUE; +} + +BOOLEAN +WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock, + LPSTR BootPath) +{ + PLIST_ENTRY NextBd; + PBOOT_DRIVER_LIST_ENTRY BootDriver; + BOOLEAN Status; + + // Walk through the boot drivers list + NextBd = LoaderBlock->BootDriverListHead.Flink; + + while (NextBd != &LoaderBlock->BootDriverListHead) + { + BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, ListEntry); + + DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath, + BootDriver->DataTableEntry, &BootDriver->RegistryPath)); + + // Paths are relative (FIXME: Are they always relative?) + + // Load it + Status = WinLdrLoadDeviceDriver(LoaderBlock, BootPath, &BootDriver->FilePath, + 0, &BootDriver->DataTableEntry); + + // If loading failed - cry loudly + //FIXME: Maybe remove it from the list and try to continue? + if (!Status) + { + UiMessageBox("Can't load boot driver!"); + return FALSE; + } + + // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore + BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer); + BootDriver->DataTableEntry = PaToVa(BootDriver->DataTableEntry); + + NextBd = BootDriver->ListEntry.Flink; + } + + return TRUE; +} + +VOID +LoadAndBootWindows(PCSTR OperatingSystemName, WORD OperatingSystemVersion) +{ + CHAR MsgBuffer[256]; + CHAR SystemPath[512], SearchPath[512]; + CHAR FileName[512]; + CHAR BootPath[512]; + CHAR BootOptions[256]; + PVOID NtosBase = NULL, HalBase = NULL, KdComBase = NULL; + BOOLEAN Status; + ULONG SectionId; + ULONG BootDevice; + PLOADER_PARAMETER_BLOCK LoaderBlock, LoaderBlockVA; + KERNEL_ENTRY_POINT KiSystemStartup; + PLDR_DATA_TABLE_ENTRY KernelDTE, HalDTE, KdComDTE = NULL; + // Mm-related things + PVOID GdtIdt; + ULONG PcrBasePage=0; + ULONG TssBasePage=0; + + //sprintf(MsgBuffer,"Booting Microsoft(R) Windows(R) OS version '%04x' is not implemented yet", OperatingSystemVersion); + //UiMessageBox(MsgBuffer); + + // Open the operating system section + // specified in the .ini file + if (!IniOpenSection(OperatingSystemName, &SectionId)) + { + sprintf(MsgBuffer,"Operating System section '%s' not found in freeldr.ini", OperatingSystemName); + UiMessageBox(MsgBuffer); + return; + } + + UiDrawBackdrop(); + UiDrawStatusText("Detecting Hardware..."); + UiDrawProgressBarCenter(1, 100, "Loading Windows..."); + + /* Make sure the system path is set in the .ini file */ + if (!IniReadSettingByName(SectionId, "SystemPath", SystemPath, sizeof(SystemPath))) + { + UiMessageBox("System path not specified for selected operating system."); + return; + } + + /* Read booting options */ + if (!IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions))) + { + /* Nothing read, make the string empty */ + strcpy(BootOptions, ""); + } + + /* Normalize system path */ + if (!MachDiskNormalizeSystemPath(SystemPath, sizeof(SystemPath))) + { + UiMessageBox("Invalid system path"); + return; + } + + /* Let user know we started loading */ + UiDrawStatusText("Loading..."); + + /* Try to open system drive */ + BootDevice = 0xffffffff; + if (!FsOpenSystemVolume(SystemPath, BootPath, &BootDevice)) + { + UiMessageBox("Failed to open boot drive."); + return; + } + + /* append a backslash */ + if ((strlen(BootPath)==0) || + BootPath[strlen(BootPath)] != '\\') + strcat(BootPath, "\\"); + + DbgPrint((DPRINT_WINDOWS,"SystemRoot: '%s'\n", BootPath)); + + /* Allocate and minimalistic-initialize LPB */ + AllocateAndInitLPB(&LoaderBlock); + + /* Detect hardware */ + MachHwDetect(); + LoaderBlock->ConfigurationRoot = MmHeapAlloc(16 * 1024); + RtlCopyMemory(LoaderBlock->ConfigurationRoot, + (PVOID)reactos_arc_hardware_data, 16 * 1024); + + /* Load kernel */ + strcpy(FileName, BootPath); + strcat(FileName, "SYSTEM32\\NTOSKRNL.EXE"); + Status = WinLdrLoadImage(FileName, LoaderSystemCode, &NtosBase); + DbgPrint((DPRINT_WINDOWS, "Ntos loaded with status %d at %p\n", Status, NtosBase)); + + /* Load HAL */ + strcpy(FileName, BootPath); + strcat(FileName, "SYSTEM32\\HAL.DLL"); + Status = WinLdrLoadImage(FileName, LoaderHalCode, &HalBase); + DbgPrint((DPRINT_WINDOWS, "HAL loaded with status %d at %p\n", Status, HalBase)); + + /* Load kernel-debugger support dll */ + if (OperatingSystemVersion > _WIN32_WINNT_WIN2K) + { + strcpy(FileName, BootPath); + strcat(FileName, "SYSTEM32\\KDCOM.DLL"); + Status = WinLdrLoadImage(FileName, LoaderBootDriver, &KdComBase); + DbgPrint((DPRINT_WINDOWS, "KdCom loaded with status %d at %p\n", Status, KdComBase)); + } + + /* Allocate data table entries for above-loaded modules */ + WinLdrAllocateDataTableEntry(LoaderBlock, "ntoskrnl.exe", + "WINNT\\SYSTEM32\\NTOSKRNL.EXE", NtosBase, &KernelDTE); + WinLdrAllocateDataTableEntry(LoaderBlock, "hal.dll", + "WINNT\\SYSTEM32\\HAL.DLL", HalBase, &HalDTE); + if (OperatingSystemVersion > _WIN32_WINNT_WIN2K) + { + WinLdrAllocateDataTableEntry(LoaderBlock, "kdcom.dll", + "WINNT\\SYSTEM32\\KDCOM.DLL", KdComBase, &KdComDTE); + } + + /* Load all referenced DLLs for kernel, HAL and kdcom.dll */ + strcpy(SearchPath, BootPath); + strcat(SearchPath, "SYSTEM32\\"); + WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, KernelDTE); + WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, HalDTE); + if (KdComDTE) + WinLdrScanImportDescriptorTable(LoaderBlock, SearchPath, KdComDTE); + + /* Load Hive, and then NLS data, OEM font, and prepare boot drivers list */ + Status = WinLdrLoadAndScanSystemHive(LoaderBlock, BootPath); + DbgPrint((DPRINT_WINDOWS, "SYSTEM hive loaded and scanned with status %d\n", Status)); + + /* Load boot drivers */ + Status = WinLdrLoadBootDrivers(LoaderBlock, BootPath); + DbgPrint((DPRINT_WINDOWS, "Boot drivers loaded with status %d\n", Status)); + + /* Initialize Phase 1 - no drivers loading anymore */ + WinLdrInitializePhase1(LoaderBlock, BootOptions, SystemPath, OperatingSystemVersion); + + /* Alloc PCR, TSS, do magic things with the GDT/IDT */ + WinLdrSetupForNt(LoaderBlock, &GdtIdt, &PcrBasePage, &TssBasePage); + + /* Save entry-point pointer and Loader block VAs */ + KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint; + LoaderBlockVA = PaToVa(LoaderBlock); + + /* "Stop all motors", change videomode */ + DiskStopFloppyMotor(); + MachVideoPrepareForReactOS(FALSE); + + /* Debugging... */ + //DumpMemoryAllocMap(); + + /* Turn on paging mode of CPU*/ + WinLdrTurnOnPaging(LoaderBlock, PcrBasePage, TssBasePage, GdtIdt); + + DbgPrint((DPRINT_WINDOWS, "Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n", + KiSystemStartup, LoaderBlockVA)); + + WinLdrpDumpMemoryDescriptors(LoaderBlockVA); + WinLdrpDumpBootDriver(LoaderBlockVA); + WinLdrpDumpArcDisks(LoaderBlockVA); + + //FIXME: If I substitute this debugging checkpoint, GCC will "optimize away" the code below + //while (1) {}; + /*asm(".intel_syntax noprefix\n"); + asm("test1:\n"); + asm("jmp test1\n"); + asm(".att_syntax\n");*/ + + /* Pass control */ + (*KiSystemStartup)(LoaderBlockVA); + + return; +} + +VOID +WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PLIST_ENTRY NextMd; + PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor; + + NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; + + while (NextMd != &LoaderBlock->MemoryDescriptorListHead) + { + MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry); + + DbgPrint((DPRINT_WINDOWS, "BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage, + MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType)); + + NextMd = MemoryDescriptor->ListEntry.Flink; + } +} + +VOID +WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PLIST_ENTRY NextBd; + PBOOT_DRIVER_LIST_ENTRY BootDriver; + + NextBd = LoaderBlock->BootDriverListHead.Flink; + + while (NextBd != &LoaderBlock->BootDriverListHead) + { + BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, ListEntry); + + DbgPrint((DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath, + BootDriver->DataTableEntry, &BootDriver->RegistryPath)); + + NextBd = BootDriver->ListEntry.Flink; + } +} + +VOID +WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock) +{ + PLIST_ENTRY NextBd; + PARC_DISK_SIGNATURE ArcDisk; + + NextBd = LoaderBlock->ArcDiskInformation->DiskSignatureListHead.Flink; + + while (NextBd != &LoaderBlock->ArcDiskInformation->DiskSignatureListHead) + { + ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry); + + DbgPrint((DPRINT_WINDOWS, "ArcDisk %s checksum: 0x%X, signature: 0x%X\n", + ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature)); + + NextBd = ArcDisk->ListEntry.Flink; + } +} + diff --git a/reactos/boot/freeldr/freeldr/windows/wlmemory.c b/reactos/boot/freeldr/freeldr/windows/wlmemory.c index 8835702a0f5..2181ea6ebde 100644 --- a/reactos/boot/freeldr/freeldr/windows/wlmemory.c +++ b/reactos/boot/freeldr/freeldr/windows/wlmemory.c @@ -1,896 +1,899 @@ -/* - * PROJECT: EFI Windows Loader - * LICENSE: GPL - See COPYING in the top level directory - * FILE: freeldr/winldr/wlmemory.c - * PURPOSE: Memory related routines - * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org) - */ - -/* INCLUDES ***************************************************************/ - -#include - -#include -#include - -extern ULONG TotalNLSSize; - -// This is needed because headers define wrong one for ReactOS -#undef KIP0PCRADDRESS -#define KIP0PCRADDRESS 0xffdff000 - -#define HYPER_SPACE_ENTRY 0x300 - -PCHAR MemTypeDesc[] = { - "ExceptionBlock ", // ? - "SystemBlock ", // ? - "Free ", - "Bad ", // used - "LoadedProgram ", // == Free - "FirmwareTemporary ", // == Free - "FirmwarePermanent ", // == Bad - "OsloaderHeap ", // used - "OsloaderStack ", // == Free - "SystemCode ", - "HalCode ", - "BootDriver ", // not used - "ConsoleInDriver ", // ? - "ConsoleOutDriver ", // ? - "StartupDpcStack ", // ? - "StartupKernelStack", // ? - "StartupPanicStack ", // ? - "StartupPcrPage ", // ? - "StartupPdrPage ", // ? - "RegistryData ", // used - "MemoryData ", // not used - "NlsData ", // used - "SpecialMemory ", // == Bad - "BBTMemory " // == Bad - }; - -VOID -WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock); - - -VOID -MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, - ULONG BasePage, - ULONG PageCount, - ULONG Type); -VOID -WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, - IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor); - -VOID -WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor); - -VOID -WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss); - -// This is needed only for SetProcessorContext routine -#pragma pack(2) - typedef struct - { - USHORT Limit; - ULONG Base; - } GDTIDT; -#pragma pack(4) - -// this is needed for new IDT filling -#if 0 -extern ULONG_PTR i386DivideByZero; -extern ULONG_PTR i386DebugException; -extern ULONG_PTR i386NMIException; -extern ULONG_PTR i386Breakpoint; -extern ULONG_PTR i386Overflow; -extern ULONG_PTR i386BoundException; -extern ULONG_PTR i386InvalidOpcode; -extern ULONG_PTR i386FPUNotAvailable; -extern ULONG_PTR i386DoubleFault; -extern ULONG_PTR i386CoprocessorSegment; -extern ULONG_PTR i386InvalidTSS; -extern ULONG_PTR i386SegmentNotPresent; -extern ULONG_PTR i386StackException; -extern ULONG_PTR i386GeneralProtectionFault; -extern ULONG_PTR i386PageFault; // exc 14 -extern ULONG_PTR i386CoprocessorError; // exc 16 -extern ULONG_PTR i386AlignmentCheck; // exc 17 -#endif - -/* GLOBALS ***************************************************************/ - -PHARDWARE_PTE PDE; -PHARDWARE_PTE HalPT; - -PUCHAR PhysicalPageTablesBuffer; -PUCHAR KernelPageTablesBuffer; -ULONG PhysicalPageTables; -ULONG KernelPageTables; - -MEMORY_ALLOCATION_DESCRIPTOR Mad[1024]; -ULONG MadCount = 0; - - -/* FUNCTIONS **************************************************************/ - -BOOLEAN -MempAllocatePageTables() -{ - ULONG NumPageTables, TotalSize; - PUCHAR Buffer; - // It's better to allocate PDE + PTEs contigiuos - - // Max number of entries = MaxPageNum >> 10 - // FIXME: This is a number to describe ALL physical memory - // and windows doesn't expect ALL memory mapped... - NumPageTables = (GetSystemMemorySize() >> MM_PAGE_SHIFT) >> 10; - - DbgPrint((DPRINT_WINDOWS, "NumPageTables = %d\n", NumPageTables)); - - // Allocate memory block for all these things: - // PDE, HAL mapping page table, physical mapping, kernel mapping - // FIXME: PDE+HAL+KernelPTEs == FirmwarePermanent, Physical PTEs = FirmwareTemporary - TotalSize = (1+1+NumPageTables*2)*MM_PAGE_SIZE; - Buffer = MmAllocateMemoryWithType(TotalSize, LoaderFirmwarePermanent); - - if (Buffer == NULL) - { - UiMessageBox("Impossible to allocate memory block for page tables!"); - return FALSE; - } - - // Zero all this memory block - RtlZeroMemory(Buffer, TotalSize); - - // Set up pointers correctly now - PDE = (PHARDWARE_PTE)Buffer; - - // Map the page directory at 0xC0000000 (maps itself) - PDE[HYPER_SPACE_ENTRY].PageFrameNumber = (ULONG)PDE >> MM_PAGE_SHIFT; - PDE[HYPER_SPACE_ENTRY].Valid = 1; - PDE[HYPER_SPACE_ENTRY].Write = 1; - - // The last PDE slot is allocated for HAL's memory mapping (Virtual Addresses 0xFFC00000 - 0xFFFFFFFF) - HalPT = (PHARDWARE_PTE)&Buffer[MM_PAGE_SIZE*1]; - - // Map it - PDE[1023].PageFrameNumber = (ULONG)HalPT >> MM_PAGE_SHIFT; - PDE[1023].Valid = 1; - PDE[1023].Write = 1; - - // Store pointers to the tables for easier access - PhysicalPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2]; - KernelPageTablesBuffer = PhysicalPageTablesBuffer + NumPageTables*MM_PAGE_SIZE; - - // Mark physical PTE's buffer as FirmwareTemporary - //MmSetMemoryType(KernelPageTablesBuffer, NumPageTables*MM_PAGE_SIZE, LoaderFirmwareTemporary); - - // Zero counters of page tables used - PhysicalPageTables = 0; - KernelPageTables = 0; - - return TRUE; -} - -VOID -MempAllocatePTE(ULONG Entry, PHARDWARE_PTE *PhysicalPT, PHARDWARE_PTE *KernelPT) -{ - //Print(L"Creating PDE Entry %X\n", Entry); - - // Identity mapping - *PhysicalPT = (PHARDWARE_PTE)&PhysicalPageTablesBuffer[PhysicalPageTables*MM_PAGE_SIZE]; - PhysicalPageTables++; - - PDE[Entry].PageFrameNumber = (ULONG)*PhysicalPT >> MM_PAGE_SHIFT; - PDE[Entry].Valid = 1; - PDE[Entry].Write = 1; - - if (Entry+(KSEG0_BASE >> 22) > 1023) - { - DbgPrint((DPRINT_WINDOWS, "WARNING! Entry: %X > 1023\n", Entry+(KSEG0_BASE >> 22))); - } - - // Kernel-mode mapping - *KernelPT = (PHARDWARE_PTE)&KernelPageTablesBuffer[KernelPageTables*MM_PAGE_SIZE]; - KernelPageTables++; - - PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber = ((ULONG)*KernelPT >> MM_PAGE_SHIFT); - PDE[Entry+(KSEG0_BASE >> 22)].Valid = 1; - PDE[Entry+(KSEG0_BASE >> 22)].Write = 1; -} - -BOOLEAN -MempSetupPaging(IN ULONG StartPage, - IN ULONG NumberOfPages) -{ - PHARDWARE_PTE PhysicalPT; - PHARDWARE_PTE KernelPT; - ULONG Entry, Page; - - //Print(L"MempSetupPaging: SP 0x%X, Number: 0x%X\n", StartPage, NumberOfPages); - - // HACK - if (StartPage+NumberOfPages >= 0x80000) - { - // - // We can't map this as it requires more than 1 PDE - // and in fact it's not possible at all ;) - // - //Print(L"skipping...\n"); - return TRUE; - } - - // - // Now actually set up the page tables for identity mapping - // - for (Page=StartPage; Page < StartPage+NumberOfPages; Page++) - { - Entry = Page >> 10; - - if (((PULONG)PDE)[Entry] == 0) - { - MempAllocatePTE(Entry, &PhysicalPT, &KernelPT); - } - else - { - PhysicalPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT); - KernelPT = (PHARDWARE_PTE)(PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber << MM_PAGE_SHIFT); - } - - if (Page == 0) - { - PhysicalPT[Page & 0x3ff].PageFrameNumber = Page; - PhysicalPT[Page & 0x3ff].Valid = 0; - PhysicalPT[Page & 0x3ff].Write = 0; - - KernelPT[Page & 0x3ff].PageFrameNumber = Page; - KernelPT[Page & 0x3ff].Valid = 0; - KernelPT[Page & 0x3ff].Write = 0; - } - else - { - PhysicalPT[Page & 0x3ff].PageFrameNumber = Page; - PhysicalPT[Page & 0x3ff].Valid = 1; - PhysicalPT[Page & 0x3ff].Write = 1; - - KernelPT[Page & 0x3ff].PageFrameNumber = Page; - KernelPT[Page & 0x3ff].Valid = 1; - KernelPT[Page & 0x3ff].Write = 1; - } - } - - return TRUE; -} - -VOID -MempDisablePages() -{ - int i; - - // - // We need to delete kernel mapping from memory areas which are - // marked as Special or Permanent memory (thus non-accessible) - // - - for (i=0; i LOADER_HIGH_ZONE) - EndPage = LOADER_HIGH_ZONE; - } - - for (Page = StartPage; Page < EndPage; Page++) - { - PHARDWARE_PTE KernelPT; - ULONG Entry = (Page >> 10) + (KSEG0_BASE >> 22); - - if (PDE[Entry].Valid) - { - KernelPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT); - - if (KernelPT) - { - KernelPT[Page & 0x3ff].PageFrameNumber = 0; - KernelPT[Page & 0x3ff].Valid = 0; - KernelPT[Page & 0x3ff].Write = 0; - } - } - } - } - } -} - - -VOID -MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, - ULONG BasePage, - ULONG PageCount, - ULONG Type) -{ - BOOLEAN Status; - - // - // Check for some weird stuff at the top - // - if (BasePage + PageCount > 0xF0000) - { - // - // Just skip this, without even adding to MAD list - // - return; - } - - // - // Set Base page, page count and type - // - Mad[MadCount].BasePage = BasePage; - Mad[MadCount].PageCount = PageCount; - Mad[MadCount].MemoryType = Type; - - // - // Check if it's more than the allowed for OS loader - // if yes - don't map the pages, just add as FirmwareTemporary - // - if (BasePage + PageCount > LOADER_HIGH_ZONE) - { - if (Mad[MadCount].MemoryType != LoaderSpecialMemory || - Mad[MadCount].MemoryType != LoaderFirmwarePermanent) - { - Mad[MadCount].MemoryType = LoaderFirmwareTemporary; - } - - WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]); - MadCount++; - - return; - } - - // - // Add descriptor - // - WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]); - MadCount++; - - // - // Map it (don't map low 1Mb because it was already contigiously - // mapped in WinLdrTurnOnPaging) - // - if (BasePage >= 0x100) - { - Status = MempSetupPaging(BasePage, PageCount); - if (!Status) - { - DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging\n")); - return; - } - } -} - -BOOLEAN -WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, - ULONG PcrBasePage, - ULONG TssBasePage, - PVOID GdtIdt) -{ - ULONG i, PagesCount, MemoryMapSizeInPages; - ULONG LastPageIndex, LastPageType, MemoryMapStartPage; - PPAGE_LOOKUP_TABLE_ITEM MemoryMap; - ULONG NoEntries; - PKTSS Tss; - BOOLEAN Status; - - // - // Creating a suitable memory map for the Windows can be tricky, so let's - // give a few advices: - // 1) One must not map the whole available memory pages to PDE! - // Map only what's needed - 16Mb, 24Mb, 32Mb max I think, - // thus occupying 4, 6 or 8 PDE entries for identical mapping, - // the same quantity for KSEG0_BASE mapping, one more entry for - // hyperspace and one more entry for HAL physical pages mapping. - // 2) Memory descriptors must map *the whole* physical memory - // showing any memory above 16/24/32 as FirmwareTemporary - // - // 3) Overall memory blocks count must not exceed 30 - // - - // - // During MmInitMachineDependent, the kernel zeroes PDE at the following address - // 0xC0300000 - 0xC03007FC - // - // Then it finds the best place for non-paged pool: - // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD - // - - // Before we start mapping pages, create a block of memory, which will contain - // PDE and PTEs - if (MempAllocatePageTables() == FALSE) - return FALSE; - - // Setup an entry for each descriptor - MemoryMap = MmGetMemoryMap(&NoEntries); - if (MemoryMap == NULL) - { - UiMessageBox("Can not retrieve the current memory map"); - return FALSE; - } - - // Calculate parameters of the memory map - MemoryMapStartPage = (ULONG_PTR)MemoryMap >> MM_PAGE_SHIFT; - MemoryMapSizeInPages = NoEntries * sizeof(PAGE_LOOKUP_TABLE_ITEM); - - DbgPrint((DPRINT_WINDOWS, "Got memory map with %d entries\n", NoEntries)); - - // Always contigiously map low 1Mb of memory - Status = MempSetupPaging(0, 0x100); - if (!Status) - { - DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging of low 1Mb\n")); - return FALSE; - } - - // Construct a good memory map from what we've got, - // but mark entries which the memory allocation bitmap takes - // as free entries (this is done in order to have the ability - // to place mem alloc bitmap outside lower 16Mb zone) - PagesCount = 1; - LastPageIndex = 0; - LastPageType = MemoryMap[0].PageAllocated; - for(i=1;i= MemoryMapStartPage && - i < (MemoryMapStartPage+MemoryMapSizeInPages)) - { - // Exclude it if current page belongs to the memory map - MemoryMap[i].PageAllocated = LoaderFree; - } - - // Process entry - if (MemoryMap[i].PageAllocated == LastPageType && - (i != NoEntries-1) ) - { - PagesCount++; - } - else - { - // Add the resulting region - MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, LastPageType); - - // Reset our counter vars - LastPageIndex = i; - LastPageType = MemoryMap[i].PageAllocated; - PagesCount = 1; - } - } - - // TEMP, DEBUG! - // adding special reserved memory zones for vmware workstation -#if 0 - { - Mad[MadCount].BasePage = 0xfec00; - Mad[MadCount].PageCount = 0x10; - Mad[MadCount].MemoryType = LoaderSpecialMemory; - WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]); - MadCount++; - - Mad[MadCount].BasePage = 0xfee00; - Mad[MadCount].PageCount = 0x1; - Mad[MadCount].MemoryType = LoaderSpecialMemory; - WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]); - MadCount++; - - Mad[MadCount].BasePage = 0xfffe0; - Mad[MadCount].PageCount = 0x20; - Mad[MadCount].MemoryType = LoaderSpecialMemory; - WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]); - MadCount++; - } -#endif - - DbgPrint((DPRINT_WINDOWS, "MadCount: %d\n", MadCount)); - - WinLdrpDumpMemoryDescriptors(LoaderBlock); //FIXME: Delete! - - // Map our loader image, so we can continue running - /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT); - if (!Status) - { - UiMessageBox("Error during MempSetupPaging"); - return; - }*/ - - //VideoDisplayString(L"Hello from VGA, going into the kernel\n"); - DbgPrint((DPRINT_WINDOWS, "HalPT: 0x%X\n", HalPT)); - - // Page Tables have been setup, make special handling for PCR and TSS - // (which is done in BlSetupFotNt in usual ntldr) - HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1; - HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1; - HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1; - - HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage; - HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1; - HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1; - - // Map VGA memory - //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached); - //DbgPrint((DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase)); - - Tss = (PKTSS)(KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT)); - - // Unmap what is not needed from kernel page table - MempDisablePages(); - - // Fill the memory descriptor list and - //PrepareMemoryDescriptorList(); - DbgPrint((DPRINT_WINDOWS, "Memory Descriptor List prepared, printing PDE\n")); - List_PaToVa(&LoaderBlock->MemoryDescriptorListHead); - -#ifdef DBG - { - ULONG *PDE_Addr=(ULONG *)PDE;//0xC0300000; - int j; - - DbgPrint((DPRINT_WINDOWS, "\nPDE\n")); - - for (i=0; i<128; i++) - { - DbgPrint((DPRINT_WINDOWS, "0x%04X | ", i*8)); - - for (j=0; j<8; j++) - { - DbgPrint((DPRINT_WINDOWS, "0x%08X ", PDE_Addr[i*8+j])); - } - - DbgPrint((DPRINT_WINDOWS, "\n")); - } - } -#endif - - - // Enable paging - //BS->ExitBootServices(ImageHandle,MapKey); - - // Disable Interrupts - _disable(); - - // Re-initalize EFLAGS - Ke386EraseFlags(); - - // Set the PDBR - __writecr3((ULONG_PTR)PDE); - - // Enable paging by modifying CR0 - __writecr0(__readcr0() | CR0_PG); - - // Set processor context - WinLdrSetProcessorContext(GdtIdt, KIP0PCRADDRESS, KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT)); - - // Zero KI_USER_SHARED_DATA page - memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE); - - return TRUE; -} - -// Two special things this func does: it sorts descriptors, -// and it merges free ones -VOID -WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, - IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor) -{ - PLIST_ENTRY ListHead = &LoaderBlock->MemoryDescriptorListHead; - PLIST_ENTRY PreviousEntry, NextEntry; - PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor = NULL, NextDescriptor = NULL; - - DbgPrint((DPRINT_WINDOWS, "BP=0x%X PC=0x%X %s\n", NewDescriptor->BasePage, - NewDescriptor->PageCount, MemTypeDesc[NewDescriptor->MemoryType])); - - /* Find a place where to insert the new descriptor to */ - PreviousEntry = ListHead; - NextEntry = ListHead->Flink; - while (NextEntry != ListHead) - { - NextDescriptor = CONTAINING_RECORD(NextEntry, - MEMORY_ALLOCATION_DESCRIPTOR, - ListEntry); - if (NewDescriptor->BasePage < NextDescriptor->BasePage) - break; - - PreviousEntry = NextEntry; - PreviousDescriptor = NextDescriptor; - NextEntry = NextEntry->Flink; - } - - /* Don't forget about merging free areas */ - if (NewDescriptor->MemoryType != LoaderFree) - { - /* Just insert, nothing to merge */ - InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry); - } - else - { - /* Previous block also free? */ - if ((PreviousEntry != ListHead) && (PreviousDescriptor->MemoryType == LoaderFree) && - ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) == - NewDescriptor->BasePage)) - { - /* Just enlarge previous descriptor's PageCount */ - PreviousDescriptor->PageCount += NewDescriptor->PageCount; - NewDescriptor = PreviousDescriptor; - } - else - { - /* Nope, just insert */ - InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry); - } - - /* Next block is free ?*/ - if ((NextEntry != ListHead) && - (NextDescriptor->MemoryType == LoaderFree) && - ((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage)) - { - /* Enlarge next descriptor's PageCount */ - NewDescriptor->PageCount += NextDescriptor->PageCount; - RemoveEntryList(&NextDescriptor->ListEntry); - } - } - - return; -} - -VOID -WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss) -{ - GDTIDT GdtDesc, IdtDesc, OldIdt; - PKGDTENTRY pGdt; - PKIDTENTRY pIdt; - ULONG Ldt = 0; - //ULONG i; - - DbgPrint((DPRINT_WINDOWS, "GDtIdt %p, Pcr %p, Tss 0x%08X\n", - GdtIdt, Pcr, Tss)); - - // Kernel expects the PCR to be zero-filled on startup - // FIXME: Why zero it here when we can zero it right after allocation? - RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE); //FIXME: Why zero only 1 page when we allocate 2? - - // Get old values of GDT and IDT - Ke386GetGlobalDescriptorTable(GdtDesc); - Ke386GetInterruptDescriptorTable(IdtDesc); - - // Save old IDT - OldIdt.Base = IdtDesc.Base; - OldIdt.Limit = IdtDesc.Limit; - - // Prepare new IDT+GDT - GdtDesc.Base = KSEG0_BASE | (ULONG_PTR)GdtIdt; - GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1; - IdtDesc.Base = (ULONG)((PUCHAR)GdtDesc.Base + GdtDesc.Limit + 1); - IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1; - - // ======================== - // Fill all descriptors now - // ======================== - - pGdt = (PKGDTENTRY)GdtDesc.Base; - pIdt = (PKIDTENTRY)IdtDesc.Base; - - // - // Code selector (0x8) - // Flat 4Gb - // - pGdt[1].LimitLow = 0xFFFF; - pGdt[1].BaseLow = 0; - pGdt[1].HighWord.Bytes.BaseMid = 0; - pGdt[1].HighWord.Bytes.Flags1 = 0x9A; - pGdt[1].HighWord.Bytes.Flags2 = 0xCF; - pGdt[1].HighWord.Bytes.BaseHi = 0; - - // - // Data selector (0x10) - // Flat 4Gb - // - pGdt[2].LimitLow = 0xFFFF; - pGdt[2].BaseLow = 0; - pGdt[2].HighWord.Bytes.BaseMid = 0; - pGdt[2].HighWord.Bytes.Flags1 = 0x92; - pGdt[2].HighWord.Bytes.Flags2 = 0xCF; - pGdt[2].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x18) - // Flat 2Gb - // - pGdt[3].LimitLow = 0xFFFF; - pGdt[3].BaseLow = 0; - pGdt[3].HighWord.Bytes.BaseMid = 0; - pGdt[3].HighWord.Bytes.Flags1 = 0xFA; - pGdt[3].HighWord.Bytes.Flags2 = 0xCF; - pGdt[3].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x20) - // Flat 2Gb - // - pGdt[4].LimitLow = 0xFFFF; - pGdt[4].BaseLow = 0; - pGdt[4].HighWord.Bytes.BaseMid = 0; - pGdt[4].HighWord.Bytes.Flags1 = 0xF2; - pGdt[4].HighWord.Bytes.Flags2 = 0xCF; - pGdt[4].HighWord.Bytes.BaseHi = 0; - - // - // TSS Selector (0x28) - // - pGdt[5].LimitLow = 0x78-1; //FIXME: Check this - pGdt[5].BaseLow = (USHORT)(Tss & 0xffff); - pGdt[5].HighWord.Bytes.BaseMid = (UCHAR)((Tss >> 16) & 0xff); - pGdt[5].HighWord.Bytes.Flags1 = 0x89; - pGdt[5].HighWord.Bytes.Flags2 = 0x00; - pGdt[5].HighWord.Bytes.BaseHi = (UCHAR)((Tss >> 24) & 0xff); - - // - // PCR Selector (0x30) - // - pGdt[6].LimitLow = 0x01; - pGdt[6].BaseLow = (USHORT)(Pcr & 0xffff); - pGdt[6].HighWord.Bytes.BaseMid = (UCHAR)((Pcr >> 16) & 0xff); - pGdt[6].HighWord.Bytes.Flags1 = 0x92; - pGdt[6].HighWord.Bytes.Flags2 = 0xC0; - pGdt[6].HighWord.Bytes.BaseHi = (UCHAR)((Pcr >> 24) & 0xff); - - // - // Selector (0x38) - // - pGdt[7].LimitLow = 0xFFFF; - pGdt[7].BaseLow = 0; - pGdt[7].HighWord.Bytes.BaseMid = 0; - pGdt[7].HighWord.Bytes.Flags1 = 0xF3; - pGdt[7].HighWord.Bytes.Flags2 = 0x40; - pGdt[7].HighWord.Bytes.BaseHi = 0; - - // - // Some BIOS fuck (0x40) - // - pGdt[8].LimitLow = 0xFFFF; - pGdt[8].BaseLow = 0x400; - pGdt[8].HighWord.Bytes.BaseMid = 0; - pGdt[8].HighWord.Bytes.Flags1 = 0xF2; - pGdt[8].HighWord.Bytes.Flags2 = 0x0; - pGdt[8].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x48) - // - pGdt[9].LimitLow = 0; - pGdt[9].BaseLow = 0; - pGdt[9].HighWord.Bytes.BaseMid = 0; - pGdt[9].HighWord.Bytes.Flags1 = 0; - pGdt[9].HighWord.Bytes.Flags2 = 0; - pGdt[9].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x50) - // - pGdt[10].LimitLow = 0xFFFF; //FIXME: Not correct! - pGdt[10].BaseLow = 0; - pGdt[10].HighWord.Bytes.BaseMid = 0x2; - pGdt[10].HighWord.Bytes.Flags1 = 0x89; - pGdt[10].HighWord.Bytes.Flags2 = 0; - pGdt[10].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x58) - // - pGdt[11].LimitLow = 0xFFFF; - pGdt[11].BaseLow = 0; - pGdt[11].HighWord.Bytes.BaseMid = 0x2; - pGdt[11].HighWord.Bytes.Flags1 = 0x9A; - pGdt[11].HighWord.Bytes.Flags2 = 0; - pGdt[11].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x60) - // - pGdt[12].LimitLow = 0xFFFF; - pGdt[12].BaseLow = 0; //FIXME: Maybe not correct, but noone cares - pGdt[12].HighWord.Bytes.BaseMid = 0x2; - pGdt[12].HighWord.Bytes.Flags1 = 0x92; - pGdt[12].HighWord.Bytes.Flags2 = 0; - pGdt[12].HighWord.Bytes.BaseHi = 0; - - // - // Video buffer Selector (0x68) - // - pGdt[13].LimitLow = 0x3FFF; - pGdt[13].BaseLow = 0x8000; //FIXME: I guess not correct for UGA - pGdt[13].HighWord.Bytes.BaseMid = 0x0B; - pGdt[13].HighWord.Bytes.Flags1 = 0x92; - pGdt[13].HighWord.Bytes.Flags2 = 0; - pGdt[13].HighWord.Bytes.BaseHi = 0; - - // - // Points to GDT (0x70) - // - pGdt[14].LimitLow = NUM_GDT*sizeof(KGDTENTRY) - 1; - pGdt[14].BaseLow = 0x7000; - pGdt[14].HighWord.Bytes.BaseMid = 0xFF; - pGdt[14].HighWord.Bytes.Flags1 = 0x92; - pGdt[14].HighWord.Bytes.Flags2 = 0; - pGdt[14].HighWord.Bytes.BaseHi = 0xFF; - - // - // Some unused descriptors should go here - // ... - - // Copy the old IDT - RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit); - - // Mask interrupts - //asm("cli\n"); // they are already masked before enabling paged mode - - // Load GDT+IDT - Ke386SetGlobalDescriptorTable(GdtDesc); - Ke386SetInterruptDescriptorTable(IdtDesc); - - // Jump to proper CS and clear prefetch queue - asm("ljmp $0x08, $mb1\n" - "mb1:\n"); - - // Set SS selector - asm(".intel_syntax noprefix\n"); - asm("mov ax, 0x10\n"); // DataSelector=0x10 - asm("mov ss, ax\n"); - asm(".att_syntax\n"); - - // Set DS and ES selectors - Ke386SetDs(0x10); - Ke386SetEs(0x10); // this is vital for rep stosd - - // LDT = not used ever, thus set to 0 - Ke386SetLocalDescriptorTable(Ldt); - - // Load TSR - Ke386SetTr(0x28); - - // Clear GS - asm(".intel_syntax noprefix\n"); - asm("push 0\n"); - asm("pop gs\n"); - asm(".att_syntax\n"); - - // Set FS to PCR - Ke386SetFs(0x30); - - // Real end of the function, just for information - /* do not uncomment! - pop edi; - pop esi; - pop ebx; - mov esp, ebp; - pop ebp; - ret - */ -} +/* + * PROJECT: EFI Windows Loader + * LICENSE: GPL - See COPYING in the top level directory + * FILE: freeldr/winldr/wlmemory.c + * PURPOSE: Memory related routines + * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org) + */ + +/* INCLUDES ***************************************************************/ + +#include + +#include +#include + +extern ULONG TotalNLSSize; + +// This is needed because headers define wrong one for ReactOS +#undef KIP0PCRADDRESS +#define KIP0PCRADDRESS 0xffdff000 + +#define HYPER_SPACE_ENTRY 0x300 + +PCHAR MemTypeDesc[] = { + "ExceptionBlock ", // ? + "SystemBlock ", // ? + "Free ", + "Bad ", // used + "LoadedProgram ", // == Free + "FirmwareTemporary ", // == Free + "FirmwarePermanent ", // == Bad + "OsloaderHeap ", // used + "OsloaderStack ", // == Free + "SystemCode ", + "HalCode ", + "BootDriver ", // not used + "ConsoleInDriver ", // ? + "ConsoleOutDriver ", // ? + "StartupDpcStack ", // ? + "StartupKernelStack", // ? + "StartupPanicStack ", // ? + "StartupPcrPage ", // ? + "StartupPdrPage ", // ? + "RegistryData ", // used + "MemoryData ", // not used + "NlsData ", // used + "SpecialMemory ", // == Bad + "BBTMemory " // == Bad + }; + +VOID +WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock); + + +VOID +MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, + ULONG BasePage, + ULONG PageCount, + ULONG Type); +VOID +WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, + IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor); + +VOID +WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor); + +VOID +WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss); + +// This is needed only for SetProcessorContext routine +#pragma pack(2) + typedef struct + { + USHORT Limit; + ULONG Base; + } GDTIDT; +#pragma pack(4) + +// this is needed for new IDT filling +#if 0 +extern ULONG_PTR i386DivideByZero; +extern ULONG_PTR i386DebugException; +extern ULONG_PTR i386NMIException; +extern ULONG_PTR i386Breakpoint; +extern ULONG_PTR i386Overflow; +extern ULONG_PTR i386BoundException; +extern ULONG_PTR i386InvalidOpcode; +extern ULONG_PTR i386FPUNotAvailable; +extern ULONG_PTR i386DoubleFault; +extern ULONG_PTR i386CoprocessorSegment; +extern ULONG_PTR i386InvalidTSS; +extern ULONG_PTR i386SegmentNotPresent; +extern ULONG_PTR i386StackException; +extern ULONG_PTR i386GeneralProtectionFault; +extern ULONG_PTR i386PageFault; // exc 14 +extern ULONG_PTR i386CoprocessorError; // exc 16 +extern ULONG_PTR i386AlignmentCheck; // exc 17 +#endif + +/* GLOBALS ***************************************************************/ + +PHARDWARE_PTE PDE; +PHARDWARE_PTE HalPT; + +PUCHAR PhysicalPageTablesBuffer; +PUCHAR KernelPageTablesBuffer; +ULONG PhysicalPageTables; +ULONG KernelPageTables; + +MEMORY_ALLOCATION_DESCRIPTOR *Mad; +ULONG MadCount = 0; + + +/* FUNCTIONS **************************************************************/ + +BOOLEAN +MempAllocatePageTables() +{ + ULONG NumPageTables, TotalSize; + PUCHAR Buffer; + // It's better to allocate PDE + PTEs contigiuos + + // Max number of entries = MaxPageNum >> 10 + // FIXME: This is a number to describe ALL physical memory + // and windows doesn't expect ALL memory mapped... + NumPageTables = (GetSystemMemorySize() >> MM_PAGE_SHIFT) >> 10; + + DbgPrint((DPRINT_WINDOWS, "NumPageTables = %d\n", NumPageTables)); + + // Allocate memory block for all these things: + // PDE, HAL mapping page table, physical mapping, kernel mapping + // FIXME: PDE+HAL+KernelPTEs == FirmwarePermanent, Physical PTEs = FirmwareTemporary + TotalSize = (1+1+NumPageTables*2)*MM_PAGE_SIZE; + Buffer = MmAllocateMemoryWithType(TotalSize, LoaderFirmwarePermanent); + + if (Buffer == NULL) + { + UiMessageBox("Impossible to allocate memory block for page tables!"); + return FALSE; + } + + // Zero all this memory block + RtlZeroMemory(Buffer, TotalSize); + + // Set up pointers correctly now + PDE = (PHARDWARE_PTE)Buffer; + + // Map the page directory at 0xC0000000 (maps itself) + PDE[HYPER_SPACE_ENTRY].PageFrameNumber = (ULONG)PDE >> MM_PAGE_SHIFT; + PDE[HYPER_SPACE_ENTRY].Valid = 1; + PDE[HYPER_SPACE_ENTRY].Write = 1; + + // The last PDE slot is allocated for HAL's memory mapping (Virtual Addresses 0xFFC00000 - 0xFFFFFFFF) + HalPT = (PHARDWARE_PTE)&Buffer[MM_PAGE_SIZE*1]; + + // Map it + PDE[1023].PageFrameNumber = (ULONG)HalPT >> MM_PAGE_SHIFT; + PDE[1023].Valid = 1; + PDE[1023].Write = 1; + + // Store pointers to the tables for easier access + PhysicalPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2]; + KernelPageTablesBuffer = PhysicalPageTablesBuffer + NumPageTables*MM_PAGE_SIZE; + + // Mark physical PTE's buffer as FirmwareTemporary + //MmSetMemoryType(KernelPageTablesBuffer, NumPageTables*MM_PAGE_SIZE, LoaderFirmwareTemporary); + + // Zero counters of page tables used + PhysicalPageTables = 0; + KernelPageTables = 0; + + return TRUE; +} + +VOID +MempAllocatePTE(ULONG Entry, PHARDWARE_PTE *PhysicalPT, PHARDWARE_PTE *KernelPT) +{ + //Print(L"Creating PDE Entry %X\n", Entry); + + // Identity mapping + *PhysicalPT = (PHARDWARE_PTE)&PhysicalPageTablesBuffer[PhysicalPageTables*MM_PAGE_SIZE]; + PhysicalPageTables++; + + PDE[Entry].PageFrameNumber = (ULONG)*PhysicalPT >> MM_PAGE_SHIFT; + PDE[Entry].Valid = 1; + PDE[Entry].Write = 1; + + if (Entry+(KSEG0_BASE >> 22) > 1023) + { + DbgPrint((DPRINT_WINDOWS, "WARNING! Entry: %X > 1023\n", Entry+(KSEG0_BASE >> 22))); + } + + // Kernel-mode mapping + *KernelPT = (PHARDWARE_PTE)&KernelPageTablesBuffer[KernelPageTables*MM_PAGE_SIZE]; + KernelPageTables++; + + PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber = ((ULONG)*KernelPT >> MM_PAGE_SHIFT); + PDE[Entry+(KSEG0_BASE >> 22)].Valid = 1; + PDE[Entry+(KSEG0_BASE >> 22)].Write = 1; +} + +BOOLEAN +MempSetupPaging(IN ULONG StartPage, + IN ULONG NumberOfPages) +{ + PHARDWARE_PTE PhysicalPT; + PHARDWARE_PTE KernelPT; + ULONG Entry, Page; + + //Print(L"MempSetupPaging: SP 0x%X, Number: 0x%X\n", StartPage, NumberOfPages); + + // HACK + if (StartPage+NumberOfPages >= 0x80000) + { + // + // We can't map this as it requires more than 1 PDE + // and in fact it's not possible at all ;) + // + //Print(L"skipping...\n"); + return TRUE; + } + + // + // Now actually set up the page tables for identity mapping + // + for (Page=StartPage; Page < StartPage+NumberOfPages; Page++) + { + Entry = Page >> 10; + + if (((PULONG)PDE)[Entry] == 0) + { + MempAllocatePTE(Entry, &PhysicalPT, &KernelPT); + } + else + { + PhysicalPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT); + KernelPT = (PHARDWARE_PTE)(PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber << MM_PAGE_SHIFT); + } + + if (Page == 0) + { + PhysicalPT[Page & 0x3ff].PageFrameNumber = Page; + PhysicalPT[Page & 0x3ff].Valid = 0; + PhysicalPT[Page & 0x3ff].Write = 0; + + KernelPT[Page & 0x3ff].PageFrameNumber = Page; + KernelPT[Page & 0x3ff].Valid = 0; + KernelPT[Page & 0x3ff].Write = 0; + } + else + { + PhysicalPT[Page & 0x3ff].PageFrameNumber = Page; + PhysicalPT[Page & 0x3ff].Valid = 1; + PhysicalPT[Page & 0x3ff].Write = 1; + + KernelPT[Page & 0x3ff].PageFrameNumber = Page; + KernelPT[Page & 0x3ff].Valid = 1; + KernelPT[Page & 0x3ff].Write = 1; + } + } + + return TRUE; +} + +VOID +MempDisablePages() +{ + int i; + + // + // We need to delete kernel mapping from memory areas which are + // marked as Special or Permanent memory (thus non-accessible) + // + + for (i=0; i LOADER_HIGH_ZONE) + EndPage = LOADER_HIGH_ZONE; + } + + for (Page = StartPage; Page < EndPage; Page++) + { + PHARDWARE_PTE KernelPT; + ULONG Entry = (Page >> 10) + (KSEG0_BASE >> 22); + + if (PDE[Entry].Valid) + { + KernelPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT); + + if (KernelPT) + { + KernelPT[Page & 0x3ff].PageFrameNumber = 0; + KernelPT[Page & 0x3ff].Valid = 0; + KernelPT[Page & 0x3ff].Write = 0; + } + } + } + } + } +} + + +VOID +MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, + ULONG BasePage, + ULONG PageCount, + ULONG Type) +{ + BOOLEAN Status; + + // + // Check for some weird stuff at the top + // + if (BasePage + PageCount > 0xF0000) + { + // + // Just skip this, without even adding to MAD list + // + return; + } + + // + // Set Base page, page count and type + // + Mad[MadCount].BasePage = BasePage; + Mad[MadCount].PageCount = PageCount; + Mad[MadCount].MemoryType = Type; + + // + // Check if it's more than the allowed for OS loader + // if yes - don't map the pages, just add as FirmwareTemporary + // + if (BasePage + PageCount > LOADER_HIGH_ZONE) + { + if (Mad[MadCount].MemoryType != LoaderSpecialMemory || + Mad[MadCount].MemoryType != LoaderFirmwarePermanent) + { + Mad[MadCount].MemoryType = LoaderFirmwareTemporary; + } + + WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]); + MadCount++; + + return; + } + + // + // Add descriptor + // + WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]); + MadCount++; + + // + // Map it (don't map low 1Mb because it was already contigiously + // mapped in WinLdrTurnOnPaging) + // + if (BasePage >= 0x100) + { + Status = MempSetupPaging(BasePage, PageCount); + if (!Status) + { + DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging\n")); + return; + } + } +} + +BOOLEAN +WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, + ULONG PcrBasePage, + ULONG TssBasePage, + PVOID GdtIdt) +{ + ULONG i, PagesCount, MemoryMapSizeInPages; + ULONG LastPageIndex, LastPageType, MemoryMapStartPage; + PPAGE_LOOKUP_TABLE_ITEM MemoryMap; + ULONG NoEntries; + PKTSS Tss; + BOOLEAN Status; + + // + // Creating a suitable memory map for the Windows can be tricky, so let's + // give a few advices: + // 1) One must not map the whole available memory pages to PDE! + // Map only what's needed - 16Mb, 24Mb, 32Mb max I think, + // thus occupying 4, 6 or 8 PDE entries for identical mapping, + // the same quantity for KSEG0_BASE mapping, one more entry for + // hyperspace and one more entry for HAL physical pages mapping. + // 2) Memory descriptors must map *the whole* physical memory + // showing any memory above 16/24/32 as FirmwareTemporary + // + // 3) Overall memory blocks count must not exceed 30 + // + + // + // During MmInitMachineDependent, the kernel zeroes PDE at the following address + // 0xC0300000 - 0xC03007FC + // + // Then it finds the best place for non-paged pool: + // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD + // + + // Before we start mapping pages, create a block of memory, which will contain + // PDE and PTEs + if (MempAllocatePageTables() == FALSE) + return FALSE; + + // Allocate memory for memory allocation descriptors + Mad = MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR) * 1024); + + // Setup an entry for each descriptor + MemoryMap = MmGetMemoryMap(&NoEntries); + if (MemoryMap == NULL) + { + UiMessageBox("Can not retrieve the current memory map"); + return FALSE; + } + + // Calculate parameters of the memory map + MemoryMapStartPage = (ULONG_PTR)MemoryMap >> MM_PAGE_SHIFT; + MemoryMapSizeInPages = NoEntries * sizeof(PAGE_LOOKUP_TABLE_ITEM); + + DbgPrint((DPRINT_WINDOWS, "Got memory map with %d entries\n", NoEntries)); + + // Always contigiously map low 1Mb of memory + Status = MempSetupPaging(0, 0x100); + if (!Status) + { + DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging of low 1Mb\n")); + return FALSE; + } + + // Construct a good memory map from what we've got, + // but mark entries which the memory allocation bitmap takes + // as free entries (this is done in order to have the ability + // to place mem alloc bitmap outside lower 16Mb zone) + PagesCount = 1; + LastPageIndex = 0; + LastPageType = MemoryMap[0].PageAllocated; + for(i=1;i= MemoryMapStartPage && + i < (MemoryMapStartPage+MemoryMapSizeInPages)) + { + // Exclude it if current page belongs to the memory map + MemoryMap[i].PageAllocated = LoaderFree; + } + + // Process entry + if (MemoryMap[i].PageAllocated == LastPageType && + (i != NoEntries-1) ) + { + PagesCount++; + } + else + { + // Add the resulting region + MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, LastPageType); + + // Reset our counter vars + LastPageIndex = i; + LastPageType = MemoryMap[i].PageAllocated; + PagesCount = 1; + } + } + + // TEMP, DEBUG! + // adding special reserved memory zones for vmware workstation +#if 0 + { + Mad[MadCount].BasePage = 0xfec00; + Mad[MadCount].PageCount = 0x10; + Mad[MadCount].MemoryType = LoaderSpecialMemory; + WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]); + MadCount++; + + Mad[MadCount].BasePage = 0xfee00; + Mad[MadCount].PageCount = 0x1; + Mad[MadCount].MemoryType = LoaderSpecialMemory; + WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]); + MadCount++; + + Mad[MadCount].BasePage = 0xfffe0; + Mad[MadCount].PageCount = 0x20; + Mad[MadCount].MemoryType = LoaderSpecialMemory; + WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]); + MadCount++; + } +#endif + + DbgPrint((DPRINT_WINDOWS, "MadCount: %d\n", MadCount)); + + WinLdrpDumpMemoryDescriptors(LoaderBlock); //FIXME: Delete! + + // Map our loader image, so we can continue running + /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT); + if (!Status) + { + UiMessageBox("Error during MempSetupPaging"); + return; + }*/ + + //VideoDisplayString(L"Hello from VGA, going into the kernel\n"); + DbgPrint((DPRINT_WINDOWS, "HalPT: 0x%X\n", HalPT)); + + // Page Tables have been setup, make special handling for PCR and TSS + // (which is done in BlSetupFotNt in usual ntldr) + HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1; + HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1; + HalPT[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1; + + HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage; + HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1; + HalPT[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1; + + // Map VGA memory + //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached); + //DbgPrint((DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase)); + + Tss = (PKTSS)(KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT)); + + // Unmap what is not needed from kernel page table + MempDisablePages(); + + // Fill the memory descriptor list and + //PrepareMemoryDescriptorList(); + DbgPrint((DPRINT_WINDOWS, "Memory Descriptor List prepared, printing PDE\n")); + List_PaToVa(&LoaderBlock->MemoryDescriptorListHead); + +#ifdef DBG + { + ULONG *PDE_Addr=(ULONG *)PDE;//0xC0300000; + int j; + + DbgPrint((DPRINT_WINDOWS, "\nPDE\n")); + + for (i=0; i<128; i++) + { + DbgPrint((DPRINT_WINDOWS, "0x%04X | ", i*8)); + + for (j=0; j<8; j++) + { + DbgPrint((DPRINT_WINDOWS, "0x%08X ", PDE_Addr[i*8+j])); + } + + DbgPrint((DPRINT_WINDOWS, "\n")); + } + } +#endif + + + // Enable paging + //BS->ExitBootServices(ImageHandle,MapKey); + + // Disable Interrupts + _disable(); + + // Re-initalize EFLAGS + Ke386EraseFlags(); + + // Set the PDBR + __writecr3((ULONG_PTR)PDE); + + // Enable paging by modifying CR0 + __writecr0(__readcr0() | CR0_PG); + + // Set processor context + WinLdrSetProcessorContext(GdtIdt, KIP0PCRADDRESS, KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT)); + + // Zero KI_USER_SHARED_DATA page + memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE); + + return TRUE; +} + +// Two special things this func does: it sorts descriptors, +// and it merges free ones +VOID +WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock, + IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor) +{ + PLIST_ENTRY ListHead = &LoaderBlock->MemoryDescriptorListHead; + PLIST_ENTRY PreviousEntry, NextEntry; + PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor = NULL, NextDescriptor = NULL; + + DbgPrint((DPRINT_WINDOWS, "BP=0x%X PC=0x%X %s\n", NewDescriptor->BasePage, + NewDescriptor->PageCount, MemTypeDesc[NewDescriptor->MemoryType])); + + /* Find a place where to insert the new descriptor to */ + PreviousEntry = ListHead; + NextEntry = ListHead->Flink; + while (NextEntry != ListHead) + { + NextDescriptor = CONTAINING_RECORD(NextEntry, + MEMORY_ALLOCATION_DESCRIPTOR, + ListEntry); + if (NewDescriptor->BasePage < NextDescriptor->BasePage) + break; + + PreviousEntry = NextEntry; + PreviousDescriptor = NextDescriptor; + NextEntry = NextEntry->Flink; + } + + /* Don't forget about merging free areas */ + if (NewDescriptor->MemoryType != LoaderFree) + { + /* Just insert, nothing to merge */ + InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry); + } + else + { + /* Previous block also free? */ + if ((PreviousEntry != ListHead) && (PreviousDescriptor->MemoryType == LoaderFree) && + ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) == + NewDescriptor->BasePage)) + { + /* Just enlarge previous descriptor's PageCount */ + PreviousDescriptor->PageCount += NewDescriptor->PageCount; + NewDescriptor = PreviousDescriptor; + } + else + { + /* Nope, just insert */ + InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry); + } + + /* Next block is free ?*/ + if ((NextEntry != ListHead) && + (NextDescriptor->MemoryType == LoaderFree) && + ((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage)) + { + /* Enlarge next descriptor's PageCount */ + NewDescriptor->PageCount += NextDescriptor->PageCount; + RemoveEntryList(&NextDescriptor->ListEntry); + } + } + + return; +} + +VOID +WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss) +{ + GDTIDT GdtDesc, IdtDesc, OldIdt; + PKGDTENTRY pGdt; + PKIDTENTRY pIdt; + ULONG Ldt = 0; + //ULONG i; + + DbgPrint((DPRINT_WINDOWS, "GDtIdt %p, Pcr %p, Tss 0x%08X\n", + GdtIdt, Pcr, Tss)); + + // Kernel expects the PCR to be zero-filled on startup + // FIXME: Why zero it here when we can zero it right after allocation? + RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE); //FIXME: Why zero only 1 page when we allocate 2? + + // Get old values of GDT and IDT + Ke386GetGlobalDescriptorTable(GdtDesc); + Ke386GetInterruptDescriptorTable(IdtDesc); + + // Save old IDT + OldIdt.Base = IdtDesc.Base; + OldIdt.Limit = IdtDesc.Limit; + + // Prepare new IDT+GDT + GdtDesc.Base = KSEG0_BASE | (ULONG_PTR)GdtIdt; + GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1; + IdtDesc.Base = (ULONG)((PUCHAR)GdtDesc.Base + GdtDesc.Limit + 1); + IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1; + + // ======================== + // Fill all descriptors now + // ======================== + + pGdt = (PKGDTENTRY)GdtDesc.Base; + pIdt = (PKIDTENTRY)IdtDesc.Base; + + // + // Code selector (0x8) + // Flat 4Gb + // + pGdt[1].LimitLow = 0xFFFF; + pGdt[1].BaseLow = 0; + pGdt[1].HighWord.Bytes.BaseMid = 0; + pGdt[1].HighWord.Bytes.Flags1 = 0x9A; + pGdt[1].HighWord.Bytes.Flags2 = 0xCF; + pGdt[1].HighWord.Bytes.BaseHi = 0; + + // + // Data selector (0x10) + // Flat 4Gb + // + pGdt[2].LimitLow = 0xFFFF; + pGdt[2].BaseLow = 0; + pGdt[2].HighWord.Bytes.BaseMid = 0; + pGdt[2].HighWord.Bytes.Flags1 = 0x92; + pGdt[2].HighWord.Bytes.Flags2 = 0xCF; + pGdt[2].HighWord.Bytes.BaseHi = 0; + + // + // Selector (0x18) + // Flat 2Gb + // + pGdt[3].LimitLow = 0xFFFF; + pGdt[3].BaseLow = 0; + pGdt[3].HighWord.Bytes.BaseMid = 0; + pGdt[3].HighWord.Bytes.Flags1 = 0xFA; + pGdt[3].HighWord.Bytes.Flags2 = 0xCF; + pGdt[3].HighWord.Bytes.BaseHi = 0; + + // + // Selector (0x20) + // Flat 2Gb + // + pGdt[4].LimitLow = 0xFFFF; + pGdt[4].BaseLow = 0; + pGdt[4].HighWord.Bytes.BaseMid = 0; + pGdt[4].HighWord.Bytes.Flags1 = 0xF2; + pGdt[4].HighWord.Bytes.Flags2 = 0xCF; + pGdt[4].HighWord.Bytes.BaseHi = 0; + + // + // TSS Selector (0x28) + // + pGdt[5].LimitLow = 0x78-1; //FIXME: Check this + pGdt[5].BaseLow = (USHORT)(Tss & 0xffff); + pGdt[5].HighWord.Bytes.BaseMid = (UCHAR)((Tss >> 16) & 0xff); + pGdt[5].HighWord.Bytes.Flags1 = 0x89; + pGdt[5].HighWord.Bytes.Flags2 = 0x00; + pGdt[5].HighWord.Bytes.BaseHi = (UCHAR)((Tss >> 24) & 0xff); + + // + // PCR Selector (0x30) + // + pGdt[6].LimitLow = 0x01; + pGdt[6].BaseLow = (USHORT)(Pcr & 0xffff); + pGdt[6].HighWord.Bytes.BaseMid = (UCHAR)((Pcr >> 16) & 0xff); + pGdt[6].HighWord.Bytes.Flags1 = 0x92; + pGdt[6].HighWord.Bytes.Flags2 = 0xC0; + pGdt[6].HighWord.Bytes.BaseHi = (UCHAR)((Pcr >> 24) & 0xff); + + // + // Selector (0x38) + // + pGdt[7].LimitLow = 0xFFFF; + pGdt[7].BaseLow = 0; + pGdt[7].HighWord.Bytes.BaseMid = 0; + pGdt[7].HighWord.Bytes.Flags1 = 0xF3; + pGdt[7].HighWord.Bytes.Flags2 = 0x40; + pGdt[7].HighWord.Bytes.BaseHi = 0; + + // + // Some BIOS fuck (0x40) + // + pGdt[8].LimitLow = 0xFFFF; + pGdt[8].BaseLow = 0x400; + pGdt[8].HighWord.Bytes.BaseMid = 0; + pGdt[8].HighWord.Bytes.Flags1 = 0xF2; + pGdt[8].HighWord.Bytes.Flags2 = 0x0; + pGdt[8].HighWord.Bytes.BaseHi = 0; + + // + // Selector (0x48) + // + pGdt[9].LimitLow = 0; + pGdt[9].BaseLow = 0; + pGdt[9].HighWord.Bytes.BaseMid = 0; + pGdt[9].HighWord.Bytes.Flags1 = 0; + pGdt[9].HighWord.Bytes.Flags2 = 0; + pGdt[9].HighWord.Bytes.BaseHi = 0; + + // + // Selector (0x50) + // + pGdt[10].LimitLow = 0xFFFF; //FIXME: Not correct! + pGdt[10].BaseLow = 0; + pGdt[10].HighWord.Bytes.BaseMid = 0x2; + pGdt[10].HighWord.Bytes.Flags1 = 0x89; + pGdt[10].HighWord.Bytes.Flags2 = 0; + pGdt[10].HighWord.Bytes.BaseHi = 0; + + // + // Selector (0x58) + // + pGdt[11].LimitLow = 0xFFFF; + pGdt[11].BaseLow = 0; + pGdt[11].HighWord.Bytes.BaseMid = 0x2; + pGdt[11].HighWord.Bytes.Flags1 = 0x9A; + pGdt[11].HighWord.Bytes.Flags2 = 0; + pGdt[11].HighWord.Bytes.BaseHi = 0; + + // + // Selector (0x60) + // + pGdt[12].LimitLow = 0xFFFF; + pGdt[12].BaseLow = 0; //FIXME: Maybe not correct, but noone cares + pGdt[12].HighWord.Bytes.BaseMid = 0x2; + pGdt[12].HighWord.Bytes.Flags1 = 0x92; + pGdt[12].HighWord.Bytes.Flags2 = 0; + pGdt[12].HighWord.Bytes.BaseHi = 0; + + // + // Video buffer Selector (0x68) + // + pGdt[13].LimitLow = 0x3FFF; + pGdt[13].BaseLow = 0x8000; //FIXME: I guess not correct for UGA + pGdt[13].HighWord.Bytes.BaseMid = 0x0B; + pGdt[13].HighWord.Bytes.Flags1 = 0x92; + pGdt[13].HighWord.Bytes.Flags2 = 0; + pGdt[13].HighWord.Bytes.BaseHi = 0; + + // + // Points to GDT (0x70) + // + pGdt[14].LimitLow = NUM_GDT*sizeof(KGDTENTRY) - 1; + pGdt[14].BaseLow = 0x7000; + pGdt[14].HighWord.Bytes.BaseMid = 0xFF; + pGdt[14].HighWord.Bytes.Flags1 = 0x92; + pGdt[14].HighWord.Bytes.Flags2 = 0; + pGdt[14].HighWord.Bytes.BaseHi = 0xFF; + + // + // Some unused descriptors should go here + // ... + + // Copy the old IDT + RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit); + + // Mask interrupts + //asm("cli\n"); // they are already masked before enabling paged mode + + // Load GDT+IDT + Ke386SetGlobalDescriptorTable(GdtDesc); + Ke386SetInterruptDescriptorTable(IdtDesc); + + // Jump to proper CS and clear prefetch queue + asm("ljmp $0x08, $mb1\n" + "mb1:\n"); + + // Set SS selector + asm(".intel_syntax noprefix\n"); + asm("mov ax, 0x10\n"); // DataSelector=0x10 + asm("mov ss, ax\n"); + asm(".att_syntax\n"); + + // Set DS and ES selectors + Ke386SetDs(0x10); + Ke386SetEs(0x10); // this is vital for rep stosd + + // LDT = not used ever, thus set to 0 + Ke386SetLocalDescriptorTable(Ldt); + + // Load TSR + Ke386SetTr(0x28); + + // Clear GS + asm(".intel_syntax noprefix\n"); + asm("push 0\n"); + asm("pop gs\n"); + asm(".att_syntax\n"); + + // Set FS to PCR + Ke386SetFs(0x30); + + // Real end of the function, just for information + /* do not uncomment! + pop edi; + pop esi; + pop ebx; + mov esp, ebp; + pop ebp; + ret + */ +}