diff --git a/boot/freeldr/freeldr/disk/scsiport.c b/boot/freeldr/freeldr/disk/scsiport.c index 633facc496ccc..4469e0dd5536c 100644 --- a/boot/freeldr/freeldr/disk/scsiport.c +++ b/boot/freeldr/freeldr/disk/scsiport.c @@ -1629,20 +1629,14 @@ ScsiPortWriteRegisterUshort( WRITE_REGISTER_USHORT(Register, Value); } -extern char __ImageBase; - -ULONG +ARC_STATUS LoadBootDeviceDriver(VOID) { - PIMAGE_NT_HEADERS NtHeaders; - LIST_ENTRY ModuleListHead; - PIMAGE_IMPORT_DESCRIPTOR ImportTable; - ULONG ImportTableSize; - PLDR_DATA_TABLE_ENTRY BootDdDTE, FreeldrDTE; - CHAR NtBootDdPath[MAX_PATH]; - PVOID ImageBase = NULL; - ULONG (NTAPI *EntryPoint)(IN PVOID DriverObject, IN PVOID RegistryPath); + ARC_STATUS Status; BOOLEAN Success; + PLDR_DATA_TABLE_ENTRY BootDdDTE, ScsiPortDTE; + ULONG (NTAPI *EntryPoint)(IN PVOID DriverObject, IN PVOID RegistryPath); + CHAR NtBootDdPath[MAX_PATH]; // FIXME: Must be done *INSIDE* the HAL! #ifdef _M_IX86 @@ -1650,88 +1644,58 @@ LoadBootDeviceDriver(VOID) HalpInitBusHandler(); #endif - /* Initialize the loaded module list */ - InitializeListHead(&ModuleListHead); - /* Create full ntbootdd.sys path */ strcpy(NtBootDdPath, FrLdrBootPath); strcat(NtBootDdPath, "\\NTBOOTDD.SYS"); - /* Load file */ - Success = PeLdrLoadImage(NtBootDdPath, LoaderBootDriver, &ImageBase); - if (!Success) + if (!FreeldrDTE) { - /* That's OK, file simply doesn't exist */ - return ESUCCESS; + /* Hack to get FreeLdr PE image support initialized */ + PLDR_DATA_TABLE_ENTRY DummyDTE; + Status = FldrpLoadImage("", NULL, LoaderBootDriver, &DummyDTE, NULL); + ASSERT(Status != ESUCCESS); // Function call must fail. } - - /* Allocate a DTE for ntbootdd */ - Success = PeLdrAllocateDataTableEntry(&ModuleListHead, "ntbootdd.sys", - "NTBOOTDD.SYS", ImageBase, &BootDdDTE); - if (!Success) + if (!FreeldrDTE) { - /* Cleanup and bail out */ - MmFreeMemory(ImageBase); - return EIO; + /* FreeLdr PE image support could not be initialized, bail out */ + return ENOEXEC; } - /* Add the PE part of freeldr.sys to the list of loaded executables, it - contains ScsiPort* exports, imported by ntbootdd.sys */ - Success = PeLdrAllocateDataTableEntry(&ModuleListHead, "scsiport.sys", - "FREELDR.SYS", &__ImageBase, &FreeldrDTE); + /* + * Add freeldr.sys to the list of loaded executables, + * it contains ScsiPort* exports, imported by ntbootdd.sys. + */ + Success = PeLdrAllocateDataTableEntry(&FrLdrModuleList, + "scsiport.sys", + "FREELDR.SYS", + VaToPa(FreeldrDTE->DllBase), + &ScsiPortDTE); if (!Success) - { - /* Cleanup and bail out */ - PeLdrFreeDataTableEntry(BootDdDTE); - MmFreeMemory(ImageBase); return EIO; - } - /* Fix imports */ - Success = PeLdrScanImportDescriptorTable(&ModuleListHead, "", BootDdDTE); - if (!Success) + /* Load the image */ + Status = FldrpLoadImage(NtBootDdPath, + "ntbootdd.sys", // and FullDllName "NTBOOTDD.SYS", + LoaderBootDriver, + &BootDdDTE, + NULL /*&ImageBase*/); + if (Status != ESUCCESS) { - /* Cleanup and bail out */ - PeLdrFreeDataTableEntry(FreeldrDTE); - PeLdrFreeDataTableEntry(BootDdDTE); - MmFreeMemory(ImageBase); - return EIO; + /* That's OK, file simply doesn't exist. Cleanup and bail out. */ + PeLdrFreeDataTableEntry(ScsiPortDTE); + return ESUCCESS; } +#if 0 /* Now unlink the DTEs, they won't be valid later */ + RemoveEntryList(&ScsiPortDTE->InLoadOrderLinks); RemoveEntryList(&BootDdDTE->InLoadOrderLinks); - RemoveEntryList(&FreeldrDTE->InLoadOrderLinks); - - /* Change imports to PA */ - ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(BootDdDTE->DllBase), - TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize); - for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++) - { - PIMAGE_THUNK_DATA ThunkData = (PIMAGE_THUNK_DATA)VaToPa(RVA(BootDdDTE->DllBase, ImportTable->FirstThunk)); - - while (((PIMAGE_THUNK_DATA)ThunkData)->u1.AddressOfData != 0) - { - ThunkData->u1.Function = (ULONG_PTR)VaToPa((PVOID)ThunkData->u1.Function); - ThunkData++; - } - } - - /* Relocate image to PA */ - NtHeaders = RtlImageNtHeader(VaToPa(BootDdDTE->DllBase)); - if (!NtHeaders) - return EIO; - Success = (BOOLEAN)LdrRelocateImageWithBias(VaToPa(BootDdDTE->DllBase), - NtHeaders->OptionalHeader.ImageBase - (ULONG_PTR)BootDdDTE->DllBase, - "FreeLdr", - TRUE, - TRUE, /* In case of conflict still return success */ - FALSE); - if (!Success) - return EIO; +#endif - /* Call the entrypoint */ + /* Call the entrypoint and keep the image loaded in memory */ + // FldrpStartImage(BootDdDTE); EntryPoint = VaToPa(BootDdDTE->EntryPoint); - (*EntryPoint)(NULL, NULL); + EntryPoint(NULL, NULL); return ESUCCESS; } diff --git a/boot/freeldr/freeldr/include/disk.h b/boot/freeldr/freeldr/include/disk.h index ec12a8f4b3136..d367c9fdb7a52 100644 --- a/boot/freeldr/freeldr/include/disk.h +++ b/boot/freeldr/freeldr/include/disk.h @@ -152,4 +152,4 @@ DiskGetPartitionEntry( /* * SCSI support (disk/scsiport.c) */ -ULONG LoadBootDeviceDriver(VOID); +ARC_STATUS LoadBootDeviceDriver(VOID); diff --git a/boot/freeldr/freeldr/include/peloader.h b/boot/freeldr/freeldr/include/peloader.h index 00a387ef7a042..65fe2f6ea3b81 100644 --- a/boot/freeldr/freeldr/include/peloader.h +++ b/boot/freeldr/freeldr/include/peloader.h @@ -60,3 +60,24 @@ PeLdrCheckForLoadedDll( PVOID PeLdrInitSecurityCookie( _In_ PLDR_DATA_TABLE_ENTRY LdrEntry); + + + +extern LIST_ENTRY FrLdrModuleList; +extern PLDR_DATA_TABLE_ENTRY FreeldrDTE; + +ARC_STATUS +FldrpLoadImage( + _In_ PCSTR ImageFilePath, + _In_opt_ PCSTR ImportName, + _In_ TYPE_OF_MEMORY MemoryType, + _Out_ PLDR_DATA_TABLE_ENTRY* ImageEntry, + _Out_opt_ PVOID* ImageBasePA); + +BOOLEAN +FldrpUnloadImage( + _Inout_ PLDR_DATA_TABLE_ENTRY ImageEntry); + +ARC_STATUS +FldrpStartImage( + _In_ PLDR_DATA_TABLE_ENTRY ImageEntry); diff --git a/boot/freeldr/freeldr/lib/peloader.c b/boot/freeldr/freeldr/lib/peloader.c index 7596da490dbcd..36f03608afac2 100644 --- a/boot/freeldr/freeldr/lib/peloader.c +++ b/boot/freeldr/freeldr/lib/peloader.c @@ -25,6 +25,9 @@ DBG_DEFAULT_CHANNEL(PELOADER); /* GLOBALS *******************************************************************/ +LIST_ENTRY FrLdrModuleList; +PLDR_DATA_TABLE_ENTRY FreeldrDTE; + PELDR_IMPORTDLL_LOAD_CALLBACK PeLdrImportDllLoadCallback = NULL; #ifdef _WIN64 @@ -37,6 +40,44 @@ PELDR_IMPORTDLL_LOAD_CALLBACK PeLdrImportDllLoadCallback = NULL; /* PRIVATE FUNCTIONS *********************************************************/ +static BOOLEAN +FrLdrInitImageSupport(VOID) +{ +// extern char __ImageBase; + BOOLEAN Success; + + if (FreeldrDTE) + { + /* Already initialized, bail out */ + return TRUE; + } + + /* Initialize the loaded module list */ + InitializeListHead(&FrLdrModuleList); + + /* + * Add freeldr.sys to the list of loaded executables, as it + * contains exports that may be imported by the loaded image. + * For example, ScsiPort* exports, imported by ntbootdd.sys. + */ + Success = PeLdrAllocateDataTableEntry(&FrLdrModuleList, + "freeldr.sys", + "FREELDR.SYS", + &__ImageBase, + &FreeldrDTE); + if (!Success) + { + /* Cleanup and bail out */ + ERR("PeLdrAllocateDataTableEntry('%s') failed\n", "FREELDR.SYS"); + return FALSE; // ENOMEM; + } + + /* Now unlink the DTEs, they won't be valid later */ + // RemoveEntryList(&FreeldrDTE->InLoadOrderLinks); + + return Success; +} + static PVOID PeLdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage) { @@ -1009,3 +1050,148 @@ PeLdrLoadImage( MmFreeMemory(PhysicalBase); return FALSE; } + + +/** + * @brief + * External FreeLdr PE image loader. + **/ +ARC_STATUS +FldrpLoadImage( + _In_ PCSTR ImageFilePath, + _In_opt_ PCSTR ImportName, + _In_ TYPE_OF_MEMORY MemoryType, + _Out_ PLDR_DATA_TABLE_ENTRY* ImageEntry, + _Out_opt_ PVOID* ImageBasePA) +{ + ARC_STATUS Status; + BOOLEAN Success; + PVOID ImageBase = NULL; + PLDR_DATA_TABLE_ENTRY ImageDTE; + PIMAGE_NT_HEADERS NtHeaders; + PIMAGE_IMPORT_DESCRIPTOR ImportTable; + ULONG ImportTableSize; + + /* Initialize image loading support */ + // if (!FreeldrDTE) + if (!FrLdrInitImageSupport()) + { + ERR("Cannot initialize Image Support\n"); + return ENOEXEC; + } + + /* Load the image */ + Success = PeLdrLoadImage(ImageFilePath, MemoryType, &ImageBase); + if (!Success) + { + ERR("PeLdrLoadImage('%s') failed\n", ImageFilePath); + return ENOEXEC; + } + + if (!ImportName) + { + /* Get the file name from the path */ + ImportName = strrchr(ImageFilePath, '\\'); + if (ImportName) + { + /* Name is past the path separator */ + ImportName++; + } + else + { + /* No directory, just use the given path */ + ImportName = ImageFilePath; + } + } + + /* Allocate a DTE for it */ + Success = PeLdrAllocateDataTableEntry(&FrLdrModuleList, + ImportName, + ImageFilePath, + ImageBase, + &ImageDTE); + if (!Success) + { + /* Cleanup and bail out */ + ERR("PeLdrAllocateDataTableEntry('%s') failed\n", ImageFilePath); + MmFreeMemory(ImageBase); + return ENOMEM; + } + + /* Reset ImageBase */ + ASSERT(VaToPa(ImageDTE->DllBase) == ImageBase); + // ImageBase = VaToPa(ImageDTE->DllBase); + + /* Load any other referenced DLLs for the loaded image */ + Success = PeLdrScanImportDescriptorTable(&FrLdrModuleList, ""/*DirPath*/, ImageDTE); + if (!Success) + { + /* Cleanup and bail out */ + ERR("PeLdrScanImportDescriptorTable('%s') failed\n", ImageFilePath); + Status = EIO; + goto Failure; + } + + // /* Now unlink the DTEs, they won't be valid later */ + // RemoveEntryList(&FreeldrDTE->InLoadOrderLinks); + // RemoveEntryList(&ImageDTE->InLoadOrderLinks); + + /* Change imports to PA */ + ImportTable = + (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ImageBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_IMPORT, + &ImportTableSize); + for (; (ImportTable->Name != 0) && (ImportTable->FirstThunk != 0); ImportTable++) + { + PIMAGE_THUNK_DATA ThunkData = (PIMAGE_THUNK_DATA)VaToPa(RVA(ImageDTE->DllBase, ImportTable->FirstThunk)); + + while (((PIMAGE_THUNK_DATA)ThunkData)->u1.AddressOfData != 0) + { + ThunkData->u1.Function = (ULONG_PTR)VaToPa((PVOID)ThunkData->u1.Function); + ThunkData++; + } + } + + NtHeaders = RtlImageNtHeader(ImageBase); + ASSERT(NtHeaders); // PeLdrLoadImage succeeded, so the image was valid and had a header... + // ASSERT(NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC); + + /* Relocate image to PA */ + Success = (BOOLEAN)LdrRelocateImageWithBias(ImageBase, + NtHeaders->OptionalHeader.ImageBase - (ULONG_PTR)ImageDTE->DllBase, + "FreeLdr", + TRUE, + TRUE, /* In case of conflict still return success */ + FALSE); + if (!Success) + { + Status = EIO; + goto Failure; + } + + *ImageEntry = ImageDTE; + if (ImageBasePA) + *ImageBasePA = ImageBase; + + return ESUCCESS; + +Failure: + /* We failed, cleanup */ + FldrpUnloadImage(ImageDTE); + return Status; +} + +/** + * @brief + * Unload a loaded external FreeLdr PE image. + **/ +BOOLEAN +FldrpUnloadImage( + _Inout_ PLDR_DATA_TABLE_ENTRY ImageEntry) +{ + PVOID ImageBase = VaToPa(ImageEntry->DllBase); + PeLdrFreeDataTableEntry(ImageEntry); + MmFreeMemory(ImageBase); + return TRUE; +}