-/*\r
- * PROJECT: EFI Windows Loader\r
- * LICENSE: GPL - See COPYING in the top level directory\r
- * FILE: freeldr/winldr/conversion.c\r
- * PURPOSE: Physical <-> Virtual addressing mode conversions\r
- * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)\r
- */\r
-\r
-/* INCLUDES ***************************************************************/\r
-\r
-#include <freeldr.h>\r
-\r
-//#include <ndk/ldrtypes.h>\r
-#include <debug.h>\r
-\r
-/* FUNCTIONS **************************************************************/\r
-\r
-/* Arch-specific addresses translation implementation */\r
-PVOID\r
-VaToPa(PVOID Va)\r
-{\r
- return (PVOID)((ULONG_PTR)Va & ~KSEG0_BASE);\r
-}\r
-\r
-PVOID\r
-PaToVa(PVOID Pa)\r
-{\r
- return (PVOID)((ULONG_PTR)Pa | KSEG0_BASE);\r
-}\r
-\r
-VOID\r
-List_PaToVa(LIST_ENTRY *ListEntry)\r
-{\r
- LIST_ENTRY *ListHead = ListEntry;\r
- LIST_ENTRY *Next = ListEntry->Flink;\r
- LIST_ENTRY *NextPA;\r
-\r
- //Print(L"\n\nList_Entry: %X, First Next: %X\n", ListEntry, Next);\r
- //\r
- // Walk through the whole list\r
- //\r
- if (Next != NULL)\r
- {\r
- while (Next != PaToVa(ListHead))\r
- {\r
- NextPA = VaToPa(Next);\r
- //Print(L"Current: %X, Flink: %X, Blink: %X\n", Next, NextPA->Flink, NextPA->Blink);\r
-\r
- NextPA->Flink = PaToVa((PVOID)NextPA->Flink);\r
- NextPA->Blink = PaToVa((PVOID)NextPA->Blink);\r
-\r
- //Print(L"After converting Flink: %X, Blink: %X\n", NextPA->Flink, NextPA->Blink);\r
-\r
- Next = NextPA->Flink;\r
- }\r
-\r
- //\r
- // Finally convert first Flink/Blink\r
- //\r
- ListEntry->Flink = PaToVa((PVOID)ListEntry->Flink);\r
- if (ListEntry->Blink)\r
- ListEntry->Blink = PaToVa((PVOID)ListEntry->Blink);\r
- }\r
-}\r
-\r
-// This function converts only Child->Child, and calls itself for each Sibling\r
-VOID\r
-ConvertConfigToVA(PCONFIGURATION_COMPONENT_DATA Start)\r
-{\r
- PCONFIGURATION_COMPONENT_DATA Child;\r
- PCONFIGURATION_COMPONENT_DATA Sibling;\r
-\r
- DbgPrint((DPRINT_WINDOWS, "ConvertConfigToVA(Start 0x%X)\n", Start));\r
- Child = Start;\r
-\r
- while (Child != NULL)\r
- {\r
- if (Child->ConfigurationData)\r
- Child->ConfigurationData = PaToVa(Child->ConfigurationData);\r
-\r
- if (Child->Child)\r
- Child->Child = PaToVa(Child->Child);\r
-\r
- if (Child->Parent)\r
- Child->Parent = PaToVa(Child->Parent);\r
-\r
- if (Child->Sibling)\r
- Child->Sibling = PaToVa(Child->Sibling);\r
-\r
- if (Child->ComponentEntry.Identifier)\r
- Child->ComponentEntry.Identifier = PaToVa(Child->ComponentEntry.Identifier);\r
-\r
- DbgPrint((DPRINT_WINDOWS, "Device 0x%X class %d type %d id '%s', parent %p\n", Child,\r
- Child->ComponentEntry.Class, Child->ComponentEntry.Type, VaToPa(Child->ComponentEntry.Identifier), Child->Parent));\r
-\r
- // Go through siblings list\r
- Sibling = VaToPa(Child->Sibling);\r
- while (Sibling != NULL)\r
- {\r
- if (Sibling->ConfigurationData)\r
- Sibling->ConfigurationData = PaToVa(Sibling->ConfigurationData);\r
-\r
- if (Sibling->Child)\r
- Sibling->Child = PaToVa(Sibling->Child);\r
-\r
- if (Sibling->Parent)\r
- Sibling->Parent = PaToVa(Sibling->Parent);\r
-\r
- if (Sibling->Sibling)\r
- Sibling->Sibling = PaToVa(Sibling->Sibling);\r
-\r
- if (Sibling->ComponentEntry.Identifier)\r
- Sibling->ComponentEntry.Identifier = PaToVa(Sibling->ComponentEntry.Identifier);\r
-\r
- DbgPrint((DPRINT_WINDOWS, "Device 0x%X class %d type %d id '%s', parent %p\n", Sibling,\r
- Sibling->ComponentEntry.Class, Sibling->ComponentEntry.Type, VaToPa(Sibling->ComponentEntry.Identifier), Sibling->Parent));\r
-\r
- // Recurse into the Child tree\r
- if (VaToPa(Sibling->Child) != NULL)\r
- ConvertConfigToVA(VaToPa(Sibling->Child));\r
-\r
- Sibling = VaToPa(Sibling->Sibling);\r
- }\r
-\r
- // Go to the next child\r
- Child = VaToPa(Child->Child);\r
- }\r
-}\r
+/*
+ * PROJECT: EFI Windows Loader
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: freeldr/winldr/conversion.c
+ * PURPOSE: Physical <-> Virtual addressing mode conversions
+ * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
+ */
+
+/* INCLUDES ***************************************************************/
+
+#include <freeldr.h>
+
+//#include <ndk/ldrtypes.h>
+#include <debug.h>
+
+/* FUNCTIONS **************************************************************/
+
+/* Arch-specific addresses translation implementation */
+PVOID
+VaToPa(PVOID Va)
+{
+ return (PVOID)((ULONG_PTR)Va & ~KSEG0_BASE);
+}
+
+PVOID
+PaToVa(PVOID Pa)
+{
+ return (PVOID)((ULONG_PTR)Pa | KSEG0_BASE);
+}
+
+VOID
+List_PaToVa(LIST_ENTRY *ListEntry)
+{
+ LIST_ENTRY *ListHead = ListEntry;
+ LIST_ENTRY *Next = ListEntry->Flink;
+ LIST_ENTRY *NextPA;
+
+ //Print(L"\n\nList_Entry: %X, First Next: %X\n", ListEntry, Next);
+ //
+ // Walk through the whole list
+ //
+ if (Next != NULL)
+ {
+ while (Next != PaToVa(ListHead))
+ {
+ NextPA = VaToPa(Next);
+ //Print(L"Current: %X, Flink: %X, Blink: %X\n", Next, NextPA->Flink, NextPA->Blink);
+
+ NextPA->Flink = PaToVa((PVOID)NextPA->Flink);
+ NextPA->Blink = PaToVa((PVOID)NextPA->Blink);
+
+ //Print(L"After converting Flink: %X, Blink: %X\n", NextPA->Flink, NextPA->Blink);
+
+ Next = NextPA->Flink;
+ }
+
+ //
+ // Finally convert first Flink/Blink
+ //
+ ListEntry->Flink = PaToVa((PVOID)ListEntry->Flink);
+ if (ListEntry->Blink)
+ ListEntry->Blink = PaToVa((PVOID)ListEntry->Blink);
+ }
+}
+
+// This function converts only Child->Child, and calls itself for each Sibling
+VOID
+ConvertConfigToVA(PCONFIGURATION_COMPONENT_DATA Start)
+{
+ PCONFIGURATION_COMPONENT_DATA Child;
+ PCONFIGURATION_COMPONENT_DATA Sibling;
+
+ DbgPrint((DPRINT_WINDOWS, "ConvertConfigToVA(Start 0x%X)\n", Start));
+ Child = Start;
+
+ while (Child != NULL)
+ {
+ if (Child->ConfigurationData)
+ Child->ConfigurationData = PaToVa(Child->ConfigurationData);
+
+ if (Child->Child)
+ Child->Child = PaToVa(Child->Child);
+
+ if (Child->Parent)
+ Child->Parent = PaToVa(Child->Parent);
+
+ if (Child->Sibling)
+ Child->Sibling = PaToVa(Child->Sibling);
+
+ if (Child->ComponentEntry.Identifier)
+ Child->ComponentEntry.Identifier = PaToVa(Child->ComponentEntry.Identifier);
+
+ DbgPrint((DPRINT_WINDOWS, "Device 0x%X class %d type %d id '%s', parent %p\n", Child,
+ Child->ComponentEntry.Class, Child->ComponentEntry.Type, VaToPa(Child->ComponentEntry.Identifier), Child->Parent));
+
+ // Go through siblings list
+ Sibling = VaToPa(Child->Sibling);
+ while (Sibling != NULL)
+ {
+ if (Sibling->ConfigurationData)
+ Sibling->ConfigurationData = PaToVa(Sibling->ConfigurationData);
+
+ if (Sibling->Child)
+ Sibling->Child = PaToVa(Sibling->Child);
+
+ if (Sibling->Parent)
+ Sibling->Parent = PaToVa(Sibling->Parent);
+
+ if (Sibling->Sibling)
+ Sibling->Sibling = PaToVa(Sibling->Sibling);
+
+ if (Sibling->ComponentEntry.Identifier)
+ Sibling->ComponentEntry.Identifier = PaToVa(Sibling->ComponentEntry.Identifier);
+
+ DbgPrint((DPRINT_WINDOWS, "Device 0x%X class %d type %d id '%s', parent %p\n", Sibling,
+ Sibling->ComponentEntry.Class, Sibling->ComponentEntry.Type, VaToPa(Sibling->ComponentEntry.Identifier), Sibling->Parent));
+
+ // Recurse into the Child tree
+ if (VaToPa(Sibling->Child) != NULL)
+ ConvertConfigToVA(VaToPa(Sibling->Child));
+
+ Sibling = VaToPa(Sibling->Sibling);
+ }
+
+ // Go to the next child
+ Child = VaToPa(Child->Child);
+ }
+}
-/*\r
- * PROJECT: FreeLoader\r
- * LICENSE: GPL - See COPYING in the top level directory\r
- * FILE: freeldr/winldr/peloader.c\r
- * PURPOSE: Provides routines for loading PE files. To be merged with\r
- * arch/i386/loader.c in future\r
- * This article was very handy during development:\r
- * http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/\r
- * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)\r
- * The source code in this file is based on the work of respective\r
- * authors of PE loading code in ReactOS and Brian Palmer and\r
- * Alex Ionescu's arch/i386/loader.c, and my research project\r
- * (creating a native EFI loader for Windows)\r
- */\r
-\r
-/* INCLUDES ***************************************************************/\r
-#include <freeldr.h>\r
-#include <debug.h>\r
-\r
-\r
-BOOLEAN\r
-WinLdrpCompareDllName(IN PCH DllName,\r
- IN PUNICODE_STRING UnicodeName);\r
-\r
-BOOLEAN\r
-WinLdrpBindImportName(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
- IN PVOID DllBase,\r
- IN PVOID ImageBase,\r
- IN PIMAGE_THUNK_DATA ThunkData,\r
- IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,\r
- IN ULONG ExportSize,\r
- IN BOOLEAN ProcessForwards);\r
-\r
-BOOLEAN\r
-WinLdrpLoadAndScanReferencedDll(PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
- PCCH DirectoryPath,\r
- PCH ImportName,\r
- PLDR_DATA_TABLE_ENTRY *DataTableEntry);\r
-\r
-BOOLEAN\r
-WinLdrpScanImportAddressTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
- IN PVOID DllBase,\r
- IN PVOID ImageBase,\r
- IN PIMAGE_THUNK_DATA ThunkData);\r
-\r
-\r
-\r
-/* FUNCTIONS **************************************************************/\r
-\r
-/* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */\r
-BOOLEAN\r
-WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
- IN PCH DllName,\r
- OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry)\r
-{\r
- PLDR_DATA_TABLE_ENTRY DataTableEntry;\r
- LIST_ENTRY *ModuleEntry;\r
-\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrCheckForLoadedDll: DllName %X, LoadedEntry: %X\n",\r
- DllName, LoadedEntry));\r
-\r
- /* Just go through each entry in the LoadOrderList and compare loaded module's\r
- name with a given name */\r
- ModuleEntry = WinLdrBlock->LoadOrderListHead.Flink;\r
- while (ModuleEntry != &WinLdrBlock->LoadOrderListHead)\r
- {\r
- /* Get pointer to the current DTE */\r
- DataTableEntry = CONTAINING_RECORD(ModuleEntry,\r
- LDR_DATA_TABLE_ENTRY,\r
- InLoadOrderLinks);\r
-\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrCheckForLoadedDll: DTE %p, EP %p\n",\r
- DataTableEntry, DataTableEntry->EntryPoint));\r
-\r
- /* Compare names */\r
- if (WinLdrpCompareDllName(DllName, &DataTableEntry->BaseDllName))\r
- {\r
- /* Yes, found it, report pointer to the loaded module's DTE \r
- to the caller and increase load count for it */\r
- *LoadedEntry = DataTableEntry;\r
- DataTableEntry->LoadCount++;\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrCheckForLoadedDll: LoadedEntry %X\n", DataTableEntry));\r
- return TRUE;\r
- }\r
-\r
- /* Go to the next entry */\r
- ModuleEntry = ModuleEntry->Flink;\r
- }\r
-\r
- /* Nothing found */\r
- return FALSE;\r
-}\r
-\r
-BOOLEAN\r
-WinLdrScanImportDescriptorTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
- IN PCCH DirectoryPath,\r
- IN PLDR_DATA_TABLE_ENTRY ScanDTE)\r
-{\r
- PLDR_DATA_TABLE_ENTRY DataTableEntry;\r
- PIMAGE_IMPORT_DESCRIPTOR ImportTable;\r
- ULONG ImportTableSize;\r
- PCH ImportName;\r
- BOOLEAN Status;\r
-\r
- /* Get a pointer to the import table of this image */\r
- ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(ScanDTE->DllBase),\r
- TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize);\r
-\r
- {\r
- UNICODE_STRING BaseName;\r
- BaseName.Buffer = VaToPa(ScanDTE->BaseDllName.Buffer);\r
- BaseName.MaximumLength = ScanDTE->BaseDllName.MaximumLength;\r
- BaseName.Length = ScanDTE->BaseDllName.Length;\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n",\r
- &BaseName, ImportTable));\r
- }\r
-\r
- /* If image doesn't have any import directory - just return success */\r
- if (ImportTable == NULL)\r
- return TRUE;\r
-\r
- /* Loop through all entries */\r
- for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++)\r
- {\r
- /* Get pointer to the name */\r
- ImportName = (PCH)VaToPa(RVA(ScanDTE->DllBase, ImportTable->Name));\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable(): Looking at %s\n", ImportName));\r
-\r
- /* In case we get a reference to ourselves - just skip it */\r
- if (WinLdrpCompareDllName(ImportName, &ScanDTE->BaseDllName))\r
- continue;\r
-\r
- /* Load the DLL if it is not already loaded */\r
- if (!WinLdrCheckForLoadedDll(WinLdrBlock, ImportName, &DataTableEntry))\r
- {\r
- Status = WinLdrpLoadAndScanReferencedDll(WinLdrBlock,\r
- DirectoryPath,\r
- ImportName,\r
- &DataTableEntry);\r
-\r
- if (!Status)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrpLoadAndScanReferencedDll() failed\n"));\r
- return Status;\r
- }\r
- }\r
-\r
- /* Scan its import address table */\r
- Status = WinLdrpScanImportAddressTable(\r
- WinLdrBlock,\r
- DataTableEntry->DllBase,\r
- ScanDTE->DllBase,\r
- (PIMAGE_THUNK_DATA)RVA(ScanDTE->DllBase, ImportTable->FirstThunk));\r
-\r
- if (!Status)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrpScanImportAddressTable() failed\n"));\r
- return Status;\r
- }\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-WinLdrAllocateDataTableEntry(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
- IN PCCH BaseDllName,\r
- IN PCCH FullDllName,\r
- IN PVOID BasePA,\r
- OUT PLDR_DATA_TABLE_ENTRY *NewEntry)\r
-{\r
- PVOID BaseVA = PaToVa(BasePA);\r
- PWSTR Buffer;\r
- PLDR_DATA_TABLE_ENTRY DataTableEntry;\r
- PIMAGE_NT_HEADERS NtHeaders;\r
- USHORT Length;\r
-\r
- /* Allocate memory for a data table entry, zero-initialize it */\r
- DataTableEntry = (PLDR_DATA_TABLE_ENTRY)MmHeapAlloc(sizeof(LDR_DATA_TABLE_ENTRY));\r
- if (DataTableEntry == NULL)\r
- return FALSE;\r
- RtlZeroMemory(DataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY));\r
-\r
- /* Get NT headers from the image */\r
- NtHeaders = RtlImageNtHeader(BasePA);\r
-\r
- /* Initialize corresponding fields of DTE based on NT headers value */\r
- DataTableEntry->DllBase = BaseVA;\r
- DataTableEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;\r
- DataTableEntry->EntryPoint = RVA(BaseVA, NtHeaders->OptionalHeader.AddressOfEntryPoint);\r
- DataTableEntry->SectionPointer = 0;\r
- DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum;\r
-\r
- /* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName\r
- by simple conversion - copying each character */\r
- Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR));\r
- Buffer = (PWSTR)MmHeapAlloc(Length);\r
- if (Buffer == NULL)\r
- {\r
- MmHeapFree(DataTableEntry);\r
- return FALSE;\r
- }\r
- RtlZeroMemory(Buffer, Length);\r
-\r
- DataTableEntry->BaseDllName.Length = Length;\r
- DataTableEntry->BaseDllName.MaximumLength = Length;\r
- DataTableEntry->BaseDllName.Buffer = PaToVa(Buffer);\r
- while (*BaseDllName != 0)\r
- {\r
- *Buffer++ = *BaseDllName++;\r
- }\r
-\r
- /* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName\r
- using the same method */\r
- Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR));\r
- Buffer = (PWSTR)MmHeapAlloc(Length);\r
- if (Buffer == NULL)\r
- {\r
- MmHeapFree(DataTableEntry);\r
- return FALSE;\r
- }\r
- RtlZeroMemory(Buffer, Length);\r
-\r
- DataTableEntry->FullDllName.Length = Length;\r
- DataTableEntry->FullDllName.MaximumLength = Length;\r
- DataTableEntry->FullDllName.Buffer = PaToVa(Buffer);\r
- while (*FullDllName != 0)\r
- {\r
- *Buffer++ = *FullDllName++;\r
- }\r
-\r
- /* Initialize what's left - LoadCount which is 1, and set Flags so that\r
- we know this entry is processed */\r
- DataTableEntry->Flags = LDRP_ENTRY_PROCESSED;\r
- DataTableEntry->LoadCount = 1;\r
-\r
- /* Insert this DTE to a list in the LPB */\r
- InsertTailList(&WinLdrBlock->LoadOrderListHead, &DataTableEntry->InLoadOrderLinks);\r
-\r
- /* Save pointer to a newly allocated and initialized entry */\r
- *NewEntry = DataTableEntry;\r
-\r
- /* Return success */\r
- return TRUE;\r
-}\r
-\r
-/* WinLdrLoadImage loads the specified image from the file (it doesn't\r
- perform any additional operations on the filename, just directly\r
- calls the file I/O routines), and relocates it so that it's ready\r
- to be used when paging is enabled.\r
- Addressing mode: physical\r
- */\r
-BOOLEAN\r
-WinLdrLoadImage(IN PCHAR FileName,\r
- TYPE_OF_MEMORY MemoryType,\r
- OUT PVOID *ImageBasePA)\r
-{\r
- PFILE FileHandle;\r
- PVOID PhysicalBase;\r
- PVOID VirtualBase = NULL;\r
- UCHAR HeadersBuffer[SECTOR_SIZE * 2];\r
- PIMAGE_NT_HEADERS NtHeaders;\r
- PIMAGE_SECTION_HEADER SectionHeader;\r
- ULONG VirtualSize, SizeOfRawData, NumberOfSections;\r
- BOOLEAN Status;\r
- ULONG i, BytesRead;\r
-\r
- CHAR ProgressString[256];\r
-\r
- /* Inform user we are loading files */\r
- sprintf(ProgressString, "Loading %s...", FileName);\r
- UiDrawProgressBarCenter(1, 100, ProgressString);\r
-\r
- /* Open the image file */\r
- FileHandle = FsOpenFile(FileName);\r
-\r
- if (FileHandle == NULL)\r
- {\r
- //Print(L"Can not open the file %s\n",FileName);\r
- UiMessageBox("Can not open the file");\r
- return FALSE;\r
- }\r
-\r
- /* Load the first 2 sectors of the image so we can read the PE header */\r
- Status = FsReadFile(FileHandle, SECTOR_SIZE * 2, NULL, HeadersBuffer);\r
- if (!Status)\r
- {\r
- //Print(L"Error reading from file %s\n", FileName);\r
- UiMessageBox("Error reading from file");\r
- FsCloseFile(FileHandle);\r
- return FALSE;\r
- }\r
-\r
- /* Now read the MZ header to get the offset to the PE Header */\r
- NtHeaders = RtlImageNtHeader(HeadersBuffer);\r
-\r
- if (!NtHeaders)\r
- {\r
- //Print(L"Error - no NT header found in %s\n", FileName);\r
- UiMessageBox("Error - no NT header found");\r
- FsCloseFile(FileHandle);\r
- return FALSE;\r
- }\r
-\r
- /* Ensure this is executable image */\r
- if (((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0))\r
- {\r
- //Print(L"Not an executable image %s\n", FileName);\r
- UiMessageBox("Not an executable image");\r
- FsCloseFile(FileHandle);\r
- return FALSE;\r
- }\r
-\r
- /* Store number of sections to read and a pointer to the first section */\r
- NumberOfSections = NtHeaders->FileHeader.NumberOfSections;\r
- SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);\r
-\r
- /* Try to allocate this memory, if fails - allocate somewhere else */\r
- PhysicalBase = MmAllocateMemoryAtAddress(NtHeaders->OptionalHeader.SizeOfImage,\r
- (PVOID)((ULONG)NtHeaders->OptionalHeader.ImageBase & (KSEG0_BASE - 1)),\r
- MemoryType);\r
-\r
- if (PhysicalBase == NULL)\r
- {\r
- /* It's ok, we don't panic - let's allocate again at any other "low" place */\r
- PhysicalBase = MmAllocateMemoryWithType(NtHeaders->OptionalHeader.SizeOfImage, MemoryType);\r
-\r
- if (PhysicalBase == NULL)\r
- {\r
- //Print(L"Failed to alloc pages for image %s\n", FileName);\r
- UiMessageBox("Failed to alloc pages for image");\r
- FsCloseFile(FileHandle);\r
- return FALSE;\r
- }\r
- }\r
-\r
- /* This is the real image base - in form of a virtual address */\r
- VirtualBase = PaToVa(PhysicalBase);\r
-\r
- DbgPrint((DPRINT_WINDOWS, "Base PA: 0x%X, VA: 0x%X\n", PhysicalBase, VirtualBase));\r
-\r
- /* Set to 0 position and fully load the file image */\r
- FsSetFilePointer(FileHandle, 0);\r
-\r
- Status = FsReadFile(FileHandle, NtHeaders->OptionalHeader.SizeOfHeaders, NULL, PhysicalBase);\r
-\r
- if (!Status)\r
- {\r
- //Print(L"Error reading headers %s\n", FileName);\r
- UiMessageBox("Error reading headers");\r
- FsCloseFile(FileHandle);\r
- return FALSE;\r
- }\r
-\r
- /* Reload the NT Header */\r
- NtHeaders = RtlImageNtHeader(PhysicalBase);\r
-\r
- /* Load the first section */\r
- SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);\r
-\r
- /* Fill output parameters */\r
- *ImageBasePA = PhysicalBase;\r
-\r
- /* Walk through each section and read it (check/fix any possible\r
- bad situations, if they arise) */\r
- for (i = 0; i < NumberOfSections; i++)\r
- {\r
- VirtualSize = SectionHeader->Misc.VirtualSize;\r
- SizeOfRawData = SectionHeader->SizeOfRawData;\r
-\r
- /* Handle a case when VirtualSize equals 0 */\r
- if (VirtualSize == 0)\r
- VirtualSize = SizeOfRawData;\r
-\r
- /* If PointerToRawData is 0, then force its size to be also 0 */\r
- if (SectionHeader->PointerToRawData == 0)\r
- {\r
- SizeOfRawData = 0;\r
- }\r
- else\r
- {\r
- /* Cut the loaded size to the VirtualSize extents */\r
- if (SizeOfRawData > VirtualSize)\r
- SizeOfRawData = VirtualSize;\r
- }\r
-\r
- /* Actually read the section (if its size is not 0) */\r
- if (SizeOfRawData != 0)\r
- {\r
- /* Seek to the correct position */\r
- FsSetFilePointer(FileHandle, SectionHeader->PointerToRawData);\r
-\r
- DbgPrint((DPRINT_WINDOWS, "SH->VA: 0x%X\n", SectionHeader->VirtualAddress));\r
-\r
- /* Read this section from the file, size = SizeOfRawData */\r
- Status = FsReadFile(FileHandle, SizeOfRawData, &BytesRead, (PUCHAR)PhysicalBase + SectionHeader->VirtualAddress);\r
-\r
- if (!Status && (BytesRead == 0))\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrLoadImage(): Error reading section from file!\n"));\r
- break;\r
- }\r
- }\r
-\r
- /* Size of data is less than the virtual size - fill up the remainder with zeroes */\r
- if (SizeOfRawData < VirtualSize)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrLoadImage(): SORD %d < VS %d", SizeOfRawData, VirtualSize));\r
- RtlZeroMemory((PVOID)(SectionHeader->VirtualAddress + (ULONG)PhysicalBase + SizeOfRawData), VirtualSize - SizeOfRawData);\r
- }\r
-\r
- SectionHeader++;\r
- }\r
-\r
- /* We are done with the file - close it */\r
- FsCloseFile(FileHandle);\r
-\r
- /* If loading failed - return right now */\r
- if (!Status)\r
- return FALSE;\r
-\r
-\r
- /* Relocate the image, if it needs it */\r
- if (NtHeaders->OptionalHeader.ImageBase != (ULONG)VirtualBase)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "Relocating %p -> %p\n",\r
- NtHeaders->OptionalHeader.ImageBase, VirtualBase));\r
- Status = (BOOLEAN)LdrRelocateImageWithBias(PhysicalBase,\r
- (ULONG_PTR)VirtualBase - (ULONG_PTR)PhysicalBase,\r
- "FreeLdr",\r
- TRUE,\r
- TRUE, /* in case of conflict still return success */\r
- FALSE);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/* PRIVATE FUNCTIONS *******************************************************/\r
-\r
-/* DllName - physical, UnicodeString->Buffer - virtual */\r
-BOOLEAN\r
-WinLdrpCompareDllName(IN PCH DllName,\r
- IN PUNICODE_STRING UnicodeName)\r
-{\r
- PWSTR Buffer;\r
- UNICODE_STRING UnicodeNamePA;\r
- ULONG i, Length;\r
- \r
- /* First obvious check: for length of two names */\r
- Length = strlen(DllName);\r
-\r
- UnicodeNamePA.Length = UnicodeName->Length;\r
- UnicodeNamePA.MaximumLength = UnicodeName->MaximumLength;\r
- UnicodeNamePA.Buffer = VaToPa(UnicodeName->Buffer);\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrpCompareDllName: %s and %wZ, Length = %d "\r
- "UN->Length %d\n", DllName, &UnicodeNamePA, Length, UnicodeName->Length));\r
-\r
- if ((Length * sizeof(WCHAR)) > UnicodeName->Length)\r
- return FALSE;\r
-\r
- /* Store pointer to unicode string's buffer */\r
- Buffer = VaToPa(UnicodeName->Buffer);\r
-\r
- /* Loop character by character */\r
- for (i = 0; i < Length; i++)\r
- {\r
- /* Compare two characters, uppercasing them */\r
- if (toupper(*DllName) != toupper((CHAR)*Buffer))\r
- return FALSE;\r
-\r
- /* Move to the next character */\r
- DllName++;\r
- Buffer++;\r
- }\r
-\r
- /* Check, if strings either fully match, or match till the "." (w/o extension) */\r
- if ((UnicodeName->Length == Length * sizeof(WCHAR)) || (*Buffer == L'.'))\r
- {\r
- /* Yes they do */\r
- return TRUE;\r
- }\r
-\r
- /* Strings don't match, return FALSE */\r
- return FALSE;\r
-}\r
-\r
-BOOLEAN\r
-WinLdrpBindImportName(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
- IN PVOID DllBase,\r
- IN PVOID ImageBase,\r
- IN PIMAGE_THUNK_DATA ThunkData,\r
- IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,\r
- IN ULONG ExportSize,\r
- IN BOOLEAN ProcessForwards)\r
-{\r
- ULONG Ordinal;\r
- PULONG NameTable, FunctionTable;\r
- PUSHORT OrdinalTable;\r
- LONG High, Low, Middle, Result;\r
- ULONG Hint;\r
-\r
- //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n",\r
- // DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards));\r
-\r
- /* Check passed DllBase param */\r
- if(DllBase == NULL)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "WARNING: DllBase == NULL!\n"));\r
- return FALSE;\r
- }\r
-\r
- /* Convert all non-critical pointers to PA from VA */\r
- ThunkData = VaToPa(ThunkData);\r
-\r
- /* Is the reference by ordinal? */\r
- if (IMAGE_SNAP_BY_ORDINAL(ThunkData->u1.Ordinal) && !ProcessForwards)\r
- {\r
- /* Yes, calculate the ordinal */\r
- Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkData->u1.Ordinal) - (UINT32)ExportDirectory->Base);\r
- //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): Ordinal %d\n", Ordinal));\r
- }\r
- else\r
- {\r
- /* It's reference by name, we have to look it up in the export directory */\r
- if (!ProcessForwards)\r
- {\r
- /* AddressOfData in thunk entry will become a virtual address (from relative) */\r
- //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData));\r
- ThunkData->u1.AddressOfData =\r
- (ULONG)RVA(ImageBase, ThunkData->u1.AddressOfData);\r
- //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData));\r
- }\r
-\r
- /* Get pointers to Name and Ordinal tables (RVA -> VA) */\r
- NameTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfNames));\r
- OrdinalTable = (PUSHORT)VaToPa(RVA(DllBase, ExportDirectory->AddressOfNameOrdinals));\r
-\r
- //DbgPrint((DPRINT_WINDOWS, "NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n",\r
- // NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals));\r
-\r
- /* Get the hint, convert it to a physical pointer */\r
- Hint = ((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Hint;\r
- //DbgPrint((DPRINT_WINDOWS, "HintIndex %d\n", Hint));\r
-\r
- /* If Hint is less than total number of entries in the export directory,\r
- and import name == export name, then we can just get it from the OrdinalTable */\r
- if (\r
- (Hint < ExportDirectory->NumberOfNames) &&\r
- (\r
- strcmp(VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Name[0]),\r
- (PCHAR)VaToPa( RVA(DllBase, NameTable[Hint])) ) == 0\r
- )\r
- )\r
- {\r
- Ordinal = OrdinalTable[Hint];\r
- //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): Ordinal %d\n", Ordinal));\r
- }\r
- else\r
- {\r
- /* It's not the easy way, we have to lookup import name in the name table.\r
- Let's use a binary search for this task. */\r
-\r
- //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName() looking up the import name using binary search...\n"));\r
-\r
- /* Low boundary is set to 0, and high boundary to the maximum index */\r
- Low = 0;\r
- High = ExportDirectory->NumberOfNames - 1;\r
-\r
- /* Perform a binary-search loop */\r
- while (High >= Low)\r
- {\r
- /* Divide by 2 by shifting to the right once */\r
- Middle = (Low + High) >> 1;\r
-\r
- /* Compare the names */\r
- Result = strcmp(VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Name[0]),\r
- (PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));\r
-\r
- /*DbgPrint((DPRINT_WINDOWS, "Binary search: comparing Import '__', Export '%s'\n",*/\r
- /*VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),*/\r
- /*(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle]))));*/\r
-\r
- /*DbgPrint((DPRINT_WINDOWS, "TE->u1.AOD %p, fulladdr %p\n",\r
- ThunkData->u1.AddressOfData,\r
- ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name ));*/\r
-\r
-\r
- /* Depending on result of strcmp, perform different actions */\r
- if (Result < 0)\r
- {\r
- /* Adjust top boundary */\r
- High = Middle - 1;\r
- }\r
- else if (Result > 0)\r
- {\r
- /* Adjust bottom boundary */\r
- Low = Middle + 1;\r
- }\r
- else\r
- {\r
- /* Yay, found it! */\r
- break;\r
- }\r
- }\r
-\r
- /* If high boundary is less than low boundary, then no result found */\r
- if (High < Low)\r
- {\r
- //Print(L"Error in binary search\n");\r
- DbgPrint((DPRINT_WINDOWS, "Error in binary search!\n"));\r
- return FALSE;\r
- }\r
-\r
- /* Everything allright, get the ordinal */\r
- Ordinal = OrdinalTable[Middle];\r
- \r
- //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName() found Ordinal %d\n", Ordinal));\r
- }\r
- }\r
-\r
- /* Check ordinal number for validity! */\r
- if (Ordinal >= ExportDirectory->NumberOfFunctions)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "Ordinal number is invalid!\n"));\r
- return FALSE;\r
- }\r
-\r
- /* Get a pointer to the function table */\r
- FunctionTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfFunctions));\r
-\r
- /* Save a pointer to the function */\r
- ThunkData->u1.Function = (ULONG)RVA(DllBase, FunctionTable[Ordinal]);\r
-\r
- /* Is it a forwarder? (function pointer isn't within the export directory) */\r
- if (((ULONG)VaToPa((PVOID)ThunkData->u1.Function) > (ULONG)ExportDirectory) &&\r
- ((ULONG)VaToPa((PVOID)ThunkData->u1.Function) < ((ULONG)ExportDirectory + ExportSize)))\r
- {\r
- PLDR_DATA_TABLE_ENTRY DataTableEntry;\r
- CHAR ForwardDllName[255];\r
- PIMAGE_EXPORT_DIRECTORY RefExportDirectory;\r
- ULONG RefExportSize;\r
-\r
- /* Save the name of the forward dll */\r
- RtlCopyMemory(ForwardDllName, (PCHAR)VaToPa((PVOID)ThunkData->u1.Function), sizeof(ForwardDllName));\r
-\r
- /* Strip out its extension */\r
- *strchr(ForwardDllName,'.') = '\0';\r
-\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): ForwardDllName %s\n", ForwardDllName));\r
- if (!WinLdrCheckForLoadedDll(WinLdrBlock, ForwardDllName, &DataTableEntry))\r
- {\r
- /* We can't continue if DLL couldn't be loaded, so bomb out with an error */\r
- //Print(L"Error loading DLL!\n");\r
- DbgPrint((DPRINT_WINDOWS, "Error loading DLL!\n"));\r
- return FALSE;\r
- }\r
-\r
- /* Get pointer to the export directory of loaded DLL */\r
- RefExportDirectory = (PIMAGE_EXPORT_DIRECTORY)\r
- RtlImageDirectoryEntryToData(VaToPa(DataTableEntry->DllBase),\r
- TRUE,\r
- IMAGE_DIRECTORY_ENTRY_EXPORT,\r
- &RefExportSize);\r
-\r
- /* Fail if it's NULL */\r
- if (RefExportDirectory)\r
- {\r
- UCHAR Buffer[128];\r
- IMAGE_THUNK_DATA RefThunkData;\r
- PIMAGE_IMPORT_BY_NAME ImportByName;\r
- PCHAR ImportName;\r
- BOOLEAN Status;\r
-\r
- /* Get pointer to the import name */\r
- ImportName = strchr((PCHAR)VaToPa((PVOID)ThunkData->u1.Function), '.') + 1;\r
-\r
- /* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */\r
- ImportByName = (PIMAGE_IMPORT_BY_NAME)Buffer;\r
-\r
- /* Fill the name with the import name */\r
- RtlCopyMemory(ImportByName->Name, ImportName, strlen(ImportName)+1);\r
-\r
- /* Set Hint to 0 */\r
- ImportByName->Hint = 0;\r
-\r
- /* And finally point ThunkData's AddressOfData to that structure */\r
- RefThunkData.u1.AddressOfData = (ULONG)ImportByName;\r
-\r
- /* And recursively call ourselves */\r
- Status = WinLdrpBindImportName(\r
- WinLdrBlock,\r
- DataTableEntry->DllBase,\r
- ImageBase,\r
- &RefThunkData,\r
- RefExportDirectory,\r
- RefExportSize,\r
- TRUE);\r
-\r
- /* Fill out the ThunkData with data from RefThunkData */\r
- ThunkData->u1 = RefThunkData.u1;\r
-\r
- /* Return what we got from the recursive call */\r
- return Status;\r
- }\r
- else\r
- {\r
- /* Fail if ExportDirectory is NULL */\r
- return FALSE;\r
- }\r
- }\r
-\r
- /* Success! */\r
- return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-WinLdrpLoadAndScanReferencedDll(PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
- PCCH DirectoryPath,\r
- PCH ImportName,\r
- PLDR_DATA_TABLE_ENTRY *DataTableEntry)\r
-{\r
- CHAR FullDllName[256];\r
- BOOLEAN Status;\r
- PVOID BasePA;\r
-\r
- /* Prepare the full path to the file to be loaded */\r
- strcpy(FullDllName, DirectoryPath);\r
- strcat(FullDllName, ImportName);\r
-\r
- DbgPrint((DPRINT_WINDOWS, "Loading referenced DLL: %s\n", FullDllName));\r
- //Print(L"Loading referenced DLL: %s\n", FullDllName);\r
-\r
- /* Load the image */\r
- Status = WinLdrLoadImage(FullDllName, LoaderHalCode, &BasePA);\r
-\r
- if (!Status)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrLoadImage() failed\n"));\r
- return Status;\r
- }\r
-\r
- /* Allocate DTE for newly loaded DLL */\r
- Status = WinLdrAllocateDataTableEntry(WinLdrBlock,\r
- ImportName,\r
- FullDllName,\r
- BasePA,\r
- DataTableEntry);\r
-\r
- if (!Status)\r
- {\r
- DbgPrint((DPRINT_WINDOWS,\r
- "WinLdrAllocateDataTableEntry() failed with Status=0x%X\n", Status));\r
- return Status;\r
- }\r
-\r
- /* Scan its dependencies too */\r
- DbgPrint((DPRINT_WINDOWS,\r
- "WinLdrScanImportDescriptorTable() calling ourselves for %S\n",\r
- VaToPa((*DataTableEntry)->BaseDllName.Buffer)));\r
- Status = WinLdrScanImportDescriptorTable(WinLdrBlock, DirectoryPath, *DataTableEntry);\r
-\r
- if (!Status)\r
- {\r
- DbgPrint((DPRINT_WINDOWS,\r
- "WinLdrScanImportDescriptorTable() failed with Status=0x%X\n", Status));\r
- return Status;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-BOOLEAN\r
-WinLdrpScanImportAddressTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,\r
- IN PVOID DllBase,\r
- IN PVOID ImageBase,\r
- IN PIMAGE_THUNK_DATA ThunkData)\r
-{\r
- PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;\r
- BOOLEAN Status;\r
- ULONG ExportSize;\r
-\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrpScanImportAddressTable(): DllBase 0x%X, "\r
- "ImageBase 0x%X, ThunkData 0x%X\n", DllBase, ImageBase, ThunkData));\r
-\r
- /* Obtain the export table from the DLL's base */\r
- if (DllBase == NULL)\r
- {\r
- //Print(L"Error, DllBase == NULL!\n");\r
- return FALSE;\r
- }\r
- else\r
- {\r
- ExportDirectory =\r
- (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(VaToPa(DllBase),\r
- TRUE,\r
- IMAGE_DIRECTORY_ENTRY_EXPORT,\r
- &ExportSize);\r
- }\r
-\r
- DbgPrint((DPRINT_WINDOWS, "WinLdrpScanImportAddressTable(): ExportDirectory 0x%X\n", ExportDirectory));\r
-\r
- /* If pointer to Export Directory is */\r
- if (ExportDirectory == NULL)\r
- return FALSE;\r
-\r
- /* Go through each entry in the thunk table and bind it */\r
- while (((PIMAGE_THUNK_DATA)VaToPa(ThunkData))->u1.AddressOfData != 0)\r
- {\r
- /* Bind it */\r
- Status = WinLdrpBindImportName(\r
- WinLdrBlock,\r
- DllBase,\r
- ImageBase,\r
- ThunkData,\r
- ExportDirectory,\r
- ExportSize,\r
- FALSE);\r
-\r
- /* Move to the next entry */\r
- ThunkData++;\r
-\r
- /* Return error if binding was unsuccessful */\r
- if (!Status)\r
- return Status;\r
- }\r
-\r
- /* Return success */\r
- return TRUE;\r
-}\r
+/*
+ * PROJECT: FreeLoader
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: freeldr/winldr/peloader.c
+ * PURPOSE: Provides routines for loading PE files. To be merged with
+ * arch/i386/loader.c in future
+ * This article was very handy during development:
+ * http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/
+ * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
+ * The source code in this file is based on the work of respective
+ * authors of PE loading code in ReactOS and Brian Palmer and
+ * Alex Ionescu's arch/i386/loader.c, and my research project
+ * (creating a native EFI loader for Windows)
+ */
+
+/* INCLUDES ***************************************************************/
+#include <freeldr.h>
+#include <debug.h>
+
+
+BOOLEAN
+WinLdrpCompareDllName(IN PCH DllName,
+ IN PUNICODE_STRING UnicodeName);
+
+BOOLEAN
+WinLdrpBindImportName(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
+ IN PVOID DllBase,
+ IN PVOID ImageBase,
+ IN PIMAGE_THUNK_DATA ThunkData,
+ IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
+ IN ULONG ExportSize,
+ IN BOOLEAN ProcessForwards);
+
+BOOLEAN
+WinLdrpLoadAndScanReferencedDll(PLOADER_PARAMETER_BLOCK WinLdrBlock,
+ PCCH DirectoryPath,
+ PCH ImportName,
+ PLDR_DATA_TABLE_ENTRY *DataTableEntry);
+
+BOOLEAN
+WinLdrpScanImportAddressTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
+ IN PVOID DllBase,
+ IN PVOID ImageBase,
+ IN PIMAGE_THUNK_DATA ThunkData);
+
+
+
+/* FUNCTIONS **************************************************************/
+
+/* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */
+BOOLEAN
+WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
+ IN PCH DllName,
+ OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry)
+{
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ LIST_ENTRY *ModuleEntry;
+
+ DbgPrint((DPRINT_WINDOWS, "WinLdrCheckForLoadedDll: DllName %X, LoadedEntry: %X\n",
+ DllName, LoadedEntry));
+
+ /* Just go through each entry in the LoadOrderList and compare loaded module's
+ name with a given name */
+ ModuleEntry = WinLdrBlock->LoadOrderListHead.Flink;
+ while (ModuleEntry != &WinLdrBlock->LoadOrderListHead)
+ {
+ /* Get pointer to the current DTE */
+ DataTableEntry = CONTAINING_RECORD(ModuleEntry,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ DbgPrint((DPRINT_WINDOWS, "WinLdrCheckForLoadedDll: DTE %p, EP %p\n",
+ DataTableEntry, DataTableEntry->EntryPoint));
+
+ /* Compare names */
+ if (WinLdrpCompareDllName(DllName, &DataTableEntry->BaseDllName))
+ {
+ /* Yes, found it, report pointer to the loaded module's DTE
+ to the caller and increase load count for it */
+ *LoadedEntry = DataTableEntry;
+ DataTableEntry->LoadCount++;
+ DbgPrint((DPRINT_WINDOWS, "WinLdrCheckForLoadedDll: LoadedEntry %X\n", DataTableEntry));
+ return TRUE;
+ }
+
+ /* Go to the next entry */
+ ModuleEntry = ModuleEntry->Flink;
+ }
+
+ /* Nothing found */
+ return FALSE;
+}
+
+BOOLEAN
+WinLdrScanImportDescriptorTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
+ IN PCCH DirectoryPath,
+ IN PLDR_DATA_TABLE_ENTRY ScanDTE)
+{
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ PIMAGE_IMPORT_DESCRIPTOR ImportTable;
+ ULONG ImportTableSize;
+ PCH ImportName;
+ BOOLEAN Status;
+
+ /* Get a pointer to the import table of this image */
+ ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(ScanDTE->DllBase),
+ TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize);
+
+ {
+ UNICODE_STRING BaseName;
+ BaseName.Buffer = VaToPa(ScanDTE->BaseDllName.Buffer);
+ BaseName.MaximumLength = ScanDTE->BaseDllName.MaximumLength;
+ BaseName.Length = ScanDTE->BaseDllName.Length;
+ DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n",
+ &BaseName, ImportTable));
+ }
+
+ /* If image doesn't have any import directory - just return success */
+ if (ImportTable == NULL)
+ return TRUE;
+
+ /* Loop through all entries */
+ for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++)
+ {
+ /* Get pointer to the name */
+ ImportName = (PCH)VaToPa(RVA(ScanDTE->DllBase, ImportTable->Name));
+ DbgPrint((DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable(): Looking at %s\n", ImportName));
+
+ /* In case we get a reference to ourselves - just skip it */
+ if (WinLdrpCompareDllName(ImportName, &ScanDTE->BaseDllName))
+ continue;
+
+ /* Load the DLL if it is not already loaded */
+ if (!WinLdrCheckForLoadedDll(WinLdrBlock, ImportName, &DataTableEntry))
+ {
+ Status = WinLdrpLoadAndScanReferencedDll(WinLdrBlock,
+ DirectoryPath,
+ ImportName,
+ &DataTableEntry);
+
+ if (!Status)
+ {
+ DbgPrint((DPRINT_WINDOWS, "WinLdrpLoadAndScanReferencedDll() failed\n"));
+ return Status;
+ }
+ }
+
+ /* Scan its import address table */
+ Status = WinLdrpScanImportAddressTable(
+ WinLdrBlock,
+ DataTableEntry->DllBase,
+ ScanDTE->DllBase,
+ (PIMAGE_THUNK_DATA)RVA(ScanDTE->DllBase, ImportTable->FirstThunk));
+
+ if (!Status)
+ {
+ DbgPrint((DPRINT_WINDOWS, "WinLdrpScanImportAddressTable() failed\n"));
+ return Status;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+WinLdrAllocateDataTableEntry(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
+ IN PCCH BaseDllName,
+ IN PCCH FullDllName,
+ IN PVOID BasePA,
+ OUT PLDR_DATA_TABLE_ENTRY *NewEntry)
+{
+ PVOID BaseVA = PaToVa(BasePA);
+ PWSTR Buffer;
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ PIMAGE_NT_HEADERS NtHeaders;
+ USHORT Length;
+
+ /* Allocate memory for a data table entry, zero-initialize it */
+ DataTableEntry = (PLDR_DATA_TABLE_ENTRY)MmHeapAlloc(sizeof(LDR_DATA_TABLE_ENTRY));
+ if (DataTableEntry == NULL)
+ return FALSE;
+ RtlZeroMemory(DataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY));
+
+ /* Get NT headers from the image */
+ NtHeaders = RtlImageNtHeader(BasePA);
+
+ /* Initialize corresponding fields of DTE based on NT headers value */
+ DataTableEntry->DllBase = BaseVA;
+ DataTableEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
+ DataTableEntry->EntryPoint = RVA(BaseVA, NtHeaders->OptionalHeader.AddressOfEntryPoint);
+ DataTableEntry->SectionPointer = 0;
+ DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
+
+ /* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName
+ by simple conversion - copying each character */
+ Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR));
+ Buffer = (PWSTR)MmHeapAlloc(Length);
+ if (Buffer == NULL)
+ {
+ MmHeapFree(DataTableEntry);
+ return FALSE;
+ }
+ RtlZeroMemory(Buffer, Length);
+
+ DataTableEntry->BaseDllName.Length = Length;
+ DataTableEntry->BaseDllName.MaximumLength = Length;
+ DataTableEntry->BaseDllName.Buffer = PaToVa(Buffer);
+ while (*BaseDllName != 0)
+ {
+ *Buffer++ = *BaseDllName++;
+ }
+
+ /* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName
+ using the same method */
+ Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR));
+ Buffer = (PWSTR)MmHeapAlloc(Length);
+ if (Buffer == NULL)
+ {
+ MmHeapFree(DataTableEntry);
+ return FALSE;
+ }
+ RtlZeroMemory(Buffer, Length);
+
+ DataTableEntry->FullDllName.Length = Length;
+ DataTableEntry->FullDllName.MaximumLength = Length;
+ DataTableEntry->FullDllName.Buffer = PaToVa(Buffer);
+ while (*FullDllName != 0)
+ {
+ *Buffer++ = *FullDllName++;
+ }
+
+ /* Initialize what's left - LoadCount which is 1, and set Flags so that
+ we know this entry is processed */
+ DataTableEntry->Flags = LDRP_ENTRY_PROCESSED;
+ DataTableEntry->LoadCount = 1;
+
+ /* Insert this DTE to a list in the LPB */
+ InsertTailList(&WinLdrBlock->LoadOrderListHead, &DataTableEntry->InLoadOrderLinks);
+
+ /* Save pointer to a newly allocated and initialized entry */
+ *NewEntry = DataTableEntry;
+
+ /* Return success */
+ return TRUE;
+}
+
+/* WinLdrLoadImage loads the specified image from the file (it doesn't
+ perform any additional operations on the filename, just directly
+ calls the file I/O routines), and relocates it so that it's ready
+ to be used when paging is enabled.
+ Addressing mode: physical
+ */
+BOOLEAN
+WinLdrLoadImage(IN PCHAR FileName,
+ TYPE_OF_MEMORY MemoryType,
+ OUT PVOID *ImageBasePA)
+{
+ PFILE FileHandle;
+ PVOID PhysicalBase;
+ PVOID VirtualBase = NULL;
+ UCHAR HeadersBuffer[SECTOR_SIZE * 2];
+ PIMAGE_NT_HEADERS NtHeaders;
+ PIMAGE_SECTION_HEADER SectionHeader;
+ ULONG VirtualSize, SizeOfRawData, NumberOfSections;
+ BOOLEAN Status;
+ ULONG i, BytesRead;
+
+ CHAR ProgressString[256];
+
+ /* Inform user we are loading files */
+ sprintf(ProgressString, "Loading %s...", FileName);
+ UiDrawProgressBarCenter(1, 100, ProgressString);
+
+ /* Open the image file */
+ FileHandle = FsOpenFile(FileName);
+
+ if (FileHandle == NULL)
+ {
+ //Print(L"Can not open the file %s\n",FileName);
+ UiMessageBox("Can not open the file");
+ return FALSE;
+ }
+
+ /* Load the first 2 sectors of the image so we can read the PE header */
+ Status = FsReadFile(FileHandle, SECTOR_SIZE * 2, NULL, HeadersBuffer);
+ if (!Status)
+ {
+ //Print(L"Error reading from file %s\n", FileName);
+ UiMessageBox("Error reading from file");
+ FsCloseFile(FileHandle);
+ return FALSE;
+ }
+
+ /* Now read the MZ header to get the offset to the PE Header */
+ NtHeaders = RtlImageNtHeader(HeadersBuffer);
+
+ if (!NtHeaders)
+ {
+ //Print(L"Error - no NT header found in %s\n", FileName);
+ UiMessageBox("Error - no NT header found");
+ FsCloseFile(FileHandle);
+ return FALSE;
+ }
+
+ /* Ensure this is executable image */
+ if (((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0))
+ {
+ //Print(L"Not an executable image %s\n", FileName);
+ UiMessageBox("Not an executable image");
+ FsCloseFile(FileHandle);
+ return FALSE;
+ }
+
+ /* Store number of sections to read and a pointer to the first section */
+ NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
+ SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
+
+ /* Try to allocate this memory, if fails - allocate somewhere else */
+ PhysicalBase = MmAllocateMemoryAtAddress(NtHeaders->OptionalHeader.SizeOfImage,
+ (PVOID)((ULONG)NtHeaders->OptionalHeader.ImageBase & (KSEG0_BASE - 1)),
+ MemoryType);
+
+ if (PhysicalBase == NULL)
+ {
+ /* It's ok, we don't panic - let's allocate again at any other "low" place */
+ PhysicalBase = MmAllocateMemoryWithType(NtHeaders->OptionalHeader.SizeOfImage, MemoryType);
+
+ if (PhysicalBase == NULL)
+ {
+ //Print(L"Failed to alloc pages for image %s\n", FileName);
+ UiMessageBox("Failed to alloc pages for image");
+ FsCloseFile(FileHandle);
+ return FALSE;
+ }
+ }
+
+ /* This is the real image base - in form of a virtual address */
+ VirtualBase = PaToVa(PhysicalBase);
+
+ DbgPrint((DPRINT_WINDOWS, "Base PA: 0x%X, VA: 0x%X\n", PhysicalBase, VirtualBase));
+
+ /* Set to 0 position and fully load the file image */
+ FsSetFilePointer(FileHandle, 0);
+
+ Status = FsReadFile(FileHandle, NtHeaders->OptionalHeader.SizeOfHeaders, NULL, PhysicalBase);
+
+ if (!Status)
+ {
+ //Print(L"Error reading headers %s\n", FileName);
+ UiMessageBox("Error reading headers");
+ FsCloseFile(FileHandle);
+ return FALSE;
+ }
+
+ /* Reload the NT Header */
+ NtHeaders = RtlImageNtHeader(PhysicalBase);
+
+ /* Load the first section */
+ SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
+
+ /* Fill output parameters */
+ *ImageBasePA = PhysicalBase;
+
+ /* Walk through each section and read it (check/fix any possible
+ bad situations, if they arise) */
+ for (i = 0; i < NumberOfSections; i++)
+ {
+ VirtualSize = SectionHeader->Misc.VirtualSize;
+ SizeOfRawData = SectionHeader->SizeOfRawData;
+
+ /* Handle a case when VirtualSize equals 0 */
+ if (VirtualSize == 0)
+ VirtualSize = SizeOfRawData;
+
+ /* If PointerToRawData is 0, then force its size to be also 0 */
+ if (SectionHeader->PointerToRawData == 0)
+ {
+ SizeOfRawData = 0;
+ }
+ else
+ {
+ /* Cut the loaded size to the VirtualSize extents */
+ if (SizeOfRawData > VirtualSize)
+ SizeOfRawData = VirtualSize;
+ }
+
+ /* Actually read the section (if its size is not 0) */
+ if (SizeOfRawData != 0)
+ {
+ /* Seek to the correct position */
+ FsSetFilePointer(FileHandle, SectionHeader->PointerToRawData);
+
+ DbgPrint((DPRINT_WINDOWS, "SH->VA: 0x%X\n", SectionHeader->VirtualAddress));
+
+ /* Read this section from the file, size = SizeOfRawData */
+ Status = FsReadFile(FileHandle, SizeOfRawData, &BytesRead, (PUCHAR)PhysicalBase + SectionHeader->VirtualAddress);
+
+ if (!Status && (BytesRead == 0))
+ {
+ DbgPrint((DPRINT_WINDOWS, "WinLdrLoadImage(): Error reading section from file!\n"));
+ break;
+ }
+ }
+
+ /* Size of data is less than the virtual size - fill up the remainder with zeroes */
+ if (SizeOfRawData < VirtualSize)
+ {
+ DbgPrint((DPRINT_WINDOWS, "WinLdrLoadImage(): SORD %d < VS %d", SizeOfRawData, VirtualSize));
+ RtlZeroMemory((PVOID)(SectionHeader->VirtualAddress + (ULONG)PhysicalBase + SizeOfRawData), VirtualSize - SizeOfRawData);
+ }
+
+ SectionHeader++;
+ }
+
+ /* We are done with the file - close it */
+ FsCloseFile(FileHandle);
+
+ /* If loading failed - return right now */
+ if (!Status)
+ return FALSE;
+
+
+ /* Relocate the image, if it needs it */
+ if (NtHeaders->OptionalHeader.ImageBase != (ULONG)VirtualBase)
+ {
+ DbgPrint((DPRINT_WINDOWS, "Relocating %p -> %p\n",
+ NtHeaders->OptionalHeader.ImageBase, VirtualBase));
+ Status = (BOOLEAN)LdrRelocateImageWithBias(PhysicalBase,
+ (ULONG_PTR)VirtualBase - (ULONG_PTR)PhysicalBase,
+ "FreeLdr",
+ TRUE,
+ TRUE, /* in case of conflict still return success */
+ FALSE);
+ }
+
+ return Status;
+}
+
+/* PRIVATE FUNCTIONS *******************************************************/
+
+/* DllName - physical, UnicodeString->Buffer - virtual */
+BOOLEAN
+WinLdrpCompareDllName(IN PCH DllName,
+ IN PUNICODE_STRING UnicodeName)
+{
+ PWSTR Buffer;
+ UNICODE_STRING UnicodeNamePA;
+ ULONG i, Length;
+
+ /* First obvious check: for length of two names */
+ Length = strlen(DllName);
+
+ UnicodeNamePA.Length = UnicodeName->Length;
+ UnicodeNamePA.MaximumLength = UnicodeName->MaximumLength;
+ UnicodeNamePA.Buffer = VaToPa(UnicodeName->Buffer);
+ DbgPrint((DPRINT_WINDOWS, "WinLdrpCompareDllName: %s and %wZ, Length = %d "
+ "UN->Length %d\n", DllName, &UnicodeNamePA, Length, UnicodeName->Length));
+
+ if ((Length * sizeof(WCHAR)) > UnicodeName->Length)
+ return FALSE;
+
+ /* Store pointer to unicode string's buffer */
+ Buffer = VaToPa(UnicodeName->Buffer);
+
+ /* Loop character by character */
+ for (i = 0; i < Length; i++)
+ {
+ /* Compare two characters, uppercasing them */
+ if (toupper(*DllName) != toupper((CHAR)*Buffer))
+ return FALSE;
+
+ /* Move to the next character */
+ DllName++;
+ Buffer++;
+ }
+
+ /* Check, if strings either fully match, or match till the "." (w/o extension) */
+ if ((UnicodeName->Length == Length * sizeof(WCHAR)) || (*Buffer == L'.'))
+ {
+ /* Yes they do */
+ return TRUE;
+ }
+
+ /* Strings don't match, return FALSE */
+ return FALSE;
+}
+
+BOOLEAN
+WinLdrpBindImportName(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
+ IN PVOID DllBase,
+ IN PVOID ImageBase,
+ IN PIMAGE_THUNK_DATA ThunkData,
+ IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
+ IN ULONG ExportSize,
+ IN BOOLEAN ProcessForwards)
+{
+ ULONG Ordinal;
+ PULONG NameTable, FunctionTable;
+ PUSHORT OrdinalTable;
+ LONG High, Low, Middle, Result;
+ ULONG Hint;
+
+ //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n",
+ // DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards));
+
+ /* Check passed DllBase param */
+ if(DllBase == NULL)
+ {
+ DbgPrint((DPRINT_WINDOWS, "WARNING: DllBase == NULL!\n"));
+ return FALSE;
+ }
+
+ /* Convert all non-critical pointers to PA from VA */
+ ThunkData = VaToPa(ThunkData);
+
+ /* Is the reference by ordinal? */
+ if (IMAGE_SNAP_BY_ORDINAL(ThunkData->u1.Ordinal) && !ProcessForwards)
+ {
+ /* Yes, calculate the ordinal */
+ Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkData->u1.Ordinal) - (UINT32)ExportDirectory->Base);
+ //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): Ordinal %d\n", Ordinal));
+ }
+ else
+ {
+ /* It's reference by name, we have to look it up in the export directory */
+ if (!ProcessForwards)
+ {
+ /* AddressOfData in thunk entry will become a virtual address (from relative) */
+ //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData));
+ ThunkData->u1.AddressOfData =
+ (ULONG)RVA(ImageBase, ThunkData->u1.AddressOfData);
+ //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData));
+ }
+
+ /* Get pointers to Name and Ordinal tables (RVA -> VA) */
+ NameTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfNames));
+ OrdinalTable = (PUSHORT)VaToPa(RVA(DllBase, ExportDirectory->AddressOfNameOrdinals));
+
+ //DbgPrint((DPRINT_WINDOWS, "NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n",
+ // NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals));
+
+ /* Get the hint, convert it to a physical pointer */
+ Hint = ((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Hint;
+ //DbgPrint((DPRINT_WINDOWS, "HintIndex %d\n", Hint));
+
+ /* If Hint is less than total number of entries in the export directory,
+ and import name == export name, then we can just get it from the OrdinalTable */
+ if (
+ (Hint < ExportDirectory->NumberOfNames) &&
+ (
+ strcmp(VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Name[0]),
+ (PCHAR)VaToPa( RVA(DllBase, NameTable[Hint])) ) == 0
+ )
+ )
+ {
+ Ordinal = OrdinalTable[Hint];
+ //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): Ordinal %d\n", Ordinal));
+ }
+ else
+ {
+ /* It's not the easy way, we have to lookup import name in the name table.
+ Let's use a binary search for this task. */
+
+ //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName() looking up the import name using binary search...\n"));
+
+ /* Low boundary is set to 0, and high boundary to the maximum index */
+ Low = 0;
+ High = ExportDirectory->NumberOfNames - 1;
+
+ /* Perform a binary-search loop */
+ while (High >= Low)
+ {
+ /* Divide by 2 by shifting to the right once */
+ Middle = (Low + High) >> 1;
+
+ /* Compare the names */
+ Result = strcmp(VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Name[0]),
+ (PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));
+
+ /*DbgPrint((DPRINT_WINDOWS, "Binary search: comparing Import '__', Export '%s'\n",*/
+ /*VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),*/
+ /*(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle]))));*/
+
+ /*DbgPrint((DPRINT_WINDOWS, "TE->u1.AOD %p, fulladdr %p\n",
+ ThunkData->u1.AddressOfData,
+ ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name ));*/
+
+
+ /* Depending on result of strcmp, perform different actions */
+ if (Result < 0)
+ {
+ /* Adjust top boundary */
+ High = Middle - 1;
+ }
+ else if (Result > 0)
+ {
+ /* Adjust bottom boundary */
+ Low = Middle + 1;
+ }
+ else
+ {
+ /* Yay, found it! */
+ break;
+ }
+ }
+
+ /* If high boundary is less than low boundary, then no result found */
+ if (High < Low)
+ {
+ //Print(L"Error in binary search\n");
+ DbgPrint((DPRINT_WINDOWS, "Error in binary search!\n"));
+ return FALSE;
+ }
+
+ /* Everything allright, get the ordinal */
+ Ordinal = OrdinalTable[Middle];
+
+ //DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName() found Ordinal %d\n", Ordinal));
+ }
+ }
+
+ /* Check ordinal number for validity! */
+ if (Ordinal >= ExportDirectory->NumberOfFunctions)
+ {
+ DbgPrint((DPRINT_WINDOWS, "Ordinal number is invalid!\n"));
+ return FALSE;
+ }
+
+ /* Get a pointer to the function table */
+ FunctionTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfFunctions));
+
+ /* Save a pointer to the function */
+ ThunkData->u1.Function = (ULONG)RVA(DllBase, FunctionTable[Ordinal]);
+
+ /* Is it a forwarder? (function pointer isn't within the export directory) */
+ if (((ULONG)VaToPa((PVOID)ThunkData->u1.Function) > (ULONG)ExportDirectory) &&
+ ((ULONG)VaToPa((PVOID)ThunkData->u1.Function) < ((ULONG)ExportDirectory + ExportSize)))
+ {
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ CHAR ForwardDllName[255];
+ PIMAGE_EXPORT_DIRECTORY RefExportDirectory;
+ ULONG RefExportSize;
+
+ /* Save the name of the forward dll */
+ RtlCopyMemory(ForwardDllName, (PCHAR)VaToPa((PVOID)ThunkData->u1.Function), sizeof(ForwardDllName));
+
+ /* Strip out its extension */
+ *strchr(ForwardDllName,'.') = '\0';
+
+ DbgPrint((DPRINT_WINDOWS, "WinLdrpBindImportName(): ForwardDllName %s\n", ForwardDllName));
+ if (!WinLdrCheckForLoadedDll(WinLdrBlock, ForwardDllName, &DataTableEntry))
+ {
+ /* We can't continue if DLL couldn't be loaded, so bomb out with an error */
+ //Print(L"Error loading DLL!\n");
+ DbgPrint((DPRINT_WINDOWS, "Error loading DLL!\n"));
+ return FALSE;
+ }
+
+ /* Get pointer to the export directory of loaded DLL */
+ RefExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
+ RtlImageDirectoryEntryToData(VaToPa(DataTableEntry->DllBase),
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &RefExportSize);
+
+ /* Fail if it's NULL */
+ if (RefExportDirectory)
+ {
+ UCHAR Buffer[128];
+ IMAGE_THUNK_DATA RefThunkData;
+ PIMAGE_IMPORT_BY_NAME ImportByName;
+ PCHAR ImportName;
+ BOOLEAN Status;
+
+ /* Get pointer to the import name */
+ ImportName = strchr((PCHAR)VaToPa((PVOID)ThunkData->u1.Function), '.') + 1;
+
+ /* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */
+ ImportByName = (PIMAGE_IMPORT_BY_NAME)Buffer;
+
+ /* Fill the name with the import name */
+ RtlCopyMemory(ImportByName->Name, ImportName, strlen(ImportName)+1);
+
+ /* Set Hint to 0 */
+ ImportByName->Hint = 0;
+
+ /* And finally point ThunkData's AddressOfData to that structure */
+ RefThunkData.u1.AddressOfData = (ULONG)ImportByName;
+
+ /* And recursively call ourselves */
+ Status = WinLdrpBindImportName(
+ WinLdrBlock,
+ DataTableEntry->DllBase,
+ ImageBase,
+ &RefThunkData,
+ RefExportDirectory,
+ RefExportSize,
+ TRUE);
+
+ /* Fill out the ThunkData with data from RefThunkData */
+ ThunkData->u1 = RefThunkData.u1;
+
+ /* Return what we got from the recursive call */
+ return Status;
+ }
+ else
+ {
+ /* Fail if ExportDirectory is NULL */
+ return FALSE;
+ }
+ }
+
+ /* Success! */
+ return TRUE;
+}
+
+BOOLEAN
+WinLdrpLoadAndScanReferencedDll(PLOADER_PARAMETER_BLOCK WinLdrBlock,
+ PCCH DirectoryPath,
+ PCH ImportName,
+ PLDR_DATA_TABLE_ENTRY *DataTableEntry)
+{
+ CHAR FullDllName[256];
+ BOOLEAN Status;
+ PVOID BasePA;
+
+ /* Prepare the full path to the file to be loaded */
+ strcpy(FullDllName, DirectoryPath);
+ strcat(FullDllName, ImportName);
+
+ DbgPrint((DPRINT_WINDOWS, "Loading referenced DLL: %s\n", FullDllName));
+ //Print(L"Loading referenced DLL: %s\n", FullDllName);
+
+ /* Load the image */
+ Status = WinLdrLoadImage(FullDllName, LoaderHalCode, &BasePA);
+
+ if (!Status)
+ {
+ DbgPrint((DPRINT_WINDOWS, "WinLdrLoadImage() failed\n"));
+ return Status;
+ }
+
+ /* Allocate DTE for newly loaded DLL */
+ Status = WinLdrAllocateDataTableEntry(WinLdrBlock,
+ ImportName,
+ FullDllName,
+ BasePA,
+ DataTableEntry);
+
+ if (!Status)
+ {
+ DbgPrint((DPRINT_WINDOWS,
+ "WinLdrAllocateDataTableEntry() failed with Status=0x%X\n", Status));
+ return Status;
+ }
+
+ /* Scan its dependencies too */
+ DbgPrint((DPRINT_WINDOWS,
+ "WinLdrScanImportDescriptorTable() calling ourselves for %S\n",
+ VaToPa((*DataTableEntry)->BaseDllName.Buffer)));
+ Status = WinLdrScanImportDescriptorTable(WinLdrBlock, DirectoryPath, *DataTableEntry);
+
+ if (!Status)
+ {
+ DbgPrint((DPRINT_WINDOWS,
+ "WinLdrScanImportDescriptorTable() failed with Status=0x%X\n", Status));
+ return Status;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+WinLdrpScanImportAddressTable(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
+ IN PVOID DllBase,
+ IN PVOID ImageBase,
+ IN PIMAGE_THUNK_DATA ThunkData)
+{
+ PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
+ BOOLEAN Status;
+ ULONG ExportSize;
+
+ DbgPrint((DPRINT_WINDOWS, "WinLdrpScanImportAddressTable(): DllBase 0x%X, "
+ "ImageBase 0x%X, ThunkData 0x%X\n", DllBase, ImageBase, ThunkData));
+
+ /* Obtain the export table from the DLL's base */
+ if (DllBase == NULL)
+ {
+ //Print(L"Error, DllBase == NULL!\n");
+ return FALSE;
+ }
+ else
+ {
+ ExportDirectory =
+ (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(VaToPa(DllBase),
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &ExportSize);
+ }
+
+ DbgPrint((DPRINT_WINDOWS, "WinLdrpScanImportAddressTable(): ExportDirectory 0x%X\n", ExportDirectory));
+
+ /* If pointer to Export Directory is */
+ if (ExportDirectory == NULL)
+ return FALSE;
+
+ /* Go through each entry in the thunk table and bind it */
+ while (((PIMAGE_THUNK_DATA)VaToPa(ThunkData))->u1.AddressOfData != 0)
+ {
+ /* Bind it */
+ Status = WinLdrpBindImportName(
+ WinLdrBlock,
+ DllBase,
+ ImageBase,
+ ThunkData,
+ ExportDirectory,
+ ExportSize,
+ FALSE);
+
+ /* Move to the next entry */
+ ThunkData++;
+
+ /* Return error if binding was unsuccessful */
+ if (!Status)
+ return Status;
+ }
+
+ /* Return success */
+ return TRUE;
+}
PVOID WinLdrLoadModule(PCSTR ModuleName, ULONG *Size,
TYPE_OF_MEMORY MemoryType)
{
- PFILE FileHandle;\r
- PVOID PhysicalBase;\r
- ULONG FileSize;\r
- BOOLEAN Status;\r
-\r
- //CHAR ProgressString[256];\r
-\r
- /* Inform user we are loading files */\r
- //sprintf(ProgressString, "Loading %s...", FileName);\r
- //UiDrawProgressBarCenter(1, 100, ProgressString);\r
-\r
- DbgPrint((DPRINT_WINDOWS, "Loading module %s\n", ModuleName));\r
- *Size = 0;\r
-\r
- /* Open the image file */\r
- FileHandle = FsOpenFile(ModuleName);\r
-\r
- if (FileHandle == NULL)\r
- {\r
- /* In case of errors, we just return, without complaining to the user */\r
- return NULL;\r
- }\r
-\r
- /* Get this file's size */\r
- FileSize = FsGetFileSize(FileHandle);\r
- *Size = FileSize;\r
-\r
- /* Allocate memory */\r
- PhysicalBase = MmAllocateMemoryWithType(FileSize, MemoryType);\r
- if (PhysicalBase == NULL)\r
- {\r
- FsCloseFile(FileHandle);\r
- return NULL;\r
- }\r
-\r
- /* Load whole file */\r
- Status = FsReadFile(FileHandle, FileSize, NULL, PhysicalBase);\r
- if (!Status)\r
- {\r
- FsCloseFile(FileHandle);\r
- return NULL;\r
- }\r
-\r
- DbgPrint((DPRINT_WINDOWS, "Loaded %s at 0x%x with size 0x%x\n", ModuleName, PhysicalBase, FileSize));\r
-\r
- /* We are done with the file - close it */\r
- FsCloseFile(FileHandle);\r
-\r
- return PhysicalBase;\r
+ PFILE FileHandle;
+ PVOID PhysicalBase;
+ ULONG FileSize;
+ BOOLEAN Status;
+
+ //CHAR ProgressString[256];
+
+ /* Inform user we are loading files */
+ //sprintf(ProgressString, "Loading %s...", FileName);
+ //UiDrawProgressBarCenter(1, 100, ProgressString);
+
+ DbgPrint((DPRINT_WINDOWS, "Loading module %s\n", ModuleName));
+ *Size = 0;
+
+ /* Open the image file */
+ FileHandle = FsOpenFile(ModuleName);
+
+ if (FileHandle == NULL)
+ {
+ /* In case of errors, we just return, without complaining to the user */
+ return NULL;
+ }
+
+ /* Get this file's size */
+ FileSize = FsGetFileSize(FileHandle);
+ *Size = FileSize;
+
+ /* Allocate memory */
+ PhysicalBase = MmAllocateMemoryWithType(FileSize, MemoryType);
+ if (PhysicalBase == NULL)
+ {
+ FsCloseFile(FileHandle);
+ return NULL;
+ }
+
+ /* Load whole file */
+ Status = FsReadFile(FileHandle, FileSize, NULL, PhysicalBase);
+ if (!Status)
+ {
+ FsCloseFile(FileHandle);
+ return NULL;
+ }
+
+ DbgPrint((DPRINT_WINDOWS, "Loaded %s at 0x%x with size 0x%x\n", ModuleName, PhysicalBase, FileSize));
+
+ /* We are done with the file - close it */
+ FsCloseFile(FileHandle);
+
+ return PhysicalBase;
}
-/*\r
- * PROJECT: EFI Windows Loader\r
- * LICENSE: GPL - See COPYING in the top level directory\r
- * FILE: freeldr/winldr/wlmemory.c\r
- * PURPOSE: Memory related routines\r
- * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)\r
- */\r
-\r
-/* INCLUDES ***************************************************************/\r
-\r
-#include <freeldr.h>\r
-\r
-#include <ndk/asm.h>\r
-#include <debug.h>\r
-\r
-extern ULONG TotalNLSSize;\r
-extern ULONG LoaderPagesSpanned;\r
-\r
-// This is needed because headers define wrong one for ReactOS\r
-#undef KIP0PCRADDRESS\r
-#define KIP0PCRADDRESS 0xffdff000\r
-\r
-#define HYPER_SPACE_ENTRY 0x300\r
-\r
-PCHAR MemTypeDesc[] = {\r
- "ExceptionBlock ", // ?\r
- "SystemBlock ", // ?\r
- "Free ",\r
- "Bad ", // used\r
- "LoadedProgram ", // == Free\r
- "FirmwareTemporary ", // == Free\r
- "FirmwarePermanent ", // == Bad\r
- "OsloaderHeap ", // used\r
- "OsloaderStack ", // == Free\r
- "SystemCode ",\r
- "HalCode ",\r
- "BootDriver ", // not used\r
- "ConsoleInDriver ", // ?\r
- "ConsoleOutDriver ", // ?\r
- "StartupDpcStack ", // ?\r
- "StartupKernelStack", // ?\r
- "StartupPanicStack ", // ?\r
- "StartupPcrPage ", // ?\r
- "StartupPdrPage ", // ?\r
- "RegistryData ", // used\r
- "MemoryData ", // not used\r
- "NlsData ", // used\r
- "SpecialMemory ", // == Bad\r
- "BBTMemory " // == Bad\r
- };\r
-\r
-VOID\r
-WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);\r
-\r
-\r
-VOID\r
-MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
- ULONG BasePage,\r
- ULONG PageCount,\r
- ULONG Type);\r
-VOID\r
-WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
- IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor);\r
-\r
-VOID\r
-WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor);\r
-\r
-VOID\r
-WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss);\r
-\r
-// This is needed only for SetProcessorContext routine\r
-#pragma pack(2)\r
- typedef struct\r
- {\r
- USHORT Limit;\r
- ULONG Base;\r
- } GDTIDT;\r
-#pragma pack(4)\r
-\r
-// this is needed for new IDT filling\r
-#if 0\r
-extern ULONG_PTR i386DivideByZero;\r
-extern ULONG_PTR i386DebugException;\r
-extern ULONG_PTR i386NMIException;\r
-extern ULONG_PTR i386Breakpoint;\r
-extern ULONG_PTR i386Overflow;\r
-extern ULONG_PTR i386BoundException;\r
-extern ULONG_PTR i386InvalidOpcode;\r
-extern ULONG_PTR i386FPUNotAvailable;\r
-extern ULONG_PTR i386DoubleFault;\r
-extern ULONG_PTR i386CoprocessorSegment;\r
-extern ULONG_PTR i386InvalidTSS;\r
-extern ULONG_PTR i386SegmentNotPresent;\r
-extern ULONG_PTR i386StackException;\r
-extern ULONG_PTR i386GeneralProtectionFault;\r
-extern ULONG_PTR i386PageFault; // exc 14\r
-extern ULONG_PTR i386CoprocessorError; // exc 16\r
-extern ULONG_PTR i386AlignmentCheck; // exc 17\r
-#endif\r
-\r
-/* GLOBALS ***************************************************************/\r
-\r
-PHARDWARE_PTE PDE;\r
-PHARDWARE_PTE HalPageTable;\r
-\r
-PUCHAR PhysicalPageTablesBuffer;\r
-PUCHAR KernelPageTablesBuffer;\r
-ULONG PhysicalPageTables;\r
-ULONG KernelPageTables;\r
-\r
-MEMORY_ALLOCATION_DESCRIPTOR *Mad;\r
-ULONG MadCount = 0;\r
-\r
-\r
-/* FUNCTIONS **************************************************************/\r
-\r
-BOOLEAN\r
-MempAllocatePageTables()\r
-{\r
- ULONG NumPageTables, TotalSize;\r
- PUCHAR Buffer;\r
- // It's better to allocate PDE + PTEs contigiuos\r
-\r
- // Max number of entries = MaxPageNum >> 10\r
- // FIXME: This is a number to describe ALL physical memory\r
- // and windows doesn't expect ALL memory mapped...\r
- NumPageTables = (GetSystemMemorySize() >> MM_PAGE_SHIFT) >> 10;\r
-\r
- DbgPrint((DPRINT_WINDOWS, "NumPageTables = %d\n", NumPageTables));\r
-\r
- // Allocate memory block for all these things:\r
- // PDE, HAL mapping page table, physical mapping, kernel mapping\r
- TotalSize = (1+1+NumPageTables*2)*MM_PAGE_SIZE;\r
-\r
- // PDE+HAL+KernelPTEs == MemoryData\r
- Buffer = MmAllocateMemoryWithType(\r
- TotalSize - NumPageTables*MM_PAGE_SIZE, LoaderMemoryData);\r
-\r
- // Physical PTEs = FirmwareTemporary\r
- PhysicalPageTablesBuffer = MmAllocateMemoryWithType(\r
- NumPageTables*MM_PAGE_SIZE, LoaderFirmwareTemporary);\r
-\r
- if (Buffer + (TotalSize - NumPageTables*MM_PAGE_SIZE) !=\r
- PhysicalPageTablesBuffer)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "There was a problem allocating two adjacent blocks of memory!"));\r
- }\r
-\r
- if (Buffer == NULL || PhysicalPageTablesBuffer == NULL)\r
- {\r
- UiMessageBox("Impossible to allocate memory block for page tables!");\r
- return FALSE;\r
- }\r
-\r
- // Zero all this memory block\r
- RtlZeroMemory(Buffer, TotalSize);\r
-\r
- // Set up pointers correctly now\r
- PDE = (PHARDWARE_PTE)Buffer;\r
-\r
- // Map the page directory at 0xC0000000 (maps itself)\r
- PDE[HYPER_SPACE_ENTRY].PageFrameNumber = (ULONG)PDE >> MM_PAGE_SHIFT;\r
- PDE[HYPER_SPACE_ENTRY].Valid = 1;\r
- PDE[HYPER_SPACE_ENTRY].Write = 1;\r
-\r
- // The last PDE slot is allocated for HAL's memory mapping (Virtual Addresses 0xFFC00000 - 0xFFFFFFFF)\r
- HalPageTable = (PHARDWARE_PTE)&Buffer[MM_PAGE_SIZE*1];\r
-\r
- // Map it\r
- PDE[1023].PageFrameNumber = (ULONG)HalPageTable >> MM_PAGE_SHIFT;\r
- PDE[1023].Valid = 1;\r
- PDE[1023].Write = 1;\r
-\r
- // Store pointer to the table for easier access\r
- KernelPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2];\r
-\r
- // Zero counters of page tables used\r
- PhysicalPageTables = 0;\r
- KernelPageTables = 0;\r
-\r
- return TRUE;\r
-}\r
-\r
-VOID\r
-MempAllocatePTE(ULONG Entry, PHARDWARE_PTE *PhysicalPT, PHARDWARE_PTE *KernelPT)\r
-{\r
- //Print(L"Creating PDE Entry %X\n", Entry);\r
-\r
- // Identity mapping\r
- *PhysicalPT = (PHARDWARE_PTE)&PhysicalPageTablesBuffer[PhysicalPageTables*MM_PAGE_SIZE];\r
- PhysicalPageTables++;\r
-\r
- PDE[Entry].PageFrameNumber = (ULONG)*PhysicalPT >> MM_PAGE_SHIFT;\r
- PDE[Entry].Valid = 1;\r
- PDE[Entry].Write = 1;\r
-\r
- if (Entry+(KSEG0_BASE >> 22) > 1023)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "WARNING! Entry: %X > 1023\n", Entry+(KSEG0_BASE >> 22)));\r
- }\r
-\r
- // Kernel-mode mapping\r
- *KernelPT = (PHARDWARE_PTE)&KernelPageTablesBuffer[KernelPageTables*MM_PAGE_SIZE];\r
- KernelPageTables++;\r
-\r
- PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber = ((ULONG)*KernelPT >> MM_PAGE_SHIFT);\r
- PDE[Entry+(KSEG0_BASE >> 22)].Valid = 1;\r
- PDE[Entry+(KSEG0_BASE >> 22)].Write = 1;\r
-}\r
-\r
-BOOLEAN\r
-MempSetupPaging(IN ULONG StartPage,\r
- IN ULONG NumberOfPages)\r
-{\r
- PHARDWARE_PTE PhysicalPT;\r
- PHARDWARE_PTE KernelPT;\r
- ULONG Entry, Page;\r
-\r
- //Print(L"MempSetupPaging: SP 0x%X, Number: 0x%X\n", StartPage, NumberOfPages);\r
- \r
- // HACK\r
- if (StartPage+NumberOfPages >= 0x80000)\r
- {\r
- //\r
- // We can't map this as it requires more than 1 PDE\r
- // and in fact it's not possible at all ;)\r
- //\r
- //Print(L"skipping...\n");\r
- return TRUE;\r
- }\r
-\r
- //\r
- // Now actually set up the page tables for identity mapping\r
- //\r
- for (Page=StartPage; Page < StartPage+NumberOfPages; Page++)\r
- {\r
- Entry = Page >> 10;\r
-\r
- if (((PULONG)PDE)[Entry] == 0)\r
- {\r
- MempAllocatePTE(Entry, &PhysicalPT, &KernelPT);\r
- }\r
- else\r
- {\r
- PhysicalPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);\r
- KernelPT = (PHARDWARE_PTE)(PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber << MM_PAGE_SHIFT);\r
- }\r
-\r
- if (Page == 0)\r
- {\r
- PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;\r
- PhysicalPT[Page & 0x3ff].Valid = 0;\r
- PhysicalPT[Page & 0x3ff].Write = 0;\r
-\r
- KernelPT[Page & 0x3ff].PageFrameNumber = Page;\r
- KernelPT[Page & 0x3ff].Valid = 0;\r
- KernelPT[Page & 0x3ff].Write = 0;\r
- }\r
- else\r
- {\r
- PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;\r
- PhysicalPT[Page & 0x3ff].Valid = 1;\r
- PhysicalPT[Page & 0x3ff].Write = 1;\r
-\r
- KernelPT[Page & 0x3ff].PageFrameNumber = Page;\r
- KernelPT[Page & 0x3ff].Valid = 1;\r
- KernelPT[Page & 0x3ff].Write = 1;\r
- }\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-VOID\r
-MempDisablePages()\r
-{\r
- int i;\r
-\r
- //\r
- // We need to delete kernel mapping from memory areas which are\r
- // marked as Special or Permanent memory (thus non-accessible)\r
- //\r
-\r
- for (i=0; i<MadCount; i++)\r
- {\r
- ULONG StartPage, EndPage, Page;\r
-\r
- StartPage = Mad[i].BasePage;\r
- EndPage = Mad[i].BasePage + Mad[i].PageCount;\r
-\r
- if (Mad[i].MemoryType == LoaderFirmwarePermanent ||\r
- Mad[i].MemoryType == LoaderSpecialMemory ||\r
- Mad[i].MemoryType == LoaderFree ||\r
- (Mad[i].MemoryType == LoaderFirmwareTemporary && EndPage <= LoaderPagesSpanned) ||\r
- Mad[i].MemoryType == LoaderOsloaderStack ||\r
- Mad[i].MemoryType == LoaderLoadedProgram)\r
- {\r
- //\r
- // But, the first megabyte of memory always stays!\r
- // And, to tell the truth, we don't care about what's higher\r
- // than LoaderPagesSpanned\r
- if (Mad[i].MemoryType == LoaderFirmwarePermanent ||\r
- Mad[i].MemoryType == LoaderSpecialMemory)\r
- {\r
- if (StartPage < 0x100)\r
- StartPage = 0x100;\r
-\r
- if (EndPage > LoaderPagesSpanned)\r
- EndPage = LoaderPagesSpanned;\r
- }\r
-\r
- for (Page = StartPage; Page < EndPage; Page++)\r
- {\r
- PHARDWARE_PTE KernelPT;\r
- ULONG Entry = (Page >> 10) + (KSEG0_BASE >> 22);\r
-\r
- if (PDE[Entry].Valid)\r
- {\r
- KernelPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);\r
-\r
- if (KernelPT)\r
- {\r
- KernelPT[Page & 0x3ff].PageFrameNumber = 0;\r
- KernelPT[Page & 0x3ff].Valid = 0;\r
- KernelPT[Page & 0x3ff].Write = 0;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-VOID\r
-MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
- ULONG BasePage,\r
- ULONG PageCount,\r
- ULONG Type)\r
-{\r
- BOOLEAN Status;\r
-\r
- //\r
- // Check for some weird stuff at the top\r
- //\r
- if (BasePage + PageCount > 0xF0000)\r
- {\r
- //\r
- // Just skip this, without even adding to MAD list\r
- //\r
- return;\r
- }\r
-\r
- //\r
- // Set Base page, page count and type\r
- //\r
- Mad[MadCount].BasePage = BasePage;\r
- Mad[MadCount].PageCount = PageCount;\r
- Mad[MadCount].MemoryType = Type;\r
-\r
- //\r
- // Check if it's more than the allowed for OS loader\r
- // if yes - don't map the pages, just add as FirmwareTemporary\r
- //\r
- if (BasePage + PageCount > LoaderPagesSpanned)\r
- {\r
- if (Mad[MadCount].MemoryType != LoaderSpecialMemory &&\r
- Mad[MadCount].MemoryType != LoaderFirmwarePermanent &&\r
- Mad[MadCount].MemoryType != LoaderFree)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "Setting page %x %x to Temporary from %d\n",\r
- BasePage, PageCount, Mad[MadCount].MemoryType));\r
- Mad[MadCount].MemoryType = LoaderFirmwareTemporary;\r
- }\r
-\r
- WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
- MadCount++;\r
-\r
- return;\r
- }\r
- \r
- //\r
- // Add descriptor\r
- //\r
- WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
- MadCount++;\r
-\r
- //\r
- // Map it (don't map low 1Mb because it was already contigiously\r
- // mapped in WinLdrTurnOnPaging)\r
- //\r
- if (BasePage >= 0x100)\r
- {\r
- Status = MempSetupPaging(BasePage, PageCount);\r
- if (!Status)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging\n"));\r
- return;\r
- }\r
- }\r
-}\r
-\r
-#ifdef _M_IX86\r
-\r
-BOOLEAN LocalAPIC = FALSE;\r
-ULONG_PTR APICAddress = 0;\r
-\r
-VOID\r
-WinLdrpMapApic()\r
-{\r
- /* Check if we have a local APIC */\r
- asm(".intel_syntax noprefix\n");\r
- asm("mov eax, 1\n");\r
- asm("cpuid\n");\r
- asm("shr edx, 9\n");\r
- asm("and edx, 0x1\n");\r
- asm("mov _LocalAPIC, edx\n");\r
- asm(".att_syntax\n");\r
-\r
- /* If there is no APIC, just return */\r
- if (!LocalAPIC)\r
- return;\r
-\r
- asm(".intel_syntax noprefix\n");\r
- asm("mov ecx, 0x1B\n");\r
- asm("rdmsr\n");\r
- asm("mov edx, eax\n");\r
- asm("and edx, 0xFFFFF000\n");\r
- asm("mov _APICAddress, edx");\r
- asm(".att_syntax\n");\r
-\r
- DbgPrint((DPRINT_WINDOWS, "Local APIC detected at address 0x%x\n",\r
- APICAddress));\r
-\r
- /* Map it */\r
- HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber\r
- = APICAddress >> MM_PAGE_SHIFT;\r
- HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;\r
- HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;\r
- HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].WriteThrough = 1;\r
- HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].CacheDisable = 1;\r
-}\r
-#else\r
-VOID\r
-WinLdrpMapApic()\r
-{\r
- /* Implement it for another arch */\r
-}\r
-#endif\r
-\r
-BOOLEAN\r
-WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
- ULONG PcrBasePage,\r
- ULONG TssBasePage,\r
- PVOID GdtIdt)\r
-{\r
- ULONG i, PagesCount, MemoryMapSizeInPages;\r
- ULONG LastPageIndex, LastPageType, MemoryMapStartPage;\r
- PPAGE_LOOKUP_TABLE_ITEM MemoryMap;\r
- ULONG NoEntries;\r
- PKTSS Tss;\r
- BOOLEAN Status;\r
-\r
- //\r
- // Creating a suitable memory map for the Windows can be tricky, so let's\r
- // give a few advices:\r
- // 1) One must not map the whole available memory pages to PDE!\r
- // Map only what's needed - 16Mb, 24Mb, 32Mb max I think,\r
- // thus occupying 4, 6 or 8 PDE entries for identical mapping,\r
- // the same quantity for KSEG0_BASE mapping, one more entry for\r
- // hyperspace and one more entry for HAL physical pages mapping.\r
- // 2) Memory descriptors must map *the whole* physical memory\r
- // showing any memory above 16/24/32 as FirmwareTemporary\r
- //\r
- // 3) Overall memory blocks count must not exceed 30 (?? why?)\r
- //\r
-\r
- //\r
- // During MmInitMachineDependent, the kernel zeroes PDE at the following address\r
- // 0xC0300000 - 0xC03007FC\r
- //\r
- // Then it finds the best place for non-paged pool:\r
- // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD\r
- //\r
-\r
- // Before we start mapping pages, create a block of memory, which will contain\r
- // PDE and PTEs\r
- if (MempAllocatePageTables() == FALSE)\r
- return FALSE;\r
-\r
- // Allocate memory for memory allocation descriptors\r
- Mad = MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR) * 1024);\r
-\r
- // Setup an entry for each descriptor\r
- MemoryMap = MmGetMemoryMap(&NoEntries);\r
- if (MemoryMap == NULL)\r
- {\r
- UiMessageBox("Can not retrieve the current memory map");\r
- return FALSE;\r
- }\r
-\r
- // Calculate parameters of the memory map\r
- MemoryMapStartPage = (ULONG_PTR)MemoryMap >> MM_PAGE_SHIFT;\r
- MemoryMapSizeInPages = NoEntries * sizeof(PAGE_LOOKUP_TABLE_ITEM);\r
-\r
- DbgPrint((DPRINT_WINDOWS, "Got memory map with %d entries\n", NoEntries));\r
-\r
- // Always contigiously map low 1Mb of memory\r
- Status = MempSetupPaging(0, 0x100);\r
- if (!Status)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging of low 1Mb\n"));\r
- return FALSE;\r
- }\r
-\r
- // Construct a good memory map from what we've got,\r
- // but mark entries which the memory allocation bitmap takes\r
- // as free entries (this is done in order to have the ability\r
- // to place mem alloc bitmap outside lower 16Mb zone)\r
- PagesCount = 1;\r
- LastPageIndex = 0;\r
- LastPageType = MemoryMap[0].PageAllocated;\r
- for(i=1;i<NoEntries;i++)\r
- {\r
- // Check if its memory map itself\r
- if (i >= MemoryMapStartPage &&\r
- i < (MemoryMapStartPage+MemoryMapSizeInPages))\r
- {\r
- // Exclude it if current page belongs to the memory map\r
- MemoryMap[i].PageAllocated = LoaderFree;\r
- }\r
-\r
- // Process entry\r
- if (MemoryMap[i].PageAllocated == LastPageType &&\r
- (i != NoEntries-1) )\r
- {\r
- PagesCount++;\r
- }\r
- else\r
- {\r
- // Add the resulting region\r
- MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, LastPageType);\r
-\r
- // Reset our counter vars\r
- LastPageIndex = i;\r
- LastPageType = MemoryMap[i].PageAllocated;\r
- PagesCount = 1;\r
- }\r
- }\r
-\r
- // TEMP, DEBUG!\r
- // adding special reserved memory zones for vmware workstation\r
-#if 0\r
- {\r
- Mad[MadCount].BasePage = 0xfec00;\r
- Mad[MadCount].PageCount = 0x10;\r
- Mad[MadCount].MemoryType = LoaderSpecialMemory;\r
- WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
- MadCount++;\r
-\r
- Mad[MadCount].BasePage = 0xfee00;\r
- Mad[MadCount].PageCount = 0x1;\r
- Mad[MadCount].MemoryType = LoaderSpecialMemory;\r
- WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
- MadCount++;\r
-\r
- Mad[MadCount].BasePage = 0xfffe0;\r
- Mad[MadCount].PageCount = 0x20;\r
- Mad[MadCount].MemoryType = LoaderSpecialMemory;\r
- WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);\r
- MadCount++;\r
- }\r
-#endif\r
-\r
- DbgPrint((DPRINT_WINDOWS, "MadCount: %d\n", MadCount));\r
-\r
- WinLdrpDumpMemoryDescriptors(LoaderBlock); //FIXME: Delete!\r
-\r
- // Map our loader image, so we can continue running\r
- /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);\r
- if (!Status)\r
- {\r
- UiMessageBox("Error during MempSetupPaging");\r
- return;\r
- }*/\r
-\r
- //VideoDisplayString(L"Hello from VGA, going into the kernel\n");\r
- DbgPrint((DPRINT_WINDOWS, "HalPageTable: 0x%X\n", HalPageTable));\r
-\r
- // Page Tables have been setup, make special handling for PCR and TSS\r
- // (which is done in BlSetupFotNt in usual ntldr)\r
- HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1;\r
- HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;\r
- HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;\r
-\r
- HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage;\r
- HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;\r
- HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;\r
-\r
- // Map APIC\r
- WinLdrpMapApic();\r
-\r
- // Map VGA memory\r
- //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);\r
- //DbgPrint((DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase));\r
-\r
- Tss = (PKTSS)(KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));\r
-\r
- // Unmap what is not needed from kernel page table\r
- MempDisablePages();\r
-\r
- // Fill the memory descriptor list and \r
- //PrepareMemoryDescriptorList();\r
- DbgPrint((DPRINT_WINDOWS, "Memory Descriptor List prepared, printing PDE\n"));\r
- List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);\r
-\r
-#ifdef DBG\r
- {\r
- ULONG *PDE_Addr=(ULONG *)PDE;//0xC0300000;\r
- int j;\r
-\r
- DbgPrint((DPRINT_WINDOWS, "\nPDE\n"));\r
-\r
- for (i=0; i<128; i++)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "0x%04X | ", i*8));\r
-\r
- for (j=0; j<8; j++)\r
- {\r
- DbgPrint((DPRINT_WINDOWS, "0x%08X ", PDE_Addr[i*8+j]));\r
- }\r
-\r
- DbgPrint((DPRINT_WINDOWS, "\n"));\r
- }\r
- }\r
-#endif\r
-\r
-\r
- // Enable paging\r
- //BS->ExitBootServices(ImageHandle,MapKey);\r
-\r
- // Disable Interrupts\r
- _disable();\r
-\r
- // Re-initalize EFLAGS\r
- Ke386EraseFlags();\r
-\r
- // Set the PDBR\r
- __writecr3((ULONG_PTR)PDE);\r
-\r
- // Enable paging by modifying CR0\r
- __writecr0(__readcr0() | CR0_PG);\r
-\r
- // Set processor context\r
- WinLdrSetProcessorContext(GdtIdt, KIP0PCRADDRESS, KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));\r
-\r
- // Zero KI_USER_SHARED_DATA page\r
- memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE);\r
-\r
- return TRUE;\r
-}\r
-\r
-// Two special things this func does: it sorts descriptors,\r
-// and it merges free ones\r
-VOID\r
-WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,\r
- IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)\r
-{\r
- PLIST_ENTRY ListHead = &LoaderBlock->MemoryDescriptorListHead;\r
- PLIST_ENTRY PreviousEntry, NextEntry;\r
- PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor = NULL, NextDescriptor = NULL;\r
-\r
- DbgPrint((DPRINT_WINDOWS, "BP=0x%X PC=0x%X %s\n", NewDescriptor->BasePage,\r
- NewDescriptor->PageCount, MemTypeDesc[NewDescriptor->MemoryType]));\r
-\r
- /* Find a place where to insert the new descriptor to */\r
- PreviousEntry = ListHead;\r
- NextEntry = ListHead->Flink;\r
- while (NextEntry != ListHead)\r
- {\r
- NextDescriptor = CONTAINING_RECORD(NextEntry,\r
- MEMORY_ALLOCATION_DESCRIPTOR,\r
- ListEntry);\r
- if (NewDescriptor->BasePage < NextDescriptor->BasePage)\r
- break;\r
-\r
- PreviousEntry = NextEntry;\r
- PreviousDescriptor = NextDescriptor;\r
- NextEntry = NextEntry->Flink;\r
- }\r
-\r
- /* Don't forget about merging free areas */\r
- if (NewDescriptor->MemoryType != LoaderFree)\r
- {\r
- /* Just insert, nothing to merge */\r
- InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);\r
- }\r
- else\r
- {\r
- /* Previous block also free? */\r
- if ((PreviousEntry != ListHead) && (PreviousDescriptor->MemoryType == LoaderFree) &&\r
- ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==\r
- NewDescriptor->BasePage))\r
- {\r
- /* Just enlarge previous descriptor's PageCount */\r
- PreviousDescriptor->PageCount += NewDescriptor->PageCount;\r
- NewDescriptor = PreviousDescriptor;\r
- }\r
- else\r
- {\r
- /* Nope, just insert */\r
- InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);\r
- }\r
-\r
- /* Next block is free ?*/\r
- if ((NextEntry != ListHead) &&\r
- (NextDescriptor->MemoryType == LoaderFree) &&\r
- ((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage))\r
- {\r
- /* Enlarge next descriptor's PageCount */\r
- NewDescriptor->PageCount += NextDescriptor->PageCount;\r
- RemoveEntryList(&NextDescriptor->ListEntry);\r
- }\r
- }\r
-\r
- return;\r
-}\r
-\r
-VOID\r
-WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss)\r
-{\r
- GDTIDT GdtDesc, IdtDesc, OldIdt;\r
- PKGDTENTRY pGdt;\r
- PKIDTENTRY pIdt;\r
- ULONG Ldt = 0;\r
- //ULONG i;\r
-\r
- DbgPrint((DPRINT_WINDOWS, "GDtIdt %p, Pcr %p, Tss 0x%08X\n",\r
- GdtIdt, Pcr, Tss));\r
-\r
- // Kernel expects the PCR to be zero-filled on startup\r
- // FIXME: Why zero it here when we can zero it right after allocation?\r
- RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE); //FIXME: Why zero only 1 page when we allocate 2?\r
-\r
- // Get old values of GDT and IDT\r
- Ke386GetGlobalDescriptorTable(GdtDesc);\r
- Ke386GetInterruptDescriptorTable(IdtDesc);\r
-\r
- // Save old IDT\r
- OldIdt.Base = IdtDesc.Base;\r
- OldIdt.Limit = IdtDesc.Limit;\r
-\r
- // Prepare new IDT+GDT\r
- GdtDesc.Base = KSEG0_BASE | (ULONG_PTR)GdtIdt;\r
- GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1;\r
- IdtDesc.Base = (ULONG)((PUCHAR)GdtDesc.Base + GdtDesc.Limit + 1);\r
- IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1;\r
-\r
- // ========================\r
- // Fill all descriptors now\r
- // ========================\r
-\r
- pGdt = (PKGDTENTRY)GdtDesc.Base;\r
- pIdt = (PKIDTENTRY)IdtDesc.Base;\r
-\r
- //\r
- // Code selector (0x8)\r
- // Flat 4Gb\r
- //\r
- pGdt[1].LimitLow = 0xFFFF;\r
- pGdt[1].BaseLow = 0;\r
- pGdt[1].HighWord.Bytes.BaseMid = 0;\r
- pGdt[1].HighWord.Bytes.Flags1 = 0x9A;\r
- pGdt[1].HighWord.Bytes.Flags2 = 0xCF;\r
- pGdt[1].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // Data selector (0x10)\r
- // Flat 4Gb\r
- //\r
- pGdt[2].LimitLow = 0xFFFF;\r
- pGdt[2].BaseLow = 0;\r
- pGdt[2].HighWord.Bytes.BaseMid = 0;\r
- pGdt[2].HighWord.Bytes.Flags1 = 0x92;\r
- pGdt[2].HighWord.Bytes.Flags2 = 0xCF;\r
- pGdt[2].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // Selector (0x18)\r
- // Flat 2Gb\r
- //\r
- pGdt[3].LimitLow = 0xFFFF;\r
- pGdt[3].BaseLow = 0;\r
- pGdt[3].HighWord.Bytes.BaseMid = 0;\r
- pGdt[3].HighWord.Bytes.Flags1 = 0xFA;\r
- pGdt[3].HighWord.Bytes.Flags2 = 0xCF;\r
- pGdt[3].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // Selector (0x20)\r
- // Flat 2Gb\r
- //\r
- pGdt[4].LimitLow = 0xFFFF;\r
- pGdt[4].BaseLow = 0;\r
- pGdt[4].HighWord.Bytes.BaseMid = 0;\r
- pGdt[4].HighWord.Bytes.Flags1 = 0xF2;\r
- pGdt[4].HighWord.Bytes.Flags2 = 0xCF;\r
- pGdt[4].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // TSS Selector (0x28)\r
- //\r
- pGdt[5].LimitLow = 0x78-1; //FIXME: Check this\r
- pGdt[5].BaseLow = (USHORT)(Tss & 0xffff);\r
- pGdt[5].HighWord.Bytes.BaseMid = (UCHAR)((Tss >> 16) & 0xff);\r
- pGdt[5].HighWord.Bytes.Flags1 = 0x89;\r
- pGdt[5].HighWord.Bytes.Flags2 = 0x00;\r
- pGdt[5].HighWord.Bytes.BaseHi = (UCHAR)((Tss >> 24) & 0xff);\r
-\r
- //\r
- // PCR Selector (0x30)\r
- //\r
- pGdt[6].LimitLow = 0x01;\r
- pGdt[6].BaseLow = (USHORT)(Pcr & 0xffff);\r
- pGdt[6].HighWord.Bytes.BaseMid = (UCHAR)((Pcr >> 16) & 0xff);\r
- pGdt[6].HighWord.Bytes.Flags1 = 0x92;\r
- pGdt[6].HighWord.Bytes.Flags2 = 0xC0;\r
- pGdt[6].HighWord.Bytes.BaseHi = (UCHAR)((Pcr >> 24) & 0xff);\r
-\r
- //\r
- // Selector (0x38)\r
- //\r
- pGdt[7].LimitLow = 0xFFFF;\r
- pGdt[7].BaseLow = 0;\r
- pGdt[7].HighWord.Bytes.BaseMid = 0;\r
- pGdt[7].HighWord.Bytes.Flags1 = 0xF3;\r
- pGdt[7].HighWord.Bytes.Flags2 = 0x40;\r
- pGdt[7].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // Some BIOS stuff (0x40)\r
- //\r
- pGdt[8].LimitLow = 0xFFFF;\r
- pGdt[8].BaseLow = 0x400;\r
- pGdt[8].HighWord.Bytes.BaseMid = 0;\r
- pGdt[8].HighWord.Bytes.Flags1 = 0xF2;\r
- pGdt[8].HighWord.Bytes.Flags2 = 0x0;\r
- pGdt[8].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // Selector (0x48)\r
- //\r
- pGdt[9].LimitLow = 0;\r
- pGdt[9].BaseLow = 0;\r
- pGdt[9].HighWord.Bytes.BaseMid = 0;\r
- pGdt[9].HighWord.Bytes.Flags1 = 0;\r
- pGdt[9].HighWord.Bytes.Flags2 = 0;\r
- pGdt[9].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // Selector (0x50)\r
- //\r
- pGdt[10].LimitLow = 0xFFFF; //FIXME: Not correct!\r
- pGdt[10].BaseLow = 0;\r
- pGdt[10].HighWord.Bytes.BaseMid = 0x2;\r
- pGdt[10].HighWord.Bytes.Flags1 = 0x89;\r
- pGdt[10].HighWord.Bytes.Flags2 = 0;\r
- pGdt[10].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // Selector (0x58)\r
- //\r
- pGdt[11].LimitLow = 0xFFFF;\r
- pGdt[11].BaseLow = 0;\r
- pGdt[11].HighWord.Bytes.BaseMid = 0x2;\r
- pGdt[11].HighWord.Bytes.Flags1 = 0x9A;\r
- pGdt[11].HighWord.Bytes.Flags2 = 0;\r
- pGdt[11].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // Selector (0x60)\r
- //\r
- pGdt[12].LimitLow = 0xFFFF;\r
- pGdt[12].BaseLow = 0; //FIXME: Maybe not correct, but noone cares\r
- pGdt[12].HighWord.Bytes.BaseMid = 0x2;\r
- pGdt[12].HighWord.Bytes.Flags1 = 0x92;\r
- pGdt[12].HighWord.Bytes.Flags2 = 0;\r
- pGdt[12].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // Video buffer Selector (0x68)\r
- //\r
- pGdt[13].LimitLow = 0x3FFF;\r
- pGdt[13].BaseLow = 0x8000;\r
- pGdt[13].HighWord.Bytes.BaseMid = 0x0B;\r
- pGdt[13].HighWord.Bytes.Flags1 = 0x92;\r
- pGdt[13].HighWord.Bytes.Flags2 = 0;\r
- pGdt[13].HighWord.Bytes.BaseHi = 0;\r
-\r
- //\r
- // Points to GDT (0x70)\r
- //\r
- pGdt[14].LimitLow = NUM_GDT*sizeof(KGDTENTRY) - 1;\r
- pGdt[14].BaseLow = 0x7000;\r
- pGdt[14].HighWord.Bytes.BaseMid = 0xFF;\r
- pGdt[14].HighWord.Bytes.Flags1 = 0x92;\r
- pGdt[14].HighWord.Bytes.Flags2 = 0;\r
- pGdt[14].HighWord.Bytes.BaseHi = 0xFF;\r
-\r
- //\r
- // Some unused descriptors should go here\r
- //\r
-\r
- // Copy the old IDT\r
- RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit);\r
-\r
- // Mask interrupts\r
- //asm("cli\n"); // they are already masked before enabling paged mode\r
-\r
- // Load GDT+IDT\r
- Ke386SetGlobalDescriptorTable(GdtDesc);\r
- Ke386SetInterruptDescriptorTable(IdtDesc);\r
-\r
- // Jump to proper CS and clear prefetch queue\r
- asm("ljmp $0x08, $mb1\n"\r
- "mb1:\n");\r
-\r
- // Set SS selector\r
- asm(".intel_syntax noprefix\n");\r
- asm("mov ax, 0x10\n"); // DataSelector=0x10\r
- asm("mov ss, ax\n");\r
- asm(".att_syntax\n");\r
-\r
- // Set DS and ES selectors\r
- Ke386SetDs(0x10);\r
- Ke386SetEs(0x10); // this is vital for rep stosd\r
-\r
- // LDT = not used ever, thus set to 0\r
- Ke386SetLocalDescriptorTable(Ldt);\r
-\r
- // Load TSR\r
- Ke386SetTr(0x28);\r
-\r
- // Clear GS\r
- asm(".intel_syntax noprefix\n");\r
- asm("push 0\n");\r
- asm("pop gs\n");\r
- asm(".att_syntax\n");\r
-\r
- // Set FS to PCR\r
- Ke386SetFs(0x30);\r
-\r
- // Real end of the function, just for information\r
- /* do not uncomment!\r
- pop edi;\r
- pop esi;\r
- pop ebx;\r
- mov esp, ebp;\r
- pop ebp;\r
- ret\r
- */\r
-}\r
+/*
+ * 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 <freeldr.h>
+
+#include <ndk/asm.h>
+#include <debug.h>
+
+extern ULONG TotalNLSSize;
+extern ULONG LoaderPagesSpanned;
+
+// 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 HalPageTable;
+
+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
+ TotalSize = (1+1+NumPageTables*2)*MM_PAGE_SIZE;
+
+ // PDE+HAL+KernelPTEs == MemoryData
+ Buffer = MmAllocateMemoryWithType(
+ TotalSize - NumPageTables*MM_PAGE_SIZE, LoaderMemoryData);
+
+ // Physical PTEs = FirmwareTemporary
+ PhysicalPageTablesBuffer = MmAllocateMemoryWithType(
+ NumPageTables*MM_PAGE_SIZE, LoaderFirmwareTemporary);
+
+ if (Buffer + (TotalSize - NumPageTables*MM_PAGE_SIZE) !=
+ PhysicalPageTablesBuffer)
+ {
+ DbgPrint((DPRINT_WINDOWS, "There was a problem allocating two adjacent blocks of memory!"));
+ }
+
+ if (Buffer == NULL || PhysicalPageTablesBuffer == 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)
+ HalPageTable = (PHARDWARE_PTE)&Buffer[MM_PAGE_SIZE*1];
+
+ // Map it
+ PDE[1023].PageFrameNumber = (ULONG)HalPageTable >> MM_PAGE_SHIFT;
+ PDE[1023].Valid = 1;
+ PDE[1023].Write = 1;
+
+ // Store pointer to the table for easier access
+ KernelPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2];
+
+ // 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<MadCount; i++)
+ {
+ ULONG StartPage, EndPage, Page;
+
+ StartPage = Mad[i].BasePage;
+ EndPage = Mad[i].BasePage + Mad[i].PageCount;
+
+ if (Mad[i].MemoryType == LoaderFirmwarePermanent ||
+ Mad[i].MemoryType == LoaderSpecialMemory ||
+ Mad[i].MemoryType == LoaderFree ||
+ (Mad[i].MemoryType == LoaderFirmwareTemporary && EndPage <= LoaderPagesSpanned) ||
+ Mad[i].MemoryType == LoaderOsloaderStack ||
+ Mad[i].MemoryType == LoaderLoadedProgram)
+ {
+ //
+ // But, the first megabyte of memory always stays!
+ // And, to tell the truth, we don't care about what's higher
+ // than LoaderPagesSpanned
+ if (Mad[i].MemoryType == LoaderFirmwarePermanent ||
+ Mad[i].MemoryType == LoaderSpecialMemory)
+ {
+ if (StartPage < 0x100)
+ StartPage = 0x100;
+
+ if (EndPage > LoaderPagesSpanned)
+ EndPage = LoaderPagesSpanned;
+ }
+
+ 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 > LoaderPagesSpanned)
+ {
+ if (Mad[MadCount].MemoryType != LoaderSpecialMemory &&
+ Mad[MadCount].MemoryType != LoaderFirmwarePermanent &&
+ Mad[MadCount].MemoryType != LoaderFree)
+ {
+ DbgPrint((DPRINT_WINDOWS, "Setting page %x %x to Temporary from %d\n",
+ BasePage, PageCount, Mad[MadCount].MemoryType));
+ 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;
+ }
+ }
+}
+
+#ifdef _M_IX86
+
+BOOLEAN LocalAPIC = FALSE;
+ULONG_PTR APICAddress = 0;
+
+VOID
+WinLdrpMapApic()
+{
+ /* Check if we have a local APIC */
+ asm(".intel_syntax noprefix\n");
+ asm("mov eax, 1\n");
+ asm("cpuid\n");
+ asm("shr edx, 9\n");
+ asm("and edx, 0x1\n");
+ asm("mov _LocalAPIC, edx\n");
+ asm(".att_syntax\n");
+
+ /* If there is no APIC, just return */
+ if (!LocalAPIC)
+ return;
+
+ asm(".intel_syntax noprefix\n");
+ asm("mov ecx, 0x1B\n");
+ asm("rdmsr\n");
+ asm("mov edx, eax\n");
+ asm("and edx, 0xFFFFF000\n");
+ asm("mov _APICAddress, edx");
+ asm(".att_syntax\n");
+
+ DbgPrint((DPRINT_WINDOWS, "Local APIC detected at address 0x%x\n",
+ APICAddress));
+
+ /* Map it */
+ HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber
+ = APICAddress >> MM_PAGE_SHIFT;
+ HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
+ HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
+ HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].WriteThrough = 1;
+ HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].CacheDisable = 1;
+}
+#else
+VOID
+WinLdrpMapApic()
+{
+ /* Implement it for another arch */
+}
+#endif
+
+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 (?? why?)
+ //
+
+ //
+ // 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<NoEntries;i++)
+ {
+ // Check if its memory map itself
+ if (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, "HalPageTable: 0x%X\n", HalPageTable));
+
+ // Page Tables have been setup, make special handling for PCR and TSS
+ // (which is done in BlSetupFotNt in usual ntldr)
+ HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1;
+ HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
+ HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
+
+ HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage;
+ HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
+ HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
+
+ // Map APIC
+ WinLdrpMapApic();
+
+ // 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 stuff (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;
+ 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
+ */
+}