/*++ Copyright (c) 1992 Microsoft Corporation Module Name: blload.c Abstract: This module provides common code for loading things like drivers, NLS files, registry. Used by both the osloader and the setupldr. Author: John Vert (jvert) 8-Oct-1993 Environment: ARC environment Revision History: --*/ #include "bldr.h" #include "stdio.h" ARC_STATUS BlLoadSystemHive( IN ULONG DeviceId, IN PCHAR DeviceName, IN PCHAR DirectoryPath, IN PCHAR HiveName ) /*++ Routine Description: Loads the registry SYSTEM hive from \config\system. Allocates a memory descriptor to hold the hive image, reads the hive image into this descriptor, and updates the registry pointers in the LoaderBlock. Arguments: DeviceId - Supplies the file id of the device the system tree is on. DeviceName - Supplies the name of the device the system tree is on. DirectoryPath - Supplies a pointer to the zero-terminated directory path of the root of the NT tree. HiveName - Supplies the name of the system hive ("SYSTEM" or "SYSTEM.ALT") Return Value: TRUE - system hive successfully loaded. FALSE - system hive could not be loaded. --*/ { CHAR RegistryName[256]; ULONG FileId; ARC_STATUS Status; FILE_INFORMATION FileInformation; ULONG FileSize; ULONG ActualBase; PVOID LocalPointer; LARGE_INTEGER SeekValue; ULONG Count; PCHAR FailReason; // // Create the full filename for the SYSTEM hive. // strcpy(&RegistryName[0], DirectoryPath); strcat(&RegistryName[0], HiveName); BlOutputLoadMessage(DeviceName, &RegistryName[0]); Status = BlOpen(DeviceId, &RegistryName[0], ArcOpenReadOnly, &FileId); if (Status != ESUCCESS) { FailReason = "BlOpen"; goto HiveLoadFailed; } // // Determine the length of the registry file // Status = BlGetFileInformation(FileId, &FileInformation); if (Status != ESUCCESS) { BlClose(FileId); FailReason = "BlGetFileInformation"; goto HiveLoadFailed; } FileSize = FileInformation.EndingAddress.LowPart; if (FileSize == 0) { Status = EINVAL; BlClose(FileId); FailReason = "FileSize == 0"; goto HiveLoadFailed; } // // Round up to a page boundary, allocate a memory // descriptor, fill in the registry fields in the // loader parameter block, and read the registry data // into memory. // Status = BlAllocateDescriptor(LoaderRegistryData, 0x0, (FileSize + PAGE_SIZE - 1) >> PAGE_SHIFT, &ActualBase); if (Status != ESUCCESS) { BlClose(FileId); FailReason = "BlAllocateDescriptor"; goto HiveLoadFailed; } LocalPointer = (PVOID)(KSEG0_BASE | (ActualBase << PAGE_SHIFT)); BlLoaderBlock->RegistryLength = FileSize; BlLoaderBlock->RegistryBase = LocalPointer; // // Read the SYSTEM hive into the allocated memory. // SeekValue.QuadPart = 0; Status = BlSeek(FileId, &SeekValue, SeekAbsolute); if (Status != ESUCCESS) { BlClose(FileId); FailReason = "BlSeek"; goto HiveLoadFailed; } Status = BlRead(FileId, LocalPointer, FileSize, &Count); BlClose(FileId); if (Status != ESUCCESS) { FailReason = "BlRead"; goto HiveLoadFailed; } return(ESUCCESS); HiveLoadFailed: // // The system hive didn't exist, or was corrupt. Pass a NULL // pointer into the system, so it gets recreated. // return(Status); } ARC_STATUS BlLoadNLSData( IN ULONG DeviceId, IN PCHAR DeviceName, IN PCHAR DirectoryPath, IN PUNICODE_STRING AnsiCodepage, IN PUNICODE_STRING OemCodepage, IN PUNICODE_STRING LanguageTable, OUT PCHAR BadFileName ) /*++ Routine Description: This routine loads all the NLS data files into one contiguous block of memory. Arguments: DeviceId - Supplies the file id of the device the system tree is on. DeviceName - Supplies the name of the device the system tree is on. DirectoryPath - Supplies a pointer to the zero-terminated path of the directory containing the NLS files. AnsiCodePage - Supplies the filename of the ANSI codepage data file. OemCodePage - Supplies the filename of the OEM codepage data file. LanguageTable - Supplies the filename of the Unicode language case table. BadFileName - Returns the filename of the NLS file that was missing or invalid. This will not be filled in if ESUCCESS is returned. Return Value: ESUCCESS is returned if the NLS data was successfully loaded. Otherwise, an unsuccessful status is returned. --*/ { CHAR Filename[100]; ULONG AnsiFileId; ULONG OemFileId; ULONG LanguageFileId; ARC_STATUS Status; FILE_INFORMATION FileInformation; ULONG AnsiFileSize; ULONG OemFileSize; ULONG LanguageFileSize; ULONG TotalSize; ULONG ActualBase; PVOID LocalPointer; LARGE_INTEGER SeekValue; ULONG Count; BOOLEAN OemIsSameAsAnsi = FALSE; // // Under the Japanese version of NT, ANSI code page and OEM codepage // is same. In this case, we share the same data to save and memory. // if ( (AnsiCodepage->Length == OemCodepage->Length) && (_wcsnicmp(AnsiCodepage->Buffer, OemCodepage->Buffer, AnsiCodepage->Length) == 0)) { OemIsSameAsAnsi = TRUE; } // // Open the ANSI data file // sprintf(Filename, "%s%wZ", DirectoryPath,AnsiCodepage); BlOutputLoadMessage(DeviceName, Filename); Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &AnsiFileId); if (Status != ESUCCESS) { goto NlsLoadFailed; } Status = BlGetFileInformation(AnsiFileId, &FileInformation); BlClose(AnsiFileId); if (Status != ESUCCESS) { goto NlsLoadFailed; } AnsiFileSize = FileInformation.EndingAddress.LowPart; // // Open the OEM data file // if (OemIsSameAsAnsi) { OemFileSize = 0; } else { sprintf(Filename, "%s%wZ", DirectoryPath, OemCodepage); BlOutputLoadMessage(DeviceName, Filename); Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &OemFileId); if (Status != ESUCCESS) { goto NlsLoadFailed; } Status = BlGetFileInformation(OemFileId, &FileInformation); BlClose(OemFileId); if (Status != ESUCCESS) { goto NlsLoadFailed; } OemFileSize = FileInformation.EndingAddress.LowPart; } // // Open the language codepage file // sprintf(Filename, "%s%wZ", DirectoryPath,LanguageTable); BlOutputLoadMessage(DeviceName, Filename); Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &LanguageFileId); if (Status != ESUCCESS) { goto NlsLoadFailed; } Status = BlGetFileInformation(LanguageFileId, &FileInformation); BlClose(LanguageFileId); if (Status != ESUCCESS) { goto NlsLoadFailed; } LanguageFileSize = FileInformation.EndingAddress.LowPart; // // Calculate the total size of the descriptor needed. We want each // data file to start on a page boundary, so round up each size to // page granularity. // TotalSize = ROUND_TO_PAGES(AnsiFileSize) + ROUND_TO_PAGES(OemFileSize) + ROUND_TO_PAGES(LanguageFileSize); Status = BlAllocateDescriptor(LoaderNlsData, 0x0, TotalSize >> PAGE_SHIFT, &ActualBase); if (Status != ESUCCESS) { goto NlsLoadFailed; } LocalPointer = (PVOID)(KSEG0_BASE | (ActualBase << PAGE_SHIFT)); BlLoaderBlock->NlsData->AnsiCodePageData = LocalPointer; BlLoaderBlock->NlsData->OemCodePageData = (PVOID)((PUCHAR)LocalPointer + ROUND_TO_PAGES(AnsiFileSize)); BlLoaderBlock->NlsData->UnicodeCaseTableData = (PVOID)((PUCHAR)LocalPointer + ROUND_TO_PAGES(AnsiFileSize) + ROUND_TO_PAGES(OemFileSize)); // // Let OemCodePageData point as same location as AnsiCodePageData. // if( OemIsSameAsAnsi ) { BlLoaderBlock->NlsData->OemCodePageData = BlLoaderBlock->NlsData->AnsiCodePageData; } // // Read NLS data into memory // // open and read ANSI file // sprintf(Filename, "%s%wZ", DirectoryPath,AnsiCodepage); Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &AnsiFileId); if (Status != ESUCCESS) { goto NlsLoadFailed; } SeekValue.QuadPart = 0; Status = BlSeek(AnsiFileId, &SeekValue, SeekAbsolute); if (Status != ESUCCESS) { goto NlsLoadFailed; } Status = BlRead(AnsiFileId, BlLoaderBlock->NlsData->AnsiCodePageData, AnsiFileSize, &Count); if (Status != ESUCCESS) { goto NlsLoadFailed; } BlClose(AnsiFileId); // // Open and read OEM file // if (!OemIsSameAsAnsi) { sprintf(Filename, "%s%wZ", DirectoryPath, OemCodepage); Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &OemFileId); if (Status != ESUCCESS) { goto NlsLoadFailed; } SeekValue.QuadPart = 0; Status = BlSeek(OemFileId, &SeekValue, SeekAbsolute); if (Status != ESUCCESS) { goto NlsLoadFailed; } Status = BlRead(OemFileId, BlLoaderBlock->NlsData->OemCodePageData, OemFileSize, &Count); if (Status != ESUCCESS) { goto NlsLoadFailed; } BlClose(OemFileId); } // // open and read Language file // sprintf(Filename, "%s%wZ", DirectoryPath,LanguageTable); Status = BlOpen(DeviceId, Filename, ArcOpenReadOnly, &LanguageFileId); if (Status != ESUCCESS) { goto NlsLoadFailed; } SeekValue.QuadPart = 0; Status = BlSeek(LanguageFileId, &SeekValue, SeekAbsolute); if (Status != ESUCCESS) { goto NlsLoadFailed; } Status = BlRead(LanguageFileId, BlLoaderBlock->NlsData->UnicodeCaseTableData, LanguageFileSize, &Count); if (Status != ESUCCESS) { goto NlsLoadFailed; } BlClose(LanguageFileId); return(ESUCCESS); NlsLoadFailed: strcpy(BadFileName,Filename); return(Status); } ARC_STATUS BlLoadOemHalFont( IN ULONG DeviceId, IN PCHAR DeviceName, IN PCHAR DirectoryPath, IN PUNICODE_STRING OemHalFont, OUT PCHAR BadFileName ) /*++ Routine Description: This routine loads the OEM font file for use the HAL display string function. Arguments: DeviceId - Supplies the file id of the device the system tree is on. DeviceName - Supplies the name of the device the system tree is on. DirectoryPath - Supplies a pointer to the directory path of the root of the NT tree. Fontfile - Supplies the filename of the OEM font file. BadFileName - Returns the filename of the OEM font file that was missing or invalid. Return Value: ESUCCESS is returned if the OEM font was successfully loaded. Otherwise, an unsuccessful status is returned and the bad file name is filled. --*/ { PVOID FileBuffer; ULONG Count; PIMAGE_DOS_HEADER DosHeader; ULONG FileId; FILE_INFORMATION FileInformation; CHAR Filename[100]; ULONG FileSize; ARC_STATUS Status; POEM_FONT_FILE_HEADER FontHeader; PIMAGE_OS2_HEADER Os2Header; ULONG ScaleFactor; RESOURCE_TYPE_INFORMATION UNALIGNED *TableAddress; RESOURCE_TYPE_INFORMATION UNALIGNED *TableEnd; RESOURCE_NAME_INFORMATION UNALIGNED *TableName; // // Open the OEM font file. // BlLoaderBlock->OemFontFile = NULL; sprintf(&Filename[0], "%s%wZ", DirectoryPath, OemHalFont); BlOutputLoadMessage(DeviceName, &Filename[0]); Status = BlOpen(DeviceId, &Filename[0], ArcOpenReadOnly, &FileId); if (Status != ESUCCESS) { goto OemLoadExit; } // // Get the size of the font file and allocate a buffer from the heap // to hold the font file. Typically this file is about 4kb in length. // Status = BlGetFileInformation(FileId, &FileInformation); if (Status != ESUCCESS) { goto OemLoadExit; } FileSize = FileInformation.EndingAddress.LowPart; FileBuffer = BlAllocateHeap(FileSize + BlDcacheFillSize - 1); if (FileBuffer == NULL) { Status = ENOMEM; goto OemLoadExit; } // // Round the file buffer address up to a cache line boundary and read // the file into memory. // FileBuffer = (PVOID)((ULONG)FileBuffer + BlDcacheFillSize - 1); FileBuffer = (PVOID)((ULONG)FileBuffer & ~(BlDcacheFillSize - 1)); Status = BlRead(FileId, FileBuffer, FileSize, &Count); if (Status != ESUCCESS) { goto OemLoadExit; } // // Attempt to recognize the file as either a .fon or .fnt file. // // Check if the file has a DOS header or a font file header. If the // file has a font file header, then it is a .fnt file. Otherwise, // it must be checked for an OS/2 executable with a font resource. // Status = EBADF; DosHeader = (PIMAGE_DOS_HEADER)FileBuffer; if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) { // // Check if the file has a font file header. // FontHeader = (POEM_FONT_FILE_HEADER)FileBuffer; if ((FontHeader->Version != OEM_FONT_VERSION) || (FontHeader->Type != OEM_FONT_TYPE) || (FontHeader->Italic != OEM_FONT_ITALIC) || (FontHeader->Underline != OEM_FONT_UNDERLINE) || (FontHeader->StrikeOut != OEM_FONT_STRIKEOUT) || (FontHeader->CharacterSet != OEM_FONT_CHARACTER_SET) || (FontHeader->Family != OEM_FONT_FAMILY) || (FontHeader->PixelWidth > 32)) { goto OemLoadExit; } else { BlLoaderBlock->OemFontFile = (PVOID)FontHeader; Status = ESUCCESS; goto OemLoadExit; } } // // Check if the file has an OS/2 header. // if ((FileSize < sizeof(IMAGE_DOS_HEADER)) || (FileSize < (ULONG)DosHeader->e_lfanew)) { goto OemLoadExit; } Os2Header = (PIMAGE_OS2_HEADER)((PUCHAR)DosHeader + DosHeader->e_lfanew); if (Os2Header->ne_magic != IMAGE_OS2_SIGNATURE) { goto OemLoadExit; } // // Check if the resource table exists. // if ((Os2Header->ne_restab - Os2Header->ne_rsrctab) == 0) { goto OemLoadExit; } // // Compute address of resource table and search the table for a font // resource. // TableAddress = (PRESOURCE_TYPE_INFORMATION)((PUCHAR)Os2Header + Os2Header->ne_rsrctab); TableEnd = (PRESOURCE_TYPE_INFORMATION)((PUCHAR)Os2Header + Os2Header->ne_restab); ScaleFactor = *((SHORT UNALIGNED *)TableAddress)++; while ((TableAddress < TableEnd) && (TableAddress->Ident != 0) && (TableAddress->Ident != FONT_RESOURCE)) { TableAddress = (PRESOURCE_TYPE_INFORMATION)((PUCHAR)(TableAddress + 1) + (TableAddress->Number * sizeof(RESOURCE_NAME_INFORMATION))); } if ((TableAddress >= TableEnd) || (TableAddress->Ident != FONT_RESOURCE)) { goto OemLoadExit; } // // Compute address of resource name information and check if the resource // is within the file. // TableName = (PRESOURCE_NAME_INFORMATION)(TableAddress + 1); if (FileSize < ((TableName->Offset << ScaleFactor) + sizeof(OEM_FONT_FILE_HEADER))) { goto OemLoadExit; } // // Compute the address of the font file header and check if the header // contains correct information. // FontHeader = (POEM_FONT_FILE_HEADER)((PCHAR)FileBuffer + (TableName->Offset << ScaleFactor)); if ((FontHeader->Version != OEM_FONT_VERSION) || (FontHeader->Type != OEM_FONT_TYPE) || (FontHeader->Italic != OEM_FONT_ITALIC) || (FontHeader->Underline != OEM_FONT_UNDERLINE) || (FontHeader->StrikeOut != OEM_FONT_STRIKEOUT) || (FontHeader->CharacterSet != OEM_FONT_CHARACTER_SET) || (FontHeader->PixelWidth > 32)) { goto OemLoadExit; } else { BlLoaderBlock->OemFontFile = (PVOID)FontHeader; Status = ESUCCESS; goto OemLoadExit; } // // Exit loading of the OEM font file. // OemLoadExit: BlClose(FileId); strcpy(BadFileName,&Filename[0]); return(Status); } ARC_STATUS BlLoadDeviceDriver ( IN ULONG DeviceId, IN PCHAR LoadDevice, IN PCHAR DirectoryPath, IN PCHAR DriverName, IN ULONG DriverFlags, OUT PLDR_DATA_TABLE_ENTRY *DriverDataTableEntry ) /*++ Routine Description: This routine loads the specified device driver and resolves all DLL references if the driver is not already loaded. Arguments: DeviceId - Supplies the file id of the device on which the specified device driver is loaded from. LoadDevice - Supplies a pointer to a zero terminated load device string. DirectoryPath - Supplies a pointer to a zero terminated directory path string. DriverName - Supplies a pointer to a zero terminated device driver name string. DriverFlags - Supplies the driver flags that are to be set in the generated data table entry. DriverDataTableEntry - Receives a pointer to the data table entry created for the newly-loaded driver. Return Value: ESUCCESS is returned if the specified driver is successfully loaded or it is already loaded. Otherwise, and unsuccessful status is returned. --*/ { CHAR DllName[256]; CHAR FullName[256]; PVOID Base; ARC_STATUS Status; // // Generate the DLL name for the device driver. // strcpy(&DllName[0], DriverName); // // If the specified device driver is not already loaded, then load it. // if (BlCheckForLoadedDll(&DllName[0], DriverDataTableEntry) == FALSE) { // // Generate the full path name of device driver. // strcpy(&FullName[0], &DirectoryPath[0]); strcat(&FullName[0], DriverName); BlOutputLoadMessage(LoadDevice, &FullName[0]); Status = BlLoadImage(DeviceId, LoaderBootDriver, &FullName[0], TARGET_IMAGE, &Base); if (Status != ESUCCESS) { return Status; } // // Generate a data table entry for the driver, then clear the entry // processed flag. The I/O initialization code calls each DLL in the // loaded module list that does not have its entry processed flag set. // Status = BlAllocateDataTableEntry(&DllName[0], DriverName, Base, DriverDataTableEntry); if (Status != ESUCCESS) { return Status; } (*DriverDataTableEntry)->Flags |= DriverFlags; // // Scan the import table and load all the referenced DLLs. // Status = BlScanImportDescriptorTable(DeviceId, LoadDevice, &DirectoryPath[0], *DriverDataTableEntry); if (Status != ESUCCESS) { // // Remove the driver from the load order list. // RemoveEntryList(&(*DriverDataTableEntry)->InLoadOrderLinks); return Status; } } return ESUCCESS; }