// ---------------------------------------------------------------------------- // // Copyright (c) 1992 Olivetti // // File: omf.c // // Description: this code implements the omf protocol as defined // in the ARC-EISA addendum. // // ---------------------------------------------------------------------------- #include "fwp.h" #include "oli2msft.h" #include "arceisa.h" #include "inc.h" #include "string.h" #include "debug.h" extern BL_FILE_TABLE BlFileTable [BL_FILE_TABLE_SIZE]; #define DEVICE_DEVICE 0xDEAD // ---------------------------------------------------------------------------- // Declare Function Prototypes // ---------------------------------------------------------------------------- ARC_STATUS OmfOpen ( IN PCHAR OpenPath, IN OPEN_MODE OpenMode, IN OUT PULONG FileId ); ARC_STATUS OmfClose ( IN ULONG FileId ); ARC_STATUS OmfMount ( IN PCHAR MountPath, IN MOUNT_OPERATION Operation ); ARC_STATUS OmfRead ( IN ULONG FileId, IN PVOID Buffer, IN ULONG Length, OUT PULONG Count ); ARC_STATUS OmfWrite ( IN ULONG FileId, IN PVOID Buffer, IN ULONG Length, OUT PULONG Count ); ARC_STATUS OmfGetReadStatus ( IN ULONG FileId ); ARC_STATUS OmfSeek ( IN ULONG FileId, IN PLARGE_INTEGER Offset, IN SEEK_MODE SeekMode ); ARC_STATUS OmfGetFileInformation ( IN ULONG FileId, OUT PFILE_INFORMATION Buffer ); ARC_STATUS OmfSetFileInformation ( IN ULONG FileId, IN ULONG AttributeFlags, IN ULONG AttributeMask ); ARC_STATUS OmfGetDirectoryEntry ( IN ULONG FileId, IN DIRECTORY_ENTRY *DirEntry, IN ULONG NumberDir, OUT PULONG CountDir ); ARC_STATUS OmfFileOpen ( IN PCHAR OpenPath, IN OPEN_MODE OpenMode, IN OUT PULONG FileId ); ARC_STATUS OmfFileClose ( IN ULONG FileId ); ARC_STATUS OmfFileMount ( IN PCHAR MountPath, IN MOUNT_OPERATION Operation ); ARC_STATUS OmfFileRead ( IN ULONG FileId, IN PVOID Buffer, IN ULONG Length, OUT PULONG Count ); ARC_STATUS OmfFileWrite ( IN ULONG FileId, IN PVOID Buffer, IN ULONG Length, OUT PULONG Count ); ARC_STATUS OmfFileGetReadStatus ( IN ULONG FileId ); ARC_STATUS OmfFileSeek ( IN ULONG FileId, IN PLARGE_INTEGER Offset, IN SEEK_MODE SeekMode ); ARC_STATUS OmfFileGetFileInformation ( IN ULONG FileId, OUT PFILE_INFORMATION Buffer ); ARC_STATUS OmfFileSetFileInformation ( IN ULONG FileId, IN ULONG AttributeFlags, IN ULONG AttributeMask ); ARC_STATUS OmfFileGetDirectoryEntry ( IN ULONG FileId, IN DIRECTORY_ENTRY *DirEntry, IN ULONG NumberDir, OUT PULONG CountDir ); BOOLEAN MaxOmfFatFiles ( IN OUT PCHAR MasterName, IN PCHAR CheckedName ); BOOLEAN OmfFileNameValidate ( IN PCHAR OpenPath, OUT PCHAR OmfFileName, OUT PCHAR OmfType ); BOOLEAN CmpOmfFiles ( IN PCHAR OmfFileName, IN CHAR OmfType, IN POMF_DIR_ENT POmfDirEnt ); BOOLEAN OmfHeaderValidate ( IN ULONG FileId ); BOOLEAN OmfFileValidate ( IN ULONG FileId ); VOID ConvertOmfDirToArcDir ( IN POMF_DIR_ENT POmfDirEnt, OUT DIRECTORY_ENTRY *PArcDirEnt ); BOOLEAN FwGetEisaId ( IN PCHAR PathName, OUT PCHAR EisaId, OUT PUCHAR IdInfo ); VOID FwUncompressEisaId ( IN PUCHAR CompEisaId, OUT PUCHAR UncompEisaId ); BOOLEAN FwGetEisaBusIoCpuAddress ( IN PCHAR EisaPath, OUT PVOID *IoBusAddress ); PCHAR FwGetEnvironmentVariable ( IN PCHAR Variable ); PCONFIGURATION_COMPONENT FwGetComponent ( IN PCHAR Pathname ); LARGE_INTEGER RtlConvertUlongToLargeInteger ( IN ULONG UnsignedInteger ); LARGE_INTEGER RtlLargeIntegerAdd ( IN LARGE_INTEGER Addend1, IN LARGE_INTEGER Addend2 ); ARC_STATUS FwFileIdChecksum ( IN ULONG FileId, IN LARGE_INTEGER StartingOffset, IN ULONG Length, IN OUT PUCHAR Checksum ); BOOLEAN FwGetMnemonicKey ( IN PCHAR Path, IN PCHAR Mnemonic, IN PULONG Key ); BOOLEAN FwGetNextMnemonic ( IN PCHAR Path, IN PCHAR Mnemonic, OUT PCHAR NextMnemonic ); BOOLEAN FwGetMnemonicPath ( IN PCHAR Path, IN PCHAR Mnemonic, OUT PCHAR MnemonicPath ); BOOLEAN GetNextPath ( IN OUT PCHAR *PPathList, OUT PCHAR PathTarget ); // ---------------------------------------------------------------------------- // Global Data // ---------------------------------------------------------------------------- // // Omf entry table. // This is a structure that provides entry to the OMF system procedures. // It is exported when a OMF is opened as a device. // BL_DEVICE_ENTRY_TABLE OmfEntryTable = { OmfClose, OmfMount, OmfOpen, OmfRead, OmfGetReadStatus, OmfSeek, OmfWrite, OmfGetFileInformation, OmfSetFileInformation, OmfGetDirectoryEntry }; // // Omf file entry table. // This is a structure that provides entry to the OMF file system procedures. // It is exported when a OMF file is opened. // BL_DEVICE_ENTRY_TABLE OmfFileEntryTable = { OmfFileClose, OmfFileMount, OmfFileOpen, OmfFileRead, OmfFileGetReadStatus, OmfFileSeek, OmfFileWrite, OmfFileGetFileInformation, OmfFileSetFileInformation, OmfFileGetDirectoryEntry }; // ---------------------------------------------------------------------------- // PROCEDURE: OmfOpen: // // DESCRIPTION: The routine opens the newest version/revision of OMF for // the specified Product ID. // // a) It reads the EISAROM bit of the component of // the Path argument on the EISA bus spcified by the key of // the component of Path argument. // b) If this bit is one, then a byte checksum is performed on // the ROM-based OMF header and OMF directory. // The Product ID, Firmware Version and Revision fields // values are retained for the next operations. // c) Next, the partitions, specified by the FWSearchPath // environment variable are searched for files of the // following form in the \eisa\omf subdirectory: // // "V".LF"R" // // = EISA Product ID (7 chars) // "V" = version ([0-9],[A-Z]) // "R" = revision ([0-9],[A-Z]) // // d) The OMF FAT file (or ROM) with a greater value of version- // revision and with a correct checksum is used. // f) Initialize some data structures // // When Open is used to access an OMF as a raw device, all input // functions are permitted. These functions include Read, Seek // and Close. Read and Seek are bounded by the current OMF size. // For example, to read the OMF of a serial options board that was // in slot 3 of EISA bus 0 as raw device, create and Open a path // as follows: eisa(0)serial(3)omf() . // // ARGUMENTS: OpenPath Supplies a pointer to a zero terminated device // path name. // OpenMode Supplies the mode of the open. // FileId Supplies a pointer to a variable that specifies // the file table entry that is to be filled in // if the open is successful. // // RETURN: ESUCCESS is returned if the open operation is successful. // ENODEV the device portion of the pathname is invalid // // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfOpen ( IN PCHAR OpenPath, IN OPEN_MODE OpenMode, IN OUT PULONG FileId ) { // // initialize local variables // LARGE_INTEGER Offset; // large interger for seek operations ULONG SlotNumber; // eisa slot number CHAR EisaCtrlMnemonic[ MAX_MNEMONIC_LEN +1 ]; // eisa ctrl mnemonic name UCHAR IdInfo; // info id byte PVOID IoBusAddress; // eisa I/O base address (virtual) PUCHAR SlotAddress; // I/O address BOOLEAN OmfRomOk=FALSE; // OMF ROM initialization flag BOOLEAN OmfFatFileOk=FALSE; // OMF FAT file initialization flag ULONG Count; // # of bytes transferred PCHAR PFwSearchPath; // system partitions list pointer CHAR OmfPathName[MAX_PATH_LEN +1]; // directory+subdirectory+file name CHAR OmfPathBuffer[MAX_PATH_LEN +1] = {'\0'}; // OMF path name buffer CHAR OmfFatFileName[]=" .LF "; // omf name (FAT format) ULONG OmfSubdirId; // file Id of \eisa\omf subdirectory POMF_HEADER_CONTEXT POmfHeaderContext; // OMF header context pointer POMF_HDR POmfHeader; // pointer to OMF ROM/FAT file header DIRECTORY_ENTRY DirEntBuffer; // ARC directory entry PRINTDBG("OmfOpen\n\r"); // debug support // // this is a read only device // if ( OpenMode != ArcOpenReadOnly ) { return EROFS; } // // The path must have the following form : eisa(x)"mnemonic"(y)omf() // Get EISA ID, slot number and its I/O address space. // if ( !FwGetNextMnemonic( OpenPath, "eisa", EisaCtrlMnemonic ) || !FwGetMnemonicKey( OpenPath, EisaCtrlMnemonic, &SlotNumber ) || !FwGetMnemonicPath( OpenPath, EisaCtrlMnemonic, OmfPathName ) || !FwGetEisaId( OmfPathName, OmfFatFileName, &IdInfo ) || !FwGetMnemonicPath( OpenPath,"eisa",OmfPathName ) || !FwGetEisaBusIoCpuAddress( OmfPathName, &IoBusAddress ) ) { return ENODEV; } // // Initialize some variables // POmfHeaderContext = &BlFileTable[ *FileId ].u.OmfHeaderContext; POmfHeader = &POmfHeaderContext->OmfHeader; SlotAddress = (PUCHAR)IoBusAddress + SlotNumber * 0x1000; Offset.LowPart = 0; // seek operation Offset.HighPart = 0; // seek operation // // Check EISAROM bit of the Expansion Board Control Bits field. // If the EISA ID is readable, the controller supports the EISA extensions // // DEBUG-DEBUG : for now skip the OMF ROM check because // at the moment there isn't any board available // with an OMF ROM to test the routine. if (0) //if ( !(IdInfo & CFG_UNREADABLE_ID) && // READ_REGISTER_UCHAR( SlotAddress + EXPANSION_BOARD_CTRL_BITS ) & // EISAROMBIT ) { // // initialize some fields to direct the OmfRead to the ROM // POmfHeaderContext->RomIndex = (PULONG)(SlotAddress+ROMINDEX); POmfHeaderContext->RomRead = (PULONG)(SlotAddress+ROMREAD); POmfHeaderContext->FileId = DEVICE_DEVICE; POmfHeader->FwSize = 0; // max length simulation // // check OMF ROM header, copy it in the OmfHeaderContext structure // if ( !OmfSeek( *FileId, &Offset, SeekAbsolute) && !OmfRead( *FileId, (PVOID)POmfHeader, (ULONG)sizeof(OMF_HDR), &Count ) && OmfHeaderValidate( *FileId ) ) { // // copy version and revision // ((POMF_FAT_FILE_NAME)OmfFatFileName)->Version = POmfHeader->FwVersion; ((POMF_FAT_FILE_NAME)OmfFatFileName)->Revision = POmfHeader->FwRevision; // // OMF ROM initialization has been done // OmfRomOk=TRUE; } } // // Set the current FileId to "open" so that calls to FwOpen won't use // this FileId. This will get reset later. // BlFileTable[ *FileId ].Flags.Open = 1; // // check now if there is any file that upgrate the OFM ROM firmware. // the partitions, specified by the FWSearchPath environment variable, // are searched for files of the following form in the \eisa\omf // subdirectory: // "V".LF"R" // // = EISA Product ID (7 chars) // "V" = version ([0-9],[A-Z]) // "R" = revision ([0-9],[A-Z]) // if ( (PFwSearchPath = FwGetEnvironmentVariable("FWSearchPath")) != NULL ) { // // check all the directories specified by FWSearchPath // while ( GetNextPath( &PFwSearchPath, OmfPathName )) { // // open the directory // strcat(OmfPathName, "\\eisa\\omf" ); if ( FwOpen( OmfPathName, ArcOpenDirectory, &OmfSubdirId )) { // // Go check next path // continue; } // // Check all files within the directory // while (!FwGetDirectoryEntry ( OmfSubdirId, &DirEntBuffer, (ULONG) 1, &Count) ) { // // check directory flag, length of file name and file name // if ( !( DirEntBuffer.FileAttribute & ArcDirectoryFile ) && DirEntBuffer.FileNameLength && MaxOmfFatFiles( OmfFatFileName, DirEntBuffer.FileName )) { // // correct name, save file path // strcat( strcpy(OmfPathBuffer, OmfPathName), "\\" ); strcat(OmfPathBuffer, OmfFatFileName); } } // // close directory before opening the next // FwClose( OmfSubdirId ); } } // // check for a valid OMF FAT file name // if ( OmfPathBuffer[0] ) { // // open file // if (FwOpen(OmfPathBuffer, ArcOpenReadOnly, &POmfHeaderContext->FileId)) { // // return with error // BlFileTable[ *FileId ].Flags.Open = 0; return ENODEV; } POmfHeader->FwSize=0; // max length simulation // // validate header and copy data in the OmfHeaderContext structure // if ( OmfSeek( *FileId, &Offset, SeekAbsolute ) || OmfRead( *FileId, (PVOID)POmfHeader, (ULONG)sizeof(OMF_HDR), &Count) || !OmfHeaderValidate( *FileId ) ) { PRINTDBG("No OK\n\r"); // // close file and return with error // FwClose(POmfHeaderContext->FileId); BlFileTable[ *FileId ].Flags.Open = 0; return ENODEV; } // // OMF FAT file initialization is done. // PRINTDBG("It's OK\n\r"); OmfFatFileOk=TRUE; } // // Reset the open flag. // BlFileTable[ *FileId ].Flags.Open = 0; // // if OMF initialization not done, return error // // if ( !OmfRomOk && !OmfFatFileOk ) if ( !OmfFatFileOk ) { return ENOENT; } else { BlFileTable[ *FileId ].Position.LowPart=0; BlFileTable[ *FileId ].Position.HighPart=0; return ESUCCESS; } } // ---------------------------------------------------------------------------- // PROCEDURE: OmfClose: // // DESCRIPTION: The routine closes the file table entry specified by file id. // If a OMF FAT file has been used, the routine calls the FwClose // function using its file table entry (file id). // the routine uses the following logic : // // if (OMF FAT file) // { // close file; // if (error closing file) // return error; // } // reset open flag; // return ok; // // ARGUMENTS: FileId Supplies a pointer to a variable that specifies // the file table entry. // // RETURN: ESUCCESS is returned if the open operation is successful. // EBADF invalid file descriptor // // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfClose ( IN ULONG FileId ) { // // initialize local variables // ARC_STATUS Status; // store return status from FwClose // // if OMF FAT file is used, call FwClose using its file table index // PRINTDBG("OmfClose\n\r"); if ( BlFileTable[ FileId ].DeviceId != DEVICE_DEVICE) { return EBADF; } if ( BlFileTable[ FileId ].u.OmfHeaderContext.FileId != DEVICE_DEVICE && (Status = FwClose( BlFileTable[ FileId ].u.OmfHeaderContext.FileId))) { return Status; } // // all done, return ok // BlFileTable[ FileId ].Flags.Open = 0; return ESUCCESS; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfMount: // // DESCRIPTION: The routine does nothing and return EBADF. // // ARGUMENTS: MountPath device path specifier. // Operation mount operation (load/unload). // // RETURN: EBADF invalid operation // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfMount ( IN PCHAR MountPath, IN MOUNT_OPERATION Operation ) { // // return error : invalid operation. // return EBADF; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfRead: // // DESCRIPTION: This routine implements the read operation for the ARC-EISA // firmware "OMF" driver. // // ARGUMENTS: FileId Supplies a pointer to a variable that specifies // the file table entry. // Buffer Supplies a pointer to a buffer where the // characters read will be stored. // Length Supplies the length of Buffer. // Count Return the count of the characters that // were read. // // RETURN: ESUCCESS is returned if the open operation is successful. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfRead ( IN ULONG FileId, IN PVOID Buffer, IN ULONG Length, OUT PULONG Count ) { // // initialize local variables // ARC_STATUS Status; // ARC status POMF_HEADER_CONTEXT POmfHeaderContext; // OMF header context pointer ULONG OmfSize; // OMF firmware size (bytes) PLARGE_INTEGER PPosition; // file/device position field pointer USHORT ByteIndex; // byte index within the word ULONG WordBuffer; // 1 word buffer PRINTDBG("OmfRead\n\r"); // // Initialize some variables // POmfHeaderContext = &BlFileTable[ FileId ].u.OmfHeaderContext; // // compute OMF length in bytes // OmfSize = (ULONG)POmfHeaderContext->OmfHeader.FwSize * OMF_BLOCK_SIZE; if ( !OmfSize ) { OmfSize = OMF_MAX_SIZE; } // // initialize byte count read to zero and position variable // *Count = 0; PPosition = &BlFileTable[ FileId ].Position; // // if length is zero or end of "file", return ESUCCESS. // if ( !Length || PPosition->LowPart >= OmfSize ) { return ESUCCESS; } // // adjust length if it is too big. // Length = MIN( Length, OmfSize ); // to prevent the add to overflow if ( PPosition->LowPart + Length > OmfSize ) { Length = OmfSize - PPosition->LowPart; } // // if OMF FAT file, read from file. // if ( POmfHeaderContext->FileId != DEVICE_DEVICE ) { if ( !(Status = FwSeek( POmfHeaderContext->FileId, PPosition, SeekAbsolute )) && !(Status = FwRead( POmfHeaderContext->FileId, Buffer, Length, Count )) ) { PPosition->LowPart += *Count; } return Status; } // // write word index and compute starting byte index (within a word) // WRITE_REGISTER_ULONG( POmfHeaderContext->RomIndex, PPosition->LowPart >> WORD_2P2 ); // // read OMF ROM // one loop per word // while ( Length ) { ByteIndex = (USHORT) (PPosition->LowPart & (1<= (1 << WORD_2P2) ) { *((PULONG)( (PUCHAR)Buffer + *Count ))= READ_REGISTER_ULONG( POmfHeaderContext->RomRead ); *Count += 1<RomRead ); // // read just the selected bytes // while ( ByteIndex < (1 << WORD_2P2) && Length-- ) { *( (PUCHAR)Buffer + *Count++ )= (UCHAR)( WordBuffer >> BITSXBYTE * ByteIndex++ ); } } // // update OMF pointer // PPosition->LowPart += *Count; } // // return all done // return ESUCCESS; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfWrite: // // DESCRIPTION: This routine implements the write operation for the ARC-EISA // firmware "OMF" driver. // // ARGUMENTS: FileId Supplies a pointer to a variable that specifies // the file table entry. // Buffer Supplies a pointer to a buffer where the // characters are read. // Length Supplies the length of Buffer. // Count Return the count of the characters that // were written. // // RETURN: EBADF invalid operation // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfWrite ( IN ULONG FileId, IN PVOID Buffer, IN ULONG Length, OUT PULONG Count ) { // // return error : invalid operation // return EBADF; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfGetReadStatus: // // DESCRIPTION: This routine implements the GetReadStatus operation for the // ARC-EISA firmware "OMF" driver. // // ARGUMENTS: FileId Supplies a pointer to a variable that specifies // the file table entry. // // RETURN: ESUCCESS return always success. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfGetReadStatus ( IN ULONG FileId ) { // // return ok // return ESUCCESS; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfSeek: // // DESCRIPTION: This routine implements the Seek operation for the // ARC-EISA firmware "OMF" driver. // // ARGUMENTS: FileId Supplies a pointer to a variable that specifies // the file table entry. // Offset Supplies the offset in the file to position to. // SeekMode Supplies the mode of the seek operation // // RETURN: ESUCCESS returned if the operation is successful. // EINVAL returned otherwise. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfSeek ( IN ULONG FileId, IN PLARGE_INTEGER Offset, IN SEEK_MODE SeekMode ) { // // local variables // LARGE_INTEGER Point; // New position ULONG OmfSize; // OMF size in bytes PRINTDBG("OmfSeek\n\r"); // // initialize some variables // OmfSize = (ULONG)BlFileTable[ FileId ].u.OmfHeaderContext.OmfHeader.FwSize * OMF_BLOCK_SIZE; if ( !OmfSize ) { OmfSize=OMF_MAX_SIZE; } // // compute new offset value // switch( SeekMode ) { case SeekAbsolute: Point = *Offset; break; case SeekRelative: Point = RtlLargeIntegerAdd( BlFileTable[FileId].Position, *Offset ); break; default: return EINVAL; } // // if the high 32 bits are not zero, return an error. // if new offset is valid, update position field. // if the position value 0-based is equal to the OMF size (1-based), // the EOF has been reached. no error is returned in this case and // the count field is set to zero with ESUCCESS error code for any // successive read operation. note that this combination (ESUCCESS and // count=0) is used to rappresent EOF (end of file). // if ( Point.HighPart || Point.LowPart > OmfSize ) { return EINVAL; } else { BlFileTable[FileId].Position = Point; return ESUCCESS; } } // ---------------------------------------------------------------------------- // PROCEDURE: OmfGetFileInformation: // // DESCRIPTION: This routine implements the GetFileInformation for the // ARC-EISA firmware "OMF" driver. // // ARGUMENTS: FileId Supplies the file table index. // Buffer Supplies the buffer to receive the file // information. Note that it must be large // enough to hold the full file name. // // RETURN: EBADF invalid operation // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfGetFileInformation ( IN ULONG FileId, OUT PFILE_INFORMATION Buffer ) { // // return error : invalid operation // return EBADF; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfSetFileInformation: // // DESCRIPTION: This routine implements the SetFileInformation for the // ARC-EISA firmware "OMF" driver. // // ARGUMENTS: FileId Supplies the file table index. // AttributeFlags Supplies the value (on or off) for each // attribute being modified. // AttributeMask Supplies a mask of the attributes being altered. // All other file attributes are left alone. // // RETURN: EBADF invalid operation // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfSetFileInformation ( IN ULONG FileId, IN ULONG AttributeFlags, IN ULONG AttributeMask ) { // // return error : invalid operation // return EBADF; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfGetDirectoryEntry: // // DESCRIPTION: This routine implements the GetDirectoryEntry for the // ARC-EISA firmware "OMF" driver. // // ARGUMENTS: FileId Supplies the file table index. // DirEntry Pointer to a directory entry structure // NumberDir # of entries to read // Count # of entries read // // RETURN: EBADF directory operations are not supported // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfGetDirectoryEntry ( IN ULONG FileId, IN DIRECTORY_ENTRY *DirEntry, IN ULONG NumberDir, OUT PULONG CountDir ) { // // return error : directory operations are not supported // return EBADF; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileOpen: // // DESCRIPTION: The routine opens the OMF file. // The of the is optional. The caller can // make the following assumptions if the is not // included in the : // . the firmware searches for folders whose type is MIPS first. // This is equivalent to using '.A' as the . If // the requested folder of this type is found in the most recent // OMF, then this folder is used. // . If the modst recent OMF does not contain the requested folder // whose type is MIPS, then the SMF searches for the requested // folder whose type is BINARY. This is equivalent to using '.B' // as the . If the requested folder of this type is // found in the most recent OMF then this folder is used. // . If there are no folders with either type in the most recent // OMF, the operation fails. // // When omf() is used as and the filename is the // string "\", the path specification represents the OMF directory. // The only valid operation to perform on the OMF directory is to // Open it, then use FwGetDirectoryEntry to enumerate the folders // within the OMF, and then Close it. For example, to // enumerate all folders that are containded in the OMF of a // serail options board that was in slot 3 of EISA bus0, create // and Open a path as follows : eisa(0)serial(3)omf()\ . // To open the diagnostic folder for the above EISA option board // the system utilty would create and Open the path specification : // eisa(0)serial(3)omf()\T-SERIAL. // // // ARGUMENTS: OpenPath Supplies a pointer to a zero terminated OMF // file name. // OpenMode Supplies the mode of the open. // FileId Supplies the file table entry index // // RETURN: ESUCCESS is returned if the open operation is successful. // ENOENT the named device or file does not exist. // // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfFileOpen ( IN PCHAR OpenPath, IN OPEN_MODE OpenMode, IN OUT PULONG FileId ) { // // initialize local variables // ARC_STATUS Status; // ARC status ULONG DeviceId; // device table entry index POMF_DIR_ENT POmfDirEnt; // OMF directory entry pointer POMF_HDR POmfHeader; // OMF header pointer LARGE_INTEGER AbsolutePosition; // position ULONG TypeIndex,DirIndex; // general indexes ULONG Count; // # of bytes transferred CHAR OmfFileName[OMF_FILE_NAME_LEN]; // folder name BOOLEAN SearchSucceeded = FALSE; // match flag BOOLEAN IsDirectory = FALSE; // directory flag CHAR OmfType[] = {'A','B','\0'}; // default sequance of search: // relocatable MIPS I object // format binary data format // end of chain PRINTDBG("OmfFileOpen\n\r"); // debug support // // Initialize some variables // DeviceId = BlFileTable[ *FileId ].DeviceId; POmfDirEnt = &BlFileTable[ *FileId ].u.OmfFileContext.OmfDirEnt; POmfHeader = &BlFileTable[ DeviceId ].u.OmfHeaderContext.OmfHeader; AbsolutePosition.HighPart=0; // for seek operations // // initialize the file/directory pointer to zero // BlFileTable[ *FileId ].Position.LowPart=0; BlFileTable[ *FileId ].Position.HighPart=0; // // the first char must be the directory char, otherwise it's an error // if ( *OpenPath++ != '\\' ); // // else check if the open is for the root directory // else if ( *OpenPath == '\0' ) { POmfDirEnt->FolderName[0]='\0'; SearchSucceeded = TRUE; IsDirectory = TRUE; } // // else validate OMF file name // else if ( !OmfFileNameValidate( OpenPath, OmfFileName, OmfType )); // // then search the specified file name // else { // // save the omf file name // strcpy( BlFileTable[ *FileId ].FileName, OpenPath ); BlFileTable[ *FileId ].FileNameLength = strlen( OpenPath ); // // one loop per file // for (TypeIndex = 0; !SearchSucceeded && OmfType[TypeIndex]; TypeIndex++) { // // search the directory for the specified OMF file name // for ( DirIndex = 0, AbsolutePosition.LowPart = POmfHeader->FolderDirectoryLink << WORD_2P2; DirIndex < POmfHeader->FolderCount && !SearchSucceeded; DirIndex++, AbsolutePosition.LowPart += sizeof(OMF_DIR_ENT) ) { // // exit if error during seek or read. // if ((Status = FwSeek(DeviceId, &AbsolutePosition, SeekAbsolute)) || (Status = FwRead(DeviceId, (PVOID)POmfDirEnt, (ULONG)sizeof(OMF_DIR_ENT), &Count ))) { return Status; } // // check OMF file name // SearchSucceeded = CmpOmfFiles( OmfFileName, OmfType[TypeIndex], (PVOID)POmfDirEnt ); } } // // if the search has been successful, validate file's header // if (SearchSucceeded && !OmfFileValidate( *FileId )) { SearchSucceeded = FALSE; } } // // At this point we've cracked the name up to (an maybe including the last // component). We located the last component if the SearchSucceeded flag // is true, otherwise the last component does not exist. If we located // the last component then this is like an open or a supersede, but not a // create. // if (SearchSucceeded) { // // Check if the last component is a directory // if (IsDirectory) { // // For an existing directory the only valid open mode is // OpenDirectory all other modes return an error // switch (OpenMode) { case ArcOpenReadOnly: case ArcOpenWriteOnly: case ArcOpenReadWrite: case ArcCreateWriteOnly: case ArcCreateReadWrite: case ArcSupersedeWriteOnly: case ArcSupersedeReadWrite: // // if we reach here then the caller got a directory but // didn't want to open a directory // return EISDIR; case ArcOpenDirectory: // // if we reach here then the caller got a directory and // wanted to open a directory. // BlFileTable[ *FileId ].Flags.Open = 1; BlFileTable[ *FileId ].Flags.Read = 1; return ESUCCESS; case ArcCreateDirectory: // // if we reach here then the caller got a directory and // wanted to create a new directory // return EACCES; default: // // invalid open mode // return EINVAL; } } // // If we get there then we have an existing file that is being opened. // We can open existing files only read only. // switch (OpenMode) { case ArcOpenReadOnly: // // if we reach here then the user got a file and wanted to // open the file read only // BlFileTable[ *FileId ].Flags.Open = 1; BlFileTable[ *FileId ].Flags.Read = 1; return ESUCCESS; case ArcOpenWriteOnly: case ArcOpenReadWrite: case ArcCreateWriteOnly: case ArcCreateReadWrite: case ArcSupersedeWriteOnly: case ArcSupersedeReadWrite: // // if we reach here then we are trying to open a read only // device for write. // return EROFS; case ArcOpenDirectory: case ArcCreateDirectory: // // if we reach here then the user got a file and wanted a // directory // return ENOTDIR; default: // // invalid open mode // return EINVAL; } } // // If we get here the last component does not exist so we are trying to // create either a new file or a directory. // switch (OpenMode) { case ArcOpenReadOnly: case ArcOpenWriteOnly: case ArcOpenReadWrite: case ArcOpenDirectory: // // if we reach here then the user did not get a file but wanted // a file // return ENOENT; case ArcCreateWriteOnly: case ArcSupersedeWriteOnly: case ArcCreateReadWrite: case ArcSupersedeReadWrite: case ArcCreateDirectory: // // if we get hre the user wants to create something. // return EROFS; default: // // invalid open mode // return EINVAL; } } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileClose: // // DESCRIPTION: The routine closes the file table entry specified by file id. // // ARGUMENTS: FileId Supplies the file table index. // // RETURN: ESUCCESS is returned if the open operation is successful. // // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfFileClose ( IN ULONG FileId ) { PRINTDBG("OmfFileClose\n\r"); // // clear flag and exit // BlFileTable[FileId].Flags.Open = 0; return ESUCCESS; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileMount: // // DESCRIPTION: The routine does nothing and return EBADF. // // ARGUMENTS: MountPath device path specifier. // Operation mount operation (load/unload). // // RETURN: EBADF invalid operation // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfFileMount ( IN PCHAR MountPath, IN MOUNT_OPERATION Operation ) { // // return error : invalid operation. // return EBADF; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileGetReadStatus // // DESCRIPTION: This routine implements the GetReadStatus operation for the // ARC-EISA firmware OMF file. // // ARGUMENTS: FileId Supplies a pointer to a variable that specifies // the file table entry. // // RETURN: ESUCCESS return always success. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfFileGetReadStatus ( IN ULONG FileId ) { // // return ok // return ESUCCESS; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileRead: // // DESCRIPTION: This routine implements the read operation for the ARC-EISA // firmware "OMF" driver. // // ARGUMENTS: FileId Supplies the file table index. // Buffer Supplies a pointer to a buffer where the // characters read will be stored. // Length Supplies the length of Buffer. // Count Return the count of the characters that // were read. // // RETURN: ESUCCESS is returned if the open operation is successful. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfFileRead ( IN ULONG FileId, IN PVOID Buffer, IN ULONG Length, OUT PULONG Count ) { // // initialize local variables // ARC_STATUS Status; // ARC status POMF_DIR_ENT POmfDirEnt; // OMF directory entry pointer LARGE_INTEGER AbsolutePosition; // OMF file, logical pointer ULONG OmfFileSize; // OMF file size in bytes PRINTDBG("OmfFileRead\n\r"); // // initialize some variables // POmfDirEnt = &BlFileTable[ FileId ].u.OmfFileContext.OmfDirEnt; // // if directory entry, exit with error // if ( !POmfDirEnt->FolderName[0] ) { return EBADF; // check this error code "EGI_Q" } // // initialize byte count read to zero // *Count=0; OmfFileSize = POmfDirEnt->FolderSize << WORD_2P2; // // if length is zero or EOF (end of file), return ESUCCESS. // if (!Length || BlFileTable[FileId].Position.LowPart >= OmfFileSize) { return ESUCCESS; } // // adjust length if it is too big. // Length = MIN( Length, OmfFileSize ); // to prevent the add to overflow if ( BlFileTable[ FileId ].Position.LowPart + Length > OmfFileSize ) { Length = OmfFileSize - BlFileTable[ FileId ].Position.LowPart; } // // find OMF absolute offset from OMF file absolute offset // AbsolutePosition.HighPart = 0; AbsolutePosition.LowPart = BlFileTable[ FileId ].Position.LowPart + ( POmfDirEnt->FolderLink << WORD_2P2 ); // // seek + read command // if ( (Status = FwSeek( BlFileTable[ FileId ].DeviceId, &AbsolutePosition, SeekAbsolute )) || (Status = FwRead( BlFileTable[FileId].DeviceId, Buffer, Length, Count )) ) { return Status; } // // update file pointer and exit // BlFileTable[FileId].Position.LowPart += *Count; return ESUCCESS; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileWrite: // // DESCRIPTION: This routine implements the write operation for the ARC-EISA // firmware "OMF" driver. // // ARGUMENTS: FileId Supplies the file table index. // Buffer Supplies a pointer to a buffer where the // characters are read. // Length Supplies the length of Buffer. // Count Return the count of the characters that // were written. // // RETURN: EBADF invalid operation // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfFileWrite ( IN ULONG FileId, IN PVOID Buffer, IN ULONG Length, OUT PULONG Count ) { // // return error : invalid operation // return EBADF; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileSeek: // // DESCRIPTION: This routine implements the Seek operation for the // ARC-EISA firmware "OMF" driver. // // ARGUMENTS: FileId Supplies the file table index. // Offset Supplies the offset in the file to position to. // SeekMode Supplies the mode of the seek operation // // RETURN: ESUCCESS returned if the operation is successful. // EINVAL returned otherwise. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfFileSeek ( IN ULONG FileId, IN PLARGE_INTEGER Offset, IN SEEK_MODE SeekMode ) { // // local variables // LARGE_INTEGER Point; // New position POMF_DIR_ENT POmfDirEnt; // OMF directory entry pointer PRINTDBG("OmfFileSeek\n\r"); // // initialize some variables // POmfDirEnt = &BlFileTable[ FileId ].u.OmfFileContext.OmfDirEnt; // // The offset parameter must be zero, if directory entry. // if ( !POmfDirEnt->FolderName[0] && ( Offset->LowPart || Offset->HighPart )) { return EINVAL; } // // compute new offset value // switch(SeekMode) { case SeekAbsolute: Point = *Offset; break; case SeekRelative: Point = RtlLargeIntegerAdd( BlFileTable[FileId].Position, *Offset ); break; default: return EINVAL; } // // if new offset is valid, update position field. // if the position value 0-based is equal to the OMF size (1-based), // the EOF has been reached. no error is returned in this case and // the count field is set to zero with ESUCCESS error code for any // successive read operation. note that this combination (ESUCCESS and // count=0) is used to rappresent EOF (end of file). // if ( POmfDirEnt->FolderName[0] && (Point.HighPart || Point.LowPart > POmfDirEnt->FolderSize << WORD_2P2)) { return EINVAL; } else { BlFileTable[ FileId ].Position = Point; return ESUCCESS; } } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileGetFileInformation: // // DESCRIPTION: This routine implements the GetFileInformation for the // ARC-EISA firmware "OMF" driver. // // ARGUMENTS: FileId Supplies the file table index. // Buffer Supplies the buffer to receive the file // information. Note that it must be large // enough to hold the full file name. // // RETURN: EBADF invalid operation // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfFileGetFileInformation ( IN ULONG FileId, OUT PFILE_INFORMATION Buffer ) { // // define local variable // PBL_FILE_TABLE FileTableEntry = &BlFileTable[ FileId ]; PRINTDBG("OmfFileGetFileInformation\n\r"); // // if root, exit with error // if ( !FileTableEntry->u.OmfFileContext.OmfDirEnt.FolderName[0] ) { return EBADF; } // // set output fields // RtlZeroMemory(Buffer, sizeof(FILE_INFORMATION)); // // ending address (high part is already zero) and current address // Buffer->EndingAddress.LowPart = FileTableEntry->u.OmfFileContext.OmfDirEnt.FolderSize << WORD_2P2; Buffer->CurrentPosition.LowPart = FileTableEntry->Position.LowPart; Buffer->CurrentPosition.HighPart = FileTableEntry->Position.HighPart; // // device type // Buffer->Type = OtherPeripheral; // // file name length, attributes and file name string // Buffer->FileNameLength = FileTableEntry->FileNameLength; Buffer->Attributes = ArcReadOnlyFile; strcpy( Buffer->FileName, FileTableEntry->FileName ); // // all done // return ESUCCESS; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileSetFileInformation: // // DESCRIPTION: This routine implements the SetFileInformation for the // ARC-EISA firmware "OMF" driver. // // ARGUMENTS: FileId Supplies the file table index. // AttributeFlags Supplies the value (on or off) for each // attribute being modified. // AttributeMask Supplies a mask of the attributes being altered. // All other file attributes are left alone. // // RETURN: EBADF invalid operation // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfFileSetFileInformation ( IN ULONG FileId, IN ULONG AttributeFlags, IN ULONG AttributeMask ) { // // return error : invalid operation // return EROFS; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileGetDirectoryEntry: // // DESCRIPTION: This routine implements the GetDirectoryEntry for the // ARC-EISA firmware "OMF" driver. // // ARGUMENTS: FileId Supplies the file table index. // DirEntry Pointer to a directory entry structure // NumberDir # of entries to read // Count # of entries read // // RETURN: ESUCCESS returned if the operation is successful. // EINVAL returned otherwise. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // ARC_STATUS OmfFileGetDirectoryEntry ( IN ULONG FileId, IN DIRECTORY_ENTRY *DirEntry, IN ULONG NumberDir, OUT PULONG CountDir ) { // // initialize local variables // ARC_STATUS Status; // ARC status ULONG DeviceId; // file table entry for the device POMF_HDR POmfHeader; // pointer to OMF ROM/FAT file header ULONG CurrentDir; // current directory entry LARGE_INTEGER AbsolutePosition; // OMF file, pointer of logical pointer OMF_DIR_ENT OmfFileBuffer; // buffer for directory entries ULONG Count; // # of bytes read PRINTDBG("OmfFileGetDirectoryEntry\n\r"); // // if not directory entry, exit with error // if ( BlFileTable[ FileId ].u.OmfFileContext.OmfDirEnt.FolderName[0] ) { return EBADF; } // // Initialize the output count to zero // *CountDir=0; // // if NumberDir is zero, return ESUCCESS. // if ( !NumberDir ) { return ESUCCESS; } // // initialize variables // Count=0; DeviceId = BlFileTable[ FileId ].DeviceId; POmfHeader = &BlFileTable[ DeviceId ].u.OmfHeaderContext.OmfHeader; CurrentDir = BlFileTable[ FileId ].Position.LowPart/sizeof(OMF_DIR_ENT); // // if no more entries, return ENOTDIR // if ( CurrentDir >= POmfHeader->FolderCount ) { return ENOTDIR; } // // adjust count if it is too big. // NumberDir = MIN( NumberDir, POmfHeader->FolderCount ); //avoid add overflow if ( CurrentDir + NumberDir > POmfHeader->FolderCount ) { NumberDir = POmfHeader->FolderCount - CurrentDir; } // // find OMF absolute offset from OMF file absolute offset // AbsolutePosition.HighPart = 0; AbsolutePosition.LowPart = BlFileTable[FileId].Position.LowPart + (POmfHeader->FolderDirectoryLink<Version; MasterRevision = PointerMaster->Revision; // // save version and revision checked values // PointerChecked = (POMF_FAT_FILE_NAME)CheckedName; CheckedVersion = PointerChecked->Version; CheckedRevision = PointerChecked->Revision; PointerChecked->Version = MasterVersion; PointerChecked->Revision = MasterRevision; // // update name if new version for the same product Id // if (strcmp(MasterName, CheckedName) || CheckedVersionVersion = CheckedVersion; PointerMaster->Revision = CheckedRevision; return TRUE; } } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileNameValidate: // // DESCRIPTION: The routine validates the requested OMF file name. // The name is decomposed in Folder Name and Folder Type. // // ARGUMENTS: OpenPath Supplies a pointer to a zero terminated OMF // file name. // OmfFileName Supplies a pointer to an array used to store // the Folder Name. // OmfType Supplies a pointer to an array used to store // the Folder Types. // // RETURN: TRUE is returned if the operation succeed. // FALSE is returned if the OpenPath is incorrect. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // BOOLEAN OmfFileNameValidate ( IN PCHAR OpenPath, OUT PCHAR OmfFileName, OUT PCHAR OmfType ) { // // Define variables // ULONG NameIndex; // general index PRINTDBG("OmfFileNameValidate\n\r"); // // name validation // for ( NameIndex = 0; NameIndex < OMF_FILE_NAME_LEN && *OpenPath && *OpenPath != '.'; NameIndex++ ) { if ( isupper( *OpenPath ) // upper case letter || isdigit( *OpenPath ) // digit || *OpenPath=='-' // '-' minus || (*OpenPath=='$' && NameIndex==0) // $ char in 1st position ) { *OmfFileName++=*OpenPath++; } else { return FALSE; } } // // return error if name length > of OMF_FILE_NAME_LEN // if ( NameIndex == OMF_FILE_NAME_LEN && *OpenPath && *OpenPath != '.') { return FALSE; } // // fill right with null chars ('\0') if Folder Name is less than 12 chars // while( NameIndex++ < OMF_FILE_NAME_LEN ) { *OmfFileName++='\0'; } // // extension validation // if ( *OpenPath++ && *OpenPath ) // skip "null", ".null" { switch( *OpenPath ) // check type field { case 'A': case 'B': *OmfType++ = *OpenPath++; *OmfType = '\0'; // means : end of types break; default: return FALSE; } if( *OpenPath ) // error if more chars { return FALSE; } } // // all done, return ok // return TRUE; } // ---------------------------------------------------------------------------- // PROCEDURE: CmpOmfFiles: // // DESCRIPTION: The routine checks if the selected directory entry has the // requested OMF file name. // // ARGUMENTS: OmfFileName Requested OMF file name pointer. // OmfType Requested OMF file type pointer. // POmfDirEnt Directory entry to check. // // RETURN: TRUE is returned if the operation succeed. // FALSE is returned if the name or type doesn't match. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // BOOLEAN CmpOmfFiles ( IN PCHAR OmfFileName, IN CHAR OmfType, IN POMF_DIR_ENT POmfDirEnt ) { // // Define variables // ULONG NameIndex; // general index PRINTDBG("CmpOmfFiles\n\r"); // // check name // for ( NameIndex=0; NameIndex < OMF_FILE_NAME_LEN; NameIndex++ ) { if ( OmfFileName[ NameIndex ] != POmfDirEnt->FolderName[ NameIndex ] ) { return FALSE; } } // // check extension // if ( OmfType != POmfDirEnt->FolderType ) { return FALSE; } // // all done, return ok // return TRUE; } // ---------------------------------------------------------------------------- // PROCEDURE: OmfHeaderValidate: // // DESCRIPTION: The routine checks if the specified OMF header data is valid. // // ARGUMENTS: FileId file table entry index // // RETURN: TRUE is returned if file is ok. // FALSE is returned if file is not correct. // // ASSUMPTIONS: The header data has already been copied in the // context data of the file table entry. // The size of all the OMF structures is a multiple of a word. // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // BOOLEAN OmfHeaderValidate ( IN ULONG FileId ) { // // local variables // POMF_HDR POmfHeader; // pointer to the header data ULONG OmfDirLink; // directory link in words ULONG OmfDirLength; // directory size in words ULONG OmfSize; // OMF size in bytes UCHAR Checksum=0; // used to compute the checksum PRINTDBG("OmfHeaderValidate\n\r"); // // initialize variables // POmfHeader = &BlFileTable[FileId].u.OmfHeaderContext.OmfHeader; OmfDirLink = POmfHeader->FolderDirectoryLink; OmfDirLength =(POmfHeader->FolderCount * sizeof(OMF_DIR_ENT))/(1<FwSize * OMF_BLOCK_SIZE; if (!OmfSize) { OmfSize = OMF_MAX_SIZE; } // // check header values // if ( POmfHeader->ID[0] != OMF_ID_1ST || POmfHeader->ID[1] != OMF_ID_2ND || POmfHeader->ID[2] != OMF_ID_3RD || POmfHeader->ID[3] != OMF_ID_4TH || !isalnum(POmfHeader->FwVersion) || !isalnum(POmfHeader->FwRevision) || sizeof(OMF_HDR) > OmfSize || OmfDirLink + OmfDirLength > OmfSize/(1<>> FIXME <<< // || // Checksum ) { return FALSE; } else { return TRUE; } } // ---------------------------------------------------------------------------- // PROCEDURE: OmfFileValidate: // // DESCRIPTION: The routine checks if the selected file is valid. // // ARGUMENTS: FileId file table entry index // // RETURN: TRUE is returned if file is ok. // FALSE is returned if file is not correct. // // ASSUMPTIONS: the folder name and its extension (type) have already // been validated. // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // BOOLEAN OmfFileValidate ( IN ULONG FileId ) { // // local variables // POMF_DIR_ENT POmfDirEnt; // OMF directory entry pointer ULONG OmfFileLength; // file length, word count ULONG OmfFileLink; // file link, word count ULONG DeviceId; // device id file table entry ULONG OmfLength; // OMF rom length, word count UCHAR Checksum=0; // used to compute the checksum PRINTDBG("OmfFileValidate\n\r"); // // initialize variables // POmfDirEnt = &BlFileTable[FileId].u.OmfFileContext.OmfDirEnt; OmfFileLink = POmfDirEnt->FolderLink; OmfFileLength = POmfDirEnt->FolderSize; DeviceId = BlFileTable[FileId].DeviceId; OmfLength=(ULONG)BlFileTable[DeviceId].u.OmfHeaderContext.OmfHeader.FwSize * OMF_BLOCK_SIZE/(1< OMF_MAX_FILE_LINK || OmfFileLength > OMF_MAX_FILE_LEN || OmfFileLink + OmfFileLength > OmfLength || FwFileIdChecksum( DeviceId, RtlConvertUlongToLargeInteger(OmfFileLink<>> FIXME <<< // || // (Checksum += POmfDirEnt->FolderChecksumByte) ) { return FALSE; } else { return TRUE; } } // ---------------------------------------------------------------------------- // PROCEDURE: ConvertOmfDirToArcDir: // // DESCRIPTION: The routine converts the OMF directory entry in the ARC // directory entry format. // // ARGUMENTS: OmfFileBuffer pointer to OMF directory entry // DirEntry pointer to ARC directory entry to be filled // // RETURN: NONE // // ASSUMPTIONS: FileNameLengthMax is at least 3 chars. // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // VOID ConvertOmfDirToArcDir ( IN POMF_DIR_ENT POmfDirEnt, OUT DIRECTORY_ENTRY *PArcDirEnt ) { // // local variables // ULONG CharIndex; // name+extension length ULONG MaxFileName; // max name length PRINTDBG("ConvertOmfDirToArcDir\n\r"); // // set attribute bit (read only file) // PArcDirEnt->FileAttribute = ArcReadOnlyFile; // // set file name (note that 3 means: '.' + extension + '\0' ) // MaxFileName = MIN( 32 - 3, OMF_FILE_NAME_LEN ); for ( CharIndex = 0; CharIndex < MaxFileName && POmfDirEnt->FolderName[ CharIndex ]; CharIndex++ ) { PArcDirEnt->FileName[ CharIndex ] = POmfDirEnt->FolderName[ CharIndex]; } // // dot '.' // PArcDirEnt->FileName[ CharIndex++ ] = '.'; // // extension // PArcDirEnt->FileName[ CharIndex++ ] = POmfDirEnt->FolderType; // // null char // PArcDirEnt->FileName[ CharIndex ]='\0'; // // set length (note: CharIndex is 0-based) // PArcDirEnt->FileNameLength = CharIndex; // // all done, exit. // return; } // ---------------------------------------------------------------------------- // PROCEDURE: FwGetEisaId: // // DESCRIPTION: The routine returns the requested board and info id. // // ARGUMENTS: PathName Option board path name pointer // EisaId Pointer to 7 bytes space for the id // IdInfo Pointer to 1 byte space for the info id // // RETURN: TRUE all done. // FALSE for any error. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // BOOLEAN FwGetEisaId ( IN PCHAR PathName, OUT PCHAR EisaId, OUT PUCHAR IdInfo ) { // // define local variables // PCONFIGURATION_COMPONENT pComp; // Pointer to a component struc EISA_SLOT_INFO SlotInfo; // pointer to first eisa info BOOLEAN GetIdStatus = FALSE; // be pessimistic PRINTDBG("FwGetEisaId\n\r"); // DEBUG SUPPORT // // Check to see if the motherboard component is being accessed. Since // Jazz doesn't have a motherboard id, substitute values. // if (strstr(PathName, "eisa(0)other(0)") != NULL) { EisaId[0] = 'J'; EisaId[1] = 'A'; EisaId[2] = 'Z'; EisaId[3] = '0'; EisaId[4] = '0'; EisaId[5] = '0'; EisaId[6] = '0'; *IdInfo = 0; GetIdStatus = TRUE; // // get the requested component // } else if ( (pComp = FwGetComponent(PathName)) == NULL ); // // check the configuration data length // else if ( pComp->ConfigurationDataLength < EISA_SLOT_MIN_INFO ); // // get the slot info // else if ( FwGetConfigurationDataIndex( (PVOID)&SlotInfo, pComp, CONFIGDATAHEADER_SIZE, EISA_SLOT_INFO_SIZE )); // // get the requested info // else { FwUncompressEisaId( &SlotInfo.Id1stChar, EisaId ); *IdInfo = SlotInfo.IdInfo; GetIdStatus = TRUE; } // // return status // return GetIdStatus; } // ---------------------------------------------------------------------------- // PROCEDURE: FwUncompressEisaId: // // DESCRIPTION: The routine converts the specified compressed ID in 7 ASCII // chars. // // ARGUMENTS: CompEisaId Pointer to the compressed ID (4 bytes) // UncompEisaId Pointer to the uncompressed ID (7 bytes) // // RETURN: none // // ASSUMPTIONS: Compressed ID : 1st byte bit 7 - Reserved // bits 6-2 - 1st char name comp // bits 1-0 - 2nd char name comp // 2nd byte bits 7-5 - 2nd char name // bits 4-0 - 3rd char name comp // 3rd byte bits 7-4 - 1st decimal number comp // bits 3-0 - 2nd decimal number comp // 4th byte bits 7-4 - 3rd decimal number comp // bits 3-0 - 4th decimal number comp // // Uncompressed ID: 1st byte 1st char name // 2nd byte 2nd char name // 3rd byte 3rd char name // 4th byte 1st decimal number // 5th byte 2nd decimal number // 6th byte 3rd decimal number // 7th byte 4th decimal number // // Compressed -> Uncompressed : // // char comp + 'A' - 1 = char uncompressed // decimal comp + '0' = decimal uncompressed // // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // VOID FwUncompressEisaId ( IN PUCHAR CompEisaId, OUT PUCHAR UncompEisaId ) { // // local variables // ULONG Id; // used to hold the 4 bytes ID SHORT i; // general index UCHAR d; // hexadecimal digit PRINTDBG("FwUncompressEisaId\n\r"); // // transform the 4 chars ID in a ULONG // Id = Fw4UcharToUlongMSB( CompEisaId ); // // uncompress 4 digits, starting from the last one // for (i=3; i>=0; i--) { d = Id & ID_DIGIT_MASK; UncompEisaId[3+i] = (d <= 9) ? (d + '0') : (d - 0xA + 'A'); Id >>= ID_DIGIT_SIZE; } // // uncompress 3 chars // for (i=2; i>=0; i--) { UncompEisaId[i] = (Id & ID_CHAR_MASK) + 'A' - 1; Id >>= ID_CHAR_SIZE; } // // exit // return; } // ---------------------------------------------------------------------------- // PROCEDURE: FwGetEisaBusIoCpuAddress: // // DESCRIPTION: The routine returns the virtual (CPU) address for the specified // EISA bus. // // ARGUMENTS: EisaPath pointer to the path string // IoBusAddress pointer to a PVOID variable. It used to store // the computed address. // // RETURN: TRUE returned if all correct. // FALSE returned for any error. // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // BOOLEAN FwGetEisaBusIoCpuAddress ( IN PCHAR EisaPath, OUT PVOID *IoBusAddress ) { // // define local variables // PCONFIGURATION_COMPONENT PComponent; EISA_ADAPTER_DETAILS EisaInfo; PRINTDBG("FwGetEisaBusIoCpuAddress\n\r"); // // get the requested component and configuration data // if ( (PComponent = FwGetComponent( EisaPath )) == NULL || FwGetConfigurationData( (PVOID)&EisaInfo, PComponent )) { return FALSE; } // // Return the requested virtual (CPU) address // *IoBusAddress = EisaInfo.IoStart; return TRUE; } // ---------------------------------------------------------------------------- // PROCEDURE: FwFileChecksum: // // DESCRIPTION: The routine performs a byte checksum on the specified file. // // ARGUMENTS: Path File path // Checksum File checksum // // RETURN: ESUCCESS Operation completed successfully. // ...other Error code. // // ASSUMPTIONS: none // // CALLS: FwFileIdChecksum // // GLOBALS: none // // NOTES: The file length must be contained in a ULONG (4G -1). // ---------------------------------------------------------------------------- // ARC_STATUS FwFileChecksum ( IN PCHAR Path, OUT PUCHAR Checksum ) { ARC_STATUS Status; ULONG FileId; FILE_INFORMATION FileInfo; // // initialize checksum to zero // *Checksum = 0; // // open file // if (Status = FwOpen( Path, ArcOpenReadOnly, &FileId )) { return Status; } // // get file information // if (Status = FwGetFileInformation( FileId, &FileInfo )); // // return an error if file is greater than 4G - 1 // else if (FileInfo.EndingAddress.HighPart != 0) { Status = EINVAL; } // // perform the checksum and return the status // else { Status = FwFileIdChecksum( FileId, FileInfo.StartingAddress, FileInfo.EndingAddress.LowPart, Checksum ); } // // clase file and return status // FwClose( FileId ); return Status; } // ---------------------------------------------------------------------------- // PROCEDURE: FwChecksumByte: // // DESCRIPTION: The routine performs a byte checksum on the specified buffer. // // ARGUMENTS: Buffer Pointer to area to checksum. // Length Length of area to checksum (bytes). // ChecksumByte The pointed byte is used in input as a // starting checksum value and in output as // the final checksum value. // // RETURN: ESUCCESS operation completed successfully // // ASSUMPTIONS: none // // CALLS: none // // GLOBALS: none // // NOTES: none // // ---------------------------------------------------------------------------- // ARC_STATUS FwChecksumByte ( IN PUCHAR Buffer, IN ULONG Length, IN OUT PUCHAR ChecksumByte ) { // // checksum the buffer and exit // while (Length--) { *ChecksumByte += *Buffer++; } return ESUCCESS; } // ---------------------------------------------------------------------------- // PROCEDURE: FwFileIdChecksum: // // DESCRIPTION: The routine performs a byte checksum within the spcified // range of the FileId. // // ARGUMENTS: FileId File table entry index. // StartingOffset Beginning of checksum range (byte offset). // Length Number of bytes to checksum. // Checksum Input : start checksum value // Output: image checksum // // RETURN: ESUCCESS Operation completed successfully. // ...other Error code. // // ASSUMPTIONS: none // // CALLS: FwChecksumByte // // GLOBALS: none // // NOTES: This routine can also be called during the "open" phase // (the open bit is not set), because the read and seek functions // are called directly using the table within the file id // descriptor. // ---------------------------------------------------------------------------- // ARC_STATUS FwFileIdChecksum ( IN ULONG FileId, IN LARGE_INTEGER StartingOffset, IN ULONG Length, IN OUT PUCHAR Checksum ) { ARC_STATUS Status; ULONG BytesToRead; ULONG Count; UCHAR TempBuffer[MAXIMUM_SECTOR_SIZE + MAX_DCACHE_LINE_SIZE]; PUCHAR TempPointer = ALIGN_BUFFER( TempBuffer ); // // If buffer length is zero, return ESUCCESS // if (Length==0) { return ESUCCESS; } // // position the file pointer // if (Status = (BlFileTable[FileId].DeviceEntryTable->Seek) (FileId, &StartingOffset, SeekAbsolute)) { return Status; } // // perform the checksum // do { BytesToRead = MIN( Length, MAXIMUM_SECTOR_SIZE ); // // fill the buffer // if (Status = (BlFileTable[FileId].DeviceEntryTable->Read) (FileId, TempPointer, BytesToRead, &Count)) { return Status; } // // make sure that we got the requested number of bytes // if (Count != BytesToRead) { return EINVAL; } // // checksum the area // FwChecksumByte( TempPointer, BytesToRead, Checksum); } while ( Length -= BytesToRead ); // // all done // return Status; } // ---------------------------------------------------------------------------- // PROCEDURE: FwGetMnemonicKey; // // DESCRIPTION: The routine returns the specified key. The specified key // within the path string must be in digits, an error is returned // otherwise. // // ARGUMENTS: Path pointer to the pathname string // Mnemonic mnemonic string // Key pointer to buffer used to hold the ouput // // RETURN: TRUE returned if all correct // FALSE returned invalid input parameter // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // BOOLEAN FwGetMnemonicKey ( IN PCHAR Path, IN PCHAR Mnemonic, IN PULONG Key ) { PCHAR Tmp; PCHAR Tmp2; CHAR Digits[ KEY_MAX_DIGITS + 1 ]; ULONG i; CHAR String[ MAX_MNEMONIC_LEN + 3 ]; // mnemonic + ')' + '(' + '\0' PRINTDBG("FwGetMnemonicKey\n\r"); // // Construct a string of the form ")mnemonic(" // String[0]=')'; for(i=1; *Mnemonic; i++) { String[i] = * Mnemonic++; } String[i++]='('; String[i]='\0'; // // first look for the "mnemonic(" string. // if ( (Tmp = strstr( Path, &String[1] )) == NULL) { return FALSE; } // // if not the begin of the path name, look for the ")mnemonic(" string. // if (Tmp != Path) { if ( (Tmp = strstr( Path, String )) == NULL) { return FALSE; } } else { i--; } // // skip the mnemonic // Tmp+=i; // // make sure that the number of digits is within the allowed range // if ((Tmp2 = strchr(Tmp, ')')) == NULL || Tmp2 - Tmp > KEY_MAX_DIGITS ) { return FALSE; } // // convert the value in between parentesis to integer // for ( i=0; *Tmp != ')'; i++ ) { if ( !isdigit( Digits[i] = *Tmp++ )) { return FALSE; } } Digits[i]='\0'; // // return the converted number // *Key = i ? atoi(Digits) : 0; return TRUE; } // ---------------------------------------------------------------------------- // PROCEDURE: FwGetNextMnemonic: // // DESCRIPTION: The routine returns the next mnemonic in the list. // If Mnemonic is a null string, the first mnemonic of the list // is returned. The FALSE value is returned if the specified // mnemonic is not present or end of list. // // // ARGUMENTS: Path pointer to the pathname string. // Mnemonic mnemonic string pointer // NextMnemonic next mnemonic string pointer // // RETURN: TRUE returned if all correct // FALSE returned if invalid input parameter or end of // list // // ASSUMPTIONS: The path is composed by ARC mnemonic names as follows: // adapter(.)..adapter(.)controller(.)peripheral(.)'\0'. // The NextMnemonic string is big enough to hold the mnemonic // name. // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // BOOLEAN FwGetNextMnemonic ( IN PCHAR Path, IN PCHAR Mnemonic, OUT PCHAR NextMnemonic ) { // // local variables // PCHAR Tmp = Path; PCHAR Tmp2; ULONG i; CHAR String[ MAX_MNEMONIC_LEN + 3 ]; // mnemonic + ')' + '(' + '\0' PRINTDBG("FwGetNextMnemonic\n\r"); if ( *Mnemonic ) { // // Construct a string of the form ")mnemonic(" // String[0]=')'; for(i=1; *Mnemonic; i++) { String[i] = *Mnemonic++; } String[i++]='('; String[i]='\0'; // // first look for the "mnemonic(" string. // if ( (Tmp = strstr( Path, &String[1] )) == NULL) { return FALSE; } // // if not the begin of the path name, look for the ")mnemonic(" string. // if (Tmp != Path) { if ( (Tmp = strstr( Path, String )) == NULL) { return FALSE; } Tmp++; } // // return an error if there is another mnemonic with same name // if (strstr( Tmp, String ) != NULL) { return FALSE; } // // find the start of the next mnemonic // if ( (Tmp = strchr(Tmp,')')) == NULL ) { return FALSE; } Tmp++; } // // find the end of the next mnemonic and copy it. // if ( (Tmp2 = strchr(Tmp,'(')) == NULL || Tmp2 == Tmp || strchr( Tmp2, ')') == NULL ) { return FALSE; } // // copy the mnemonic // while( Tmp < Tmp2 ) { *NextMnemonic++ = *Tmp++; } *NextMnemonic = '\0'; // // return all done // return TRUE; } // ---------------------------------------------------------------------------- // PROCEDURE: FwGetMnemonicPath: // // DESCRIPTION: The routine returns a pointer to the mnemonic path. // The routine uses the first mnemoic match to built // the mnemonic path. // // ARGUMENTS: Path pointer to the path string. // Mnemonic pointer to the mnemomic. // MnemonicPath pointer to the mnemonic path string. // // RETURN: TRUE returned if all correct. // FALSE returned for any error. // // ASSUMPTIONS: the string pointed by MnemonicPath must be enough large to // contain the mnemoinc path. // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // BOOLEAN FwGetMnemonicPath ( IN PCHAR Path, IN PCHAR Mnemonic, OUT PCHAR MnemonicPath ) { // // local variables // PCHAR Tmp; ULONG i; CHAR String[ MAX_MNEMONIC_LEN + 3 ]; // mnemonic + ')' + '(' + '\0' PRINTDBG("FwGetMnemonicPath\n\r"); // // Construct a string of the form ")mnemonic(" // String[0]=')'; for(i=1; *Mnemonic; i++) { String[i] = *Mnemonic++; } String[i++]='('; String[i]='\0'; // // first look for the "mnemonic(" string. // if ( (Tmp = strstr( Path, &String[1] )) == NULL) { return FALSE; } // // if not the begin of the path name, look for the ")mnemonic(" string. // if (Tmp != Path) { if ( (Tmp = strstr( Path, String )) == NULL) { return FALSE; } Tmp++; } // // find the end of this mnemonic // if ( (Tmp = strchr(Tmp,')')) == NULL ) { return FALSE; } // // copy the mnemonic path in the output string // strncpy( MnemonicPath, Path, Tmp-Path+1 ); MnemonicPath[ Tmp-Path+1 ] = '\0'; // // all done, return // return TRUE; } // ---------------------------------------------------------------------------- // PROCEDURE: GetNextPath: // // DESCRIPTION: The routine isolates the first path string entry form the // specified path string list. // // ARGUMENTS: PathList pointer to the path string list pointer. // it is updated upon return to point the // next path string entry. // PathTarget pointer to the isolated path string. // // // RETURN: TRUE returned if operation is successful. // FALSE returned if end of list has been reached. // // ASSUMPTIONS: The path string list is ended with a null char ('\0') and // the path string entries are separated from each other with // the ';' char. // The target string has enough space to hold the isolated // path string. // // CALLS: // // GLOBALS: // // NOTES: // ---------------------------------------------------------------------------- // BOOLEAN GetNextPath ( IN OUT PCHAR *PPathList, OUT PCHAR PathTarget ) { PRINTDBG("GetNextPath\n\r"); // // if end of list, retrun with error // if (!**PPathList) { return FALSE; } // // copy the path string and update the pointer // for (; *PathTarget=**PPathList; *PathTarget++, *(*PPathList)++) { if (**PPathList==';') { *PathTarget='\0'; (*PPathList)++; break; } } return TRUE; }