From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/fw/mips/jxconfig.c | 1956 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1956 insertions(+) create mode 100644 private/ntos/fw/mips/jxconfig.c (limited to 'private/ntos/fw/mips/jxconfig.c') diff --git a/private/ntos/fw/mips/jxconfig.c b/private/ntos/fw/mips/jxconfig.c new file mode 100644 index 000000000..409086a03 --- /dev/null +++ b/private/ntos/fw/mips/jxconfig.c @@ -0,0 +1,1956 @@ +#if defined(JAZZ) + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + jxconfig.c + +Abstract: + + This module implements the ARC firmware Configuration Query functions as + described in the Advanced Risc Computing Specification (Revision 1.00), + section 3.3.3.4, for a MIPS R3000 or R4000 Jazz system. + +Author: + + David M. Robinson (davidro) 13-June-1991 + +Revision History: + +--*/ + +#include "fwp.h" +#include "string.h" +#include "selftest.h" +extern ULONG end; + +// +// Define the ARC pathname mnemonics. +// + +PCHAR MnemonicTable[] = { + "arc", + "cpu", + "fpu", + "pic", + "pdc", + "sic", + "sdc", + "sc", + "eisa", + "tc", + "scsi", + "dti", + "multi", + "disk", + "tape", + "cdrom", + "worm", + "serial", + "net", + "video", + "par", + "point", + "key", + "audio", + "other", + "rdisk", + "fdisk", + "tape", + "modem", + "monitor", + "print", + "pointer", + "keyboard", + "term", + "other" + }; + +// +// Function prototypes. +// + +ARC_STATUS +FwRestoreConfiguration ( + VOID + ); + +VOID +FwConfigurationSetChecksum( + VOID + ); + +ULONG +FwZeroCompressLength ( + IN ULONG DataLength, + IN PVOID ConfigurationData + ); + +ULONG +FwZeroCompress ( + IN ULONG DataLength, + IN PVOID ConfigurationData, + OUT PVOID OutputBuffer + ); + +VOID +FwZeroDecompress ( + IN PVOID InBuffer, + IN ULONG Index, + OUT PVOID ConfigurationData, + IN ULONG Length + ); + +// +// IdentifierIndex and DataIndex identify the next free locations in the +// configuration identifier and data areas. Configuration points to the +// allocated configuration area. +// + +ULONG IdentifierIndex; +ULONG DataIndex; +ULONG EisaDataIndex; +PCONFIGURATION Configuration; + +// +// Boolean to keep checksum status of the NVRAM. +// + +BOOLEAN NvramValid = FALSE; + +// +// External data. +// + +extern MONITOR_CONFIGURATION_DATA DefaultMonitor; + + +VOID +FwConfigurationInitialize ( + VOID + ) + +/*++ + +Routine Description: + + This routine initializes the configuration area in memory, and the + configuration routine addresses. + + Note: This routine is called at phase 1 initialization and + at this time nothing is available. + +Arguments: + + None. + +Return Value: + + None. + +--*/ +{ + PCONFIGURATION_COMPONENT Processor, Child; + ULONG ProcessorNumber; + CHAR CpuPath[10]; + + // + // Initialize the configuration routine addresses in the system + // parameter block. + // + + (PARC_GET_CHILD_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetChildRoutine] = + FwGetChild; + (PARC_GET_PARENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetParentRoutine] = + FwGetParent; + (PARC_GET_PEER_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetPeerRoutine] = + FwGetPeer; + (PARC_ADD_CHILD_ROUTINE)SYSTEM_BLOCK->FirmwareVector[AddChildRoutine] = + FwAddChild; + (PARC_DELETE_COMPONENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[DeleteComponentRoutine] = + FwDeleteComponent; + (PARC_GET_COMPONENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetComponentRoutine] = + FwGetComponent; + (PARC_GET_DATA_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetDataRoutine] = + FwGetConfigurationData; + (PARC_SAVE_CONFIGURATION_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SaveConfigurationRoutine] = + FwSaveConfiguration; + + // + // Allocate a region to store the volatile configuration database. + // + + Configuration = (PCONFIGURATION)FwAllocatePool(sizeof(CONFIGURATION)); + + // + // Initialize other static data. + // + + IdentifierIndex = 0; + DataIndex = 0; + EisaDataIndex = 0; + + if (FwRestoreConfiguration() == ESUCCESS) { + + // + // Delete processor components. + // + + for (ProcessorNumber = 0; ProcessorNumber < 2 ; ProcessorNumber++ ) { + sprintf(CpuPath,"cpu(%1d)", ProcessorNumber); + Processor = FwGetComponent(CpuPath); + if ((Processor != NULL) && (Processor->Type == CentralProcessor)) { + while ((Child = FwGetChild(Processor)) != NULL) { + FwDeleteComponent(Child); + } + FwDeleteComponent(Processor); + } + } + + // + // Add the first processor. + // + + JzAddProcessor(0); + +#ifdef DUO + // + // Add the second processor + // + + ExecuteOnProcessorB((PPROCESSOR_TASK_ROUTINE)JzAddProcessor,1); +#endif + + FwSaveConfiguration(); + } + + return; +} + +PCONFIGURATION_COMPONENT +FwAddChild ( + IN PCONFIGURATION_COMPONENT Component, + IN PCONFIGURATION_COMPONENT NewComponent, + IN PVOID ConfigurationData OPTIONAL + ) + +/*++ + +Routine Description: + + This routine adds a new component entry as a child of Component, including + an identifier string if the IdentifierLength field of NewComponent is + non-zero, and configuration data if the ConfigurationDataLength field of + NewComponent is non-zero and the ConfigurationData parameter is present. + If Component is NULL, the root component is being added. + +Arguments: + + Component - Supplies a pointer to a configuration component. + + NewComponent - Supplies a pointer to a new configuration component + to be added as a child of Component. + + ConfigurationData - Supplies an optional pointer to a configuration + data buffer. + +Return Value: + + Returns a pointer to the new configuration component entry. If the + create operation was unsuccessful, NULL is returned. + +--*/ +{ + PCONFIGURATION_PACKET Packet; + PCONFIGURATION_PACKET ParentPacket; + ULONG Index; + PUCHAR String; + PUCHAR Data; + BOOLEAN Eisa; + ULONG DataLength; + + // + // If Component is NULL and the new Class is system, the root component is + // being added, otherwise find the first free component entry. + // + + if ((Component == NULL) && (NewComponent->Class == SystemClass)) { + + Packet = &Configuration->Packet[0]; + + // + // TEMPTEMP If the root component is being added, clear all of the + // configuration area. This is a Hack, should be replaced by + // a good way to do this. + // + + RtlZeroMemory(Configuration, sizeof(CONFIGURATION)); + IdentifierIndex = 0; + DataIndex = 0; + EisaDataIndex = 0; + + } else { + + // + // If the configuration is not valid, return NULL. + // + + if (!NvramValid) { + return(NULL); + } + + Packet = &Configuration->Packet[1]; + + for ( Index = 1 ; Packet->Parent != NULL ; Index++ ) { + + // + // If no more entries, return NULL. Since Index is 0 based + // subtract one from NUMBER_OF_ENTRIES for end check. + // + + if (Index >= (NUMBER_OF_ENTRIES - 1)) { + return NULL; + } + + Packet++; + } + } + + // + // Check to see if the parent component is the eisa bus. + // + + if ((Component != NULL) && (Component->Type == EisaAdapter)) { + Eisa = TRUE; + } else { + Eisa = FALSE; + } + + // + // If there is not enough space for the new identifier string or the + // configuration data, return NULL. + // + + if (IdentifierIndex + NewComponent->IdentifierLength >= LENGTH_OF_IDENTIFIER) { + return(NULL); + } + + if (Eisa) { + DataLength = FwZeroCompressLength(NewComponent->ConfigurationDataLength, + ConfigurationData); + + if (EisaDataIndex + DataLength >= LENGTH_OF_EISA_DATA) { + return(NULL); + } + } else { + if (DataIndex + NewComponent->ConfigurationDataLength >= LENGTH_OF_DATA) { + return(NULL); + } + } + + // + // There is space for everything. Fill in new configuration entry first. + // + + Packet->Component.Class = NewComponent->Class; + Packet->Component.Type = NewComponent->Type; + Packet->Component.Flags = NewComponent->Flags; + Packet->Component.Version = NewComponent->Version; + Packet->Component.Revision = NewComponent->Revision; + Packet->Component.Key = NewComponent->Key; + Packet->Component.AffinityMask = 0xffffffff; + Packet->Component.IdentifierLength = NewComponent->IdentifierLength; + Packet->Component.Identifier = &Configuration->Identifier[IdentifierIndex]; + + // + // If Component is NULL, this is the root component so the parent is NULL, + // otherwise find the parent packet. + // + + if (Component == NULL) { + ParentPacket = NULL; + } else { + ParentPacket = CONTAINING_RECORD(Component, + CONFIGURATION_PACKET, + Component); + } + + // + // Only copy configuration data length if configuration data is supplied. + // + + if (ConfigurationData != NULL) { + Packet->Component.ConfigurationDataLength = + NewComponent->ConfigurationDataLength; + } else { + Packet->Component.ConfigurationDataLength = 0; + } + + Packet->Parent = ParentPacket; + + Packet->Child = NULL; + + // + // Add identifer string. + // + + String = NewComponent->Identifier; + + for ( Index = 0 ; Index < NewComponent->IdentifierLength ; Index++ ) { + Configuration->Identifier[IdentifierIndex++] = *String++; + } + + // + // Make sure identifier is zero terminated, if not add one. + // + + if (Configuration->Identifier[IdentifierIndex - 1] != 0) { + Configuration->Identifier[IdentifierIndex++] = 0; + Packet->Component.IdentifierLength += 1; + } + + // + // Copy configuration data. + // + + if (Eisa) { + Packet->ConfigurationData = &Configuration->EisaData[EisaDataIndex]; + EisaDataIndex += FwZeroCompress(NewComponent->ConfigurationDataLength, + ConfigurationData, + &Configuration->EisaData[EisaDataIndex]); + } else { + Data = (PUCHAR)ConfigurationData; + Packet->ConfigurationData = &Configuration->Data[DataIndex]; + for ( Index = 0 ; Index < NewComponent->ConfigurationDataLength ; Index++ ) { + Configuration->Data[DataIndex++] = *Data++; + } + } + + // + // Add the new component as the first child of Component, unless this is + // the root component. + // + + if (Component == NULL) { + Packet->Peer = NULL; + } else { + Packet->Peer = ParentPacket->Child; + ParentPacket->Child = Packet; + } + + return (&Packet->Component); +} + + +ARC_STATUS +FwDeleteComponent ( + IN PCONFIGURATION_COMPONENT Component + ) + +/*++ + +Routine Description: + + This function deletes a component entry. If the entry has one or more + children, an error is returned, otherwise the entry is deleted. Deleting + the entry will implicitly delete the identifier string and the configuration + data. + + Note that no attempt is made to compress the entry, identifier, or the + configuration data areas after an entry is deleted, as doing so would + potentially invalidate outstanding pointers. + +Arguments: + + Component - Supplies a pointer to a configuration component. + +Return Value: + + Returns ESUCCESS if the entry was successfully deleted, otherwise one of + the following error codes is returned. + + EINVAL Component is not a valid configuration component, or the + configuration is not valid. + + EACCES Component has children, and cannot be freed until they + are deleted. + + +--*/ +{ + PCONFIGURATION_PACKET Packet; + PCONFIGURATION_PACKET SearchPacket; + + if (!NvramValid || (Component == NULL)) { + return EINVAL; + } + + Packet = CONTAINING_RECORD(Component, + CONFIGURATION_PACKET, + Component); + + // + // If Component's Parent field is NULL, return EINVAL. + // + + if (Packet->Parent == NULL) { + return EINVAL; + } + + // + // If Component has children, return EACCES. + // + + if (Packet->Child != NULL) { + return EACCES; + } + + // + // Find the entry that points to Component, and point it to + // Component's peer. If this is Component's parent, update the child + // pointer, otherwise this is a peer and update the peer pointer. + // + + SearchPacket = Packet->Parent; + + if (SearchPacket->Child == Packet) { + SearchPacket->Child = Packet->Peer; + } else { + SearchPacket = SearchPacket->Child; + while (SearchPacket->Peer != Packet) { + SearchPacket = SearchPacket->Peer; + } + SearchPacket->Peer = Packet->Peer; + } + + // + // Delete Component by zeroing the parent pointer. + // + + Packet->Parent = NULL; + + return ESUCCESS; +} + + +PCONFIGURATION_COMPONENT +FwGetComponent ( + IN PCHAR Pathname + ) + +/*++ + +Routine Description: + + This routine searches the configuration tree for the component that best + matches the Pathname string. + +Arguments: + + Pathname - Supplies a string containing the pathname to search. + +Return Value: + + Returns a pointer to the configuration component that best matches + pathname. The algorithm is to search for each component starting with + the first. When the string has been exhausted or no component matches the + current string section, then a pointer to the last successfully matched + component is returned. If the configuration information is not valid, + NULL is returned. + +--*/ +{ + PCONFIGURATION_COMPONENT Component; + PCONFIGURATION_COMPONENT MatchComponent; + PCHAR PathString; + PCHAR MatchString; + PCHAR Token; + ULONG Key; + + // + // If the configuration is not valid, return NULL. + // + + if (!NvramValid) { + return(NULL); + } + + PathString = Pathname; + + // + // Get the the root component. + // + + MatchComponent = FwGetChild(NULL); + + // + // Repeat search for each new match component. + // + + do { + + // + // Get the first child of the current match component. + // + + Component = FwGetChild( MatchComponent ); + + // + // Search each child of the current match component for the next match. + // + + while ( Component != NULL ) { + + // + // Reset Token to be the current position on the pathname. + // + + Token = PathString; + + MatchString = MnemonicTable[Component->Type]; + + // + // Compare strings. + // + + while (*MatchString == tolower(*Token)) { + MatchString++; + Token++; + } + + // + // Strings compare if the first mismatch is the terminator for + // each. + // + + if ((*MatchString == 0) && (*Token == '(')) { + + // + // Form key. + // + + Key = 0; + Token++; + while ((*Token != ')') && (*Token != 0)) { + Key = (Key * 10) + *Token++ - '0'; + } + + // + // If the key matches the component matches, so update + // pointers and break. + // + + if (Component->Key == Key) { + PathString = Token + 1; + MatchComponent = Component; + break; + } + } + +NextPeer: + Component = FwGetPeer( Component ); + } + + } while ((Component != NULL) && (*PathString != 0)); + + return MatchComponent; +} + +PCONFIGURATION_COMPONENT +FwGetChild ( + IN PCONFIGURATION_COMPONENT Component OPTIONAL + ) + +/*++ + +Routine Description: + + Returns a pointer to the configuration component for the first child of + Component. If Component is NULL, a pointer to the root configuration + component is returned. + +Arguments: + + Component - Supplies an optional pointer to a configuration component. + +Return Value: + + Returns a pointer to the configuration component for the first child of + Component. If Component has no children, this pointer will be NULL. If + Component is NULL, a pointer to the root configuration component is + returned. If the configuration is not valid, NULL is returned. + +--*/ +{ + PCONFIGURATION_PACKET Packet; + + // + // If the configuration is not valid, return NULL. + // + + if (!NvramValid) { + return(NULL); + } + + + if (Component == NULL) { + return &Configuration->Packet[0].Component; + } else { + Packet = CONTAINING_RECORD(Component, + CONFIGURATION_PACKET, + Component); + + return &((PCONFIGURATION_PACKET)(Packet->Child))->Component; + } +} + + +PCONFIGURATION_COMPONENT +FwGetParent ( + IN PCONFIGURATION_COMPONENT Component + ) + +/*++ + +Routine Description: + + This function returns the parent of the named component. + +Arguments: + + Component - Supplies a pointer to a configuration component. + +Return Value: + + Returns a pointer to the configuration component for the parent of + Component. If Component has no parent NULL is returned (this is only + true for the root configuration component). If the configuration is + not valid, NULL is returned. + +--*/ +{ + PCONFIGURATION_PACKET Packet; + + // + // If the configuration is not valid, return NULL. + // + + if (!NvramValid) { + return(NULL); + } + + Packet = CONTAINING_RECORD(Component, + CONFIGURATION_PACKET, + Component); + + if (Packet->Parent == NULL) { + return NULL; + } else { + return &((PCONFIGURATION_PACKET)(Packet->Parent))->Component; + } +} + + +PCONFIGURATION_COMPONENT +FwGetPeer ( + IN PCONFIGURATION_COMPONENT Component + ) + +/*++ + +Routine Description: + + This function returns the peer of the named component. + +Arguments: + + Component - Supplies a pointer to a configuration component. + +Return Value: + + Returns a pointer to the configuration component for the next peer of + Component. If Component has no next peer, NULL is returned. If the + configuration is not valid, NULL is returned. + +--*/ +{ + PCONFIGURATION_PACKET Packet; + + // + // If the configuration is not valid, return NULL. + // + + if (!NvramValid) { + return(NULL); + } + + Packet = CONTAINING_RECORD(Component, + CONFIGURATION_PACKET, + Component); + + if (Packet->Peer == NULL) { + return NULL; + } else { + return &((PCONFIGURATION_PACKET)(Packet->Peer))->Component; + } +} + + +ARC_STATUS +FwGetConfigurationDataIndex + ( + OUT PVOID ConfigurationData, + IN PCONFIGURATION_COMPONENT Component, + IN ULONG Index, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This functions returns the specified configuration data + associated with Component in the buffer supplied by + ConfigurationData. The max length of the data is stored + in the Component structure. + +Arguments: + + ConfigurationData - Supplies a pointer to a buffer to receive the + configuration data. + + Component - Supplies a pointer to a configuration component. + + Index - Supplies an index within the configuration data. + + Length - Supplies the number of bytes to read (see the + ConfigurationDataLength field within the Component for the max + value). + +Return Value: + + If the configuration data is successfully copied into the buffer + provided by ConfigurationData, ESUCCESS is returned. Otherwise one of + the following error codes is returned. + + EINVAL Component is not a valid configuration component or the + other arguments are invalid or the configuration is + not valid. + +--*/ + +{ + PCONFIGURATION_PACKET Packet; + ULONG DataSize; + PUCHAR SourceData; + PUCHAR DestinationData; + + // + // If the configuration is not valid, return EINVAL. + // + + if (!NvramValid) { + return(EINVAL); + } + + DataSize = Component->ConfigurationDataLength; + + // + // check the passing parameters + // + + if ( DataSize == 0 || Index >= DataSize || DataSize - Index < Length ) { + return EINVAL; + } + + Packet = CONTAINING_RECORD( Component, CONFIGURATION_PACKET, Component ); + + // + // If Component's Parent field is NULL, return EINVAL. + // + + if (Packet->Parent == NULL) { + return EINVAL; + } + + // + // If this is an eisa component, decompress the data, otherwise just copy it. + // + + if (Packet->Parent->Component.Type == EisaAdapter) { + FwZeroDecompress(Packet->ConfigurationData, + Index, + ConfigurationData, + Length); + + } else { + SourceData = (PUCHAR)Packet->ConfigurationData + Index; + DestinationData = ConfigurationData; + + while ( Length-- ) + { + *DestinationData++ = *SourceData++; + } + } + + return ESUCCESS; +} + + +ARC_STATUS +FwGetConfigurationData ( + OUT PVOID ConfigurationData, + IN PCONFIGURATION_COMPONENT Component + ) + +/*++ + +Routine Description: + + This functions returns the configuration data associated with Component + in the buffer supplied by ConfigurationData. The length of the data + is stored in the Component structure. + +Arguments: + + ConfigurationData - Supplies a pointer to a buffer to receive the + configuration data. + + Component - Supplies a pointer to a configuration component. + +Return Value: + + If the configuration data is successfully copied into the buffer + provided by ConfigurationData, ESUCCESS is returned. Otherwise one of + the following error codes is returned. + + EINVAL Component is not a valid configuration component, or the + configuration is invalid. + +--*/ + +{ + return(FwGetConfigurationDataIndex(ConfigurationData, + Component, + 0, + Component->ConfigurationDataLength)); +} + + + +ARC_STATUS +FwSaveConfiguration ( + VOID + ) + +/*++ + +Routine Description: + + This routine stores all of the configuration entries into NVRAM, + including the associated identifier strings and configuration data. + +Arguments: + + None. + +Return Value: + + Returns ESUCCESS if the save completed successfully, otherwise one of the + following error codes is returned. + + ENOSPC Not enough space in the NVRAM to save all of the data. + +--*/ + +{ + ULONG EntryIndex; + ULONG Index; + PCONFIGURATION_PACKET Packet; + PCONFIGURATION_COMPONENT Component; + PNV_CONFIGURATION NvConfiguration; + COMPRESSED_CONFIGURATION_PACKET CompressedPacket; + USHORT NvIdentifierIndex; + USHORT NvDataIndex; + USHORT NvEisaDataIndex; + PUCHAR CompressedChars, NvChars, Data; + + NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; + NvIdentifierIndex = 0; + NvDataIndex = 0; + NvEisaDataIndex = 0; + + // + // Write each volatile packet into a compressed non-volatile packet, + // including the identifier string and the configuration data. + // + + for ( EntryIndex = 0 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) { + + // + // Get pointers to the volatile data. + // + + Packet = (PCONFIGURATION_PACKET)&Configuration->Packet[EntryIndex]; + Component = &Packet->Component; + + // + // If this is not the root entry and the parent field is NULL, zero + // entry and skip to next. + // + + if ((EntryIndex != 0) && (Packet->Parent == NULL)) { + NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex]; + for ( Index = 0 ; + Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ; + Index++ ) { + WRITE_REGISTER_UCHAR( NvChars++, 0); + } + continue; + } + + // + // Determine the parent and store as an index. Note that the index + // (Packet->Parent) is 1 based, to reserve the value 0 to mean no + // parent. + // + + if (EntryIndex != 0) { + CompressedPacket.Parent = + (UCHAR)(Packet->Parent - &Configuration->Packet[0]) + 1; + } else { + CompressedPacket.Parent = 0; + } + + // + // Fill in the rest of the fields. Version and ConfigurationDataLength will + // never be larger than USHORTS. + // + + CompressedPacket.Class = (UCHAR)Component->Class; + CompressedPacket.Type = (UCHAR)Component->Type; + CompressedPacket.Version = (UCHAR)Component->Version; + CompressedPacket.Revision = (UCHAR)Component->Revision; + CompressedPacket.Key = Component->Key; + CompressedPacket.ConfigurationDataLength = + (USHORT)Component->ConfigurationDataLength; + CompressedPacket.ConfigurationData = 0; + + // + // Make sure the top bit of the flag field is zero unless it's set + // to be eisa below. + // + + CompressedPacket.Flags = *(PUCHAR)(&Component->Flags) & 0x7f; + + // + // If the component has an identifier string, copy it to NVRAM, + // otherwise set the index to indicate no identifier. + // + + if (Component->IdentifierLength != 0) { + CompressedPacket.Identifier = NvIdentifierIndex; + for ( Index = 0 ; Index < Component->IdentifierLength ; Index++ ) { + WRITE_REGISTER_UCHAR( + &NvConfiguration->Identifier[NvIdentifierIndex++], + Component->Identifier[Index]); + } + } else { + CompressedPacket.Identifier = NO_CONFIGURATION_IDENTIFIER; + } + + // + // If the component has configuration data, copy it to NVRAM. + // + + if (Component->ConfigurationDataLength != 0) { + + // + // If the parent component is the eisa bus, copy until the end + // of the compressed data. + // + + if (Packet->Parent->Component.Type == EisaAdapter) { + CompressedPacket.ConfigurationData = NvEisaDataIndex; + Data = (PUCHAR)Packet->ConfigurationData; + for ( Index = 0 ; TRUE ; Index++ ) { + WRITE_REGISTER_UCHAR( &NvConfiguration->EisaData[NvEisaDataIndex++], + *Data++); + + // + // If we've written at least two bytes and the last two + // bytes were zero we're at the end. + // + + if ((Index > 1) && (!*(Data - 1) && !*(Data - 2))) { + break; + } + } + + // + // Set a flag to make it easier to determine that this is an + // Eisa component. + // + + CompressedPacket.Flags |= 0x80; + + } else { + CompressedPacket.ConfigurationData = NvDataIndex; + Data = (PUCHAR)Packet->ConfigurationData; + for ( Index = 0 ; Index < Component->ConfigurationDataLength ; Index++ ) { + WRITE_REGISTER_UCHAR( &NvConfiguration->Data[NvDataIndex++], + *Data++); + } + } + } + + // + // Write compressed packet to NVRAM. + // + + CompressedChars = (PUCHAR)&CompressedPacket; + NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex]; + + for ( Index = 0 ; + Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ; + Index++ ) { + WRITE_REGISTER_UCHAR( NvChars++, *CompressedChars++); + } + } + + // + // Zero the rest of the identifier and configuration data areas. + // + + for ( Index = NvIdentifierIndex ; Index < LENGTH_OF_IDENTIFIER ; Index++ ) { + WRITE_REGISTER_UCHAR( &NvConfiguration->Identifier[Index], 0); + } + + for ( Index = NvDataIndex ; Index < LENGTH_OF_DATA ; Index++ ) { + WRITE_REGISTER_UCHAR( &NvConfiguration->Data[Index] ,0); + } + + for ( Index = NvEisaDataIndex ; Index < LENGTH_OF_EISA_DATA ; Index++ ) { + WRITE_REGISTER_UCHAR( &NvConfiguration->EisaData[Index] ,0); + } + + // + // Write configuration data checksum. + // + + FwConfigurationSetChecksum(); + + // + // Restore configuration information out of NVRAM. This acts to compress + // the identifier and configuration data areas if any deletes have been + // performed. + // + + return FwRestoreConfiguration(); +} + + +ARC_STATUS +FwRestoreConfiguration ( + VOID + ) + +/*++ + +Routine Description: + + This routine restores all of the configuration entries from NVRAM, + including the associated identifier strings and configuration data. + +Arguments: + + None. + +Return Value: + + Returns ESUCCESS if the restore completed successfully, otherwise one of + the following error codes is returned. + + EIO Invalid NVRAM checksum. + +--*/ + +{ + ULONG EntryIndex; + ULONG Index; + PCONFIGURATION_PACKET Packet; + PCONFIGURATION_COMPONENT Component; + PNV_CONFIGURATION NvConfiguration; + COMPRESSED_CONFIGURATION_PACKET CompressedPacket; + USHORT NvIdentifierIndex; + USHORT NvDataIndex; + USHORT NvEisaDataIndex; + PUCHAR CompressedChars, NvChars; + PCONFIGURATION_PACKET SearchPacket; + ULONG Long; + + + NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; + NvIdentifierIndex = 0; + NvDataIndex = 0; + NvEisaDataIndex = 0; + IdentifierIndex = 0; + DataIndex = 0; + EisaDataIndex = 0; + + // + // Check the checksum, return error if invalid. + // + + if (FwConfigurationCheckChecksum() != ESUCCESS) { + return EIO; + } + + // + // Clear the configuration area. + // + + RtlZeroMemory(Configuration, sizeof(CONFIGURATION)); + + // + // Read each non-volatile compressed packet into a volatile packet, + // including the identifier string and the configuration data. + // + + for ( EntryIndex = 0 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) { + + // + // Read compressed packet from NVRAM. + // + + CompressedChars = (PUCHAR)&CompressedPacket; + NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex]; + + for ( Index = 0 ; + Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ; + Index++ ) { + *CompressedChars++ = READ_REGISTER_UCHAR( NvChars++ ); + } + + // + // If this is not the root entry and the parent field is NULL, + // go to the next. + // + + if ((EntryIndex != 0) && (CompressedPacket.Parent == 0)) { + continue; + } + + // + // Get pointers to the volatile area. + // + + Packet = (PCONFIGURATION_PACKET)&Configuration->Packet[EntryIndex]; + Component = &Packet->Component; + + // + // If not the root entry and the parent field is within range, fill + // in parent field (note that the parent index + // is 1 based, subtract 1 to get correct index). If the parent's child + // pointer is NULL, fill in with the current entry, otherwise follow + // the links and add the current entry as the last peer. + // + + if ((EntryIndex != 0) && (CompressedPacket.Parent <= NUMBER_OF_ENTRIES)) { + Packet->Parent = &Configuration->Packet[CompressedPacket.Parent - 1]; + SearchPacket = Packet->Parent; + + if (SearchPacket->Child == NULL) { + SearchPacket->Child = Packet; + } else { + SearchPacket = SearchPacket->Child; + while ( SearchPacket->Peer != NULL ) { + SearchPacket = SearchPacket->Peer; + } + SearchPacket->Peer = Packet; + } + } else { + Packet->Parent = NULL; + } + + // + // NULL current packet's child and peer pointers. + // + + Packet->Child = NULL; + Packet->Peer = NULL; + + // + // Fill in the rest of the fields. + // + + Component->Class = (CONFIGURATION_CLASS)CompressedPacket.Class; + Component->Type = (CONFIGURATION_TYPE)CompressedPacket.Type; + Component->Flags.Failed = (CompressedPacket.Flags & 0x01) ? 1 : 0; + Component->Flags.ReadOnly = (CompressedPacket.Flags & 0x02) ? 1 : 0; + Component->Flags.Removable = (CompressedPacket.Flags & 0x04) ? 1 : 0; + Component->Flags.ConsoleIn = (CompressedPacket.Flags & 0x08) ? 1 : 0; + Component->Flags.ConsoleOut = (CompressedPacket.Flags & 0x10) ? 1 : 0; + Component->Flags.Input = (CompressedPacket.Flags & 0x20) ? 1 : 0; + Component->Flags.Output = (CompressedPacket.Flags & 0x40) ? 1 : 0; + Component->Version = (USHORT)CompressedPacket.Version; + Component->Revision = (USHORT)CompressedPacket.Revision; + Component->Key = CompressedPacket.Key; + Component->AffinityMask = 0xffffffff; + Component->ConfigurationDataLength = + (ULONG)CompressedPacket.ConfigurationDataLength; + + // + // If the component has an identifier string, copy it to memory. + // + + Index = 0; + + if (CompressedPacket.Identifier != NO_CONFIGURATION_IDENTIFIER) { + Component->Identifier = &Configuration->Identifier[IdentifierIndex]; + do { + Configuration->Identifier[IdentifierIndex++] = + READ_REGISTER_UCHAR( + &NvConfiguration->Identifier[NvIdentifierIndex] ); + Index++; + } while ( READ_REGISTER_UCHAR(&NvConfiguration->Identifier[NvIdentifierIndex++] ) ); + } + + // + // Set identifier length field. + // + + Component->IdentifierLength = Index; + + // + // If the component has configuration data, copy it to memory. + // + + if (Component->ConfigurationDataLength != 0) { + + // + // If the eisa flag is set, only copy the compressed data. + // + + if (CompressedPacket.Flags & 0x80) { + Packet->ConfigurationData = &Configuration->EisaData[EisaDataIndex]; + for ( Index = 0 ; TRUE ; Index++ ) { + Configuration->EisaData[EisaDataIndex++] = + READ_REGISTER_UCHAR( &NvConfiguration->EisaData[NvEisaDataIndex++] ); + + // + // If at least two bytes have been written and the last + // two bytes are zero, we're at the end. + // + + if ((Index > 1) && + (!Configuration->EisaData[EisaDataIndex - 1] & + !Configuration->EisaData[EisaDataIndex - 2])) { + break; + } + } + } else { + Packet->ConfigurationData = &Configuration->Data[DataIndex]; + for ( Index = 0 ; Index < Component->ConfigurationDataLength ; Index++ ) { + Configuration->Data[DataIndex++] = + READ_REGISTER_UCHAR( &NvConfiguration->Data[NvDataIndex++] ); + } + } + } + } + + return(ESUCCESS); +} + + +ARC_STATUS +FwConfigurationCheckChecksum ( + VOID + ) + +/*++ + +Routine Description: + + This routine checks the configuration checksum. + +Arguments: + + None. + +Return Value: + + If the checksum is good, ESUCCESS is returned, otherwise EIO is returned. + +--*/ + +{ + PUCHAR NvChars; + PNV_CONFIGURATION NvConfiguration; + ULONG Index; + ULONG Checksum1, Checksum2; + + NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; + + // + // Form checksum from NVRAM data. + // + + Checksum1 = 0; + NvChars = (PUCHAR)NvConfiguration; + + for ( Index = 0 ; + Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES + + LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA; + Index++ ) { + Checksum1 += READ_REGISTER_UCHAR( NvChars++ ); + } + + // + // Reconstitute checksum and return error if no compare. + // + + Checksum2 = (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[0] ) | + (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[1] ) << 8 | + (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[2] ) << 16 | + (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[3] ) << 24 ; + + if (Checksum1 != Checksum2) { + NvramValid = FALSE; + return EIO; + } + + // + // Repeat for the eisa data area. + // + + Checksum1 = 0; + NvChars = (PUCHAR)NvConfiguration->EisaData; + + for ( Index = 0 ; + Index < LENGTH_OF_EISA_DATA; + Index++ ) { + Checksum1 += READ_REGISTER_UCHAR( NvChars++ ); + } + + // + // Reconstitute checksum and return error if no compare. + // + + Checksum2 = (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[0] ) | + (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[1] ) << 8 | + (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[2] ) << 16 | + (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[3] ) << 24 ; + + if (Checksum1 != Checksum2) { + NvramValid = FALSE; + return EIO; + } + + NvramValid = TRUE; + return(ESUCCESS); +} + +VOID +FwConfigurationSetChecksum ( + VOID + ) + +/*++ + +Routine Description: + + This routine sets the configuration checksum. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + PUCHAR NvChars; + PNV_CONFIGURATION NvConfiguration; + ULONG Index; + ULONG Checksum1; + + NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; + + // + // Form checksum from NVRAM data. + // + + Checksum1 = 0; + NvChars = (PUCHAR)NvConfiguration; + + for ( Index = 0 ; + Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES + + LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA; + Index++ ) { + Checksum1 += READ_REGISTER_UCHAR( NvChars++ ); + } + + // + // Set checksum. + // + + WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[0], Checksum1); + WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[1], Checksum1 >> 8); + WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[2], Checksum1 >> 16); + WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[3], Checksum1 >> 24); + + // + // Repeat for the eisa data area. + // + + Checksum1 = 0; + NvChars = (PUCHAR)NvConfiguration->EisaData; + + for ( Index = 0 ; + Index < LENGTH_OF_EISA_DATA; + Index++ ) { + Checksum1 += READ_REGISTER_UCHAR( NvChars++ ); + } + + // + // Set checksum. + // + + WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[0], Checksum1); + WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[1], Checksum1 >> 8); + WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[2], Checksum1 >> 16); + WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[3], Checksum1 >> 24); + + NvramValid = TRUE; + return; + +} + +ARC_STATUS +FwGetVideoData ( + OUT PMONITOR_CONFIGURATION_DATA MonitorData + ) + +/*++ + +Routine Description: + + This routine finds the video board and monitor configuration data in the + NVRAM. Normally this information would be accessed through + FwGetConfigurationData, but the initialization code needs the video + information before the firmware routines have been initialized. If no + monitor data is found, then default data is returned. + +Arguments: + + MonitorData - Supplies a pointer to a structure to receive the monitor + configuration data. + +Return Value: + + Returns ESUCCESS if data was found and restored, otherwise returns one of + the following error codes. + + EIO Invalid NVRAM checksum. + + ENODEV Monitor data not found. + + Note that in any event valid data is returned. + +--*/ + +{ + ARC_STATUS Status; + ULONG EntryIndex; + ULONG Index; + COMPRESSED_CONFIGURATION_PACKET CompressedPacket; + PUCHAR CompressedChars; + PUCHAR NvChars; + PUCHAR Data; + PNV_CONFIGURATION NvConfiguration; + + NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; + + // + // Check configuration checksum, return error if not valid. + // + + if (FwConfigurationCheckChecksum() != ESUCCESS){ + Status = EIO; + } else { + + // + // Search the NVRAM configuration entries for the monitor, skip + // the root entry. + // + + for ( EntryIndex = 1 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) { + + // + // Read compressed packet from NVRAM. + // + + CompressedChars = (PUCHAR)&CompressedPacket; + NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex]; + + for ( Index = 0 ; + Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ; + Index++ ) { + *CompressedChars++ = READ_REGISTER_UCHAR( NvChars++ ); + } + + // + // If the parent field is not Null, and the packet is class Peripheral, + // type Monitor, this is the display. + // + + if ((CompressedPacket.Parent != 0) && + (CompressedPacket.Class == PeripheralClass) && + (CompressedPacket.Type == MonitorPeripheral)) { + break; + } + } + + // + // If we've fallen out of the loop the monitor was not found, return + // error. + // + + if (EntryIndex == NUMBER_OF_ENTRIES) { + Status = ENODEV; + } else { + + // + // If the configuration data length is the correct value, copy the data + // into the monitor data structure, otherwise return an error. + // + + if (CompressedPacket.ConfigurationDataLength == sizeof(MONITOR_CONFIGURATION_DATA)) { + Data = (PUCHAR)MonitorData; + for ( DataIndex = CompressedPacket.ConfigurationData ; + DataIndex < (CompressedPacket.ConfigurationData + + CompressedPacket.ConfigurationDataLength) ; + DataIndex++ ) { + *Data++ = READ_REGISTER_UCHAR( &NvConfiguration->Data[DataIndex] ); + } + Status = ESUCCESS; + } else { + Status = ENODEV; + } + } + } + + if (Status != ESUCCESS) { + MonitorData->HorizontalResolution = DefaultMonitor.HorizontalResolution; + MonitorData->HorizontalDisplayTime = DefaultMonitor.HorizontalDisplayTime; + MonitorData->HorizontalBackPorch = DefaultMonitor.HorizontalBackPorch; + MonitorData->HorizontalFrontPorch = DefaultMonitor.HorizontalFrontPorch; + MonitorData->HorizontalSync = DefaultMonitor.HorizontalSync; + MonitorData->VerticalResolution = DefaultMonitor.VerticalResolution; + MonitorData->VerticalBackPorch = DefaultMonitor.VerticalBackPorch; + MonitorData->VerticalFrontPorch = DefaultMonitor.VerticalFrontPorch; + MonitorData->VerticalSync = DefaultMonitor.VerticalSync; + MonitorData->HorizontalScreenSize = DefaultMonitor.HorizontalScreenSize; + MonitorData->VerticalScreenSize = DefaultMonitor.VerticalScreenSize; + } + + return(Status); +} + +VOID +FwSetVideoData ( + IN PMONITOR_CONFIGURATION_DATA MonitorData + ) + +/*++ + +Routine Description: + + This routine stores the monitor configuration data in the + NVRAM. Normally this information would be accessed through + FwAddChild, but this routine allows this data to be set before the + configuration routines have been initialized. + + N.B. This routine assumes the NVRAM has already been checked by + FwGetVideoData and is valid. + +Arguments: + + MonitorData - Supplies a pointer to a structure containing the monitor + configuration data. + +Return Value: + + None. + + +--*/ + +{ + ARC_STATUS Status; + ULONG EntryIndex; + ULONG Index; + COMPRESSED_CONFIGURATION_PACKET CompressedPacket; + PUCHAR CompressedChars; + PUCHAR NvChars; + PUCHAR Data; + PNV_CONFIGURATION NvConfiguration; + + NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; + + // + // Search the NVRAM configuration entries for the monitor, skip + // the root entry. + // + + for ( EntryIndex = 1 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) { + + // + // Read compressed packet from NVRAM. + // + + CompressedChars = (PUCHAR)&CompressedPacket; + NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex]; + + for ( Index = 0 ; + Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ; + Index++ ) { + *CompressedChars++ = READ_REGISTER_UCHAR( NvChars++ ); + } + + // + // If the parent field is not Null, and the packet is class Peripheral, + // type Monitor, this is the display. + // + + if ((CompressedPacket.Parent != 0) && + (CompressedPacket.Class == PeripheralClass) && + (CompressedPacket.Type == MonitorPeripheral)) { + break; + } + } + + // + // Copy the data into the monitor data structure. + // + + Data = (PUCHAR)MonitorData; + for ( DataIndex = CompressedPacket.ConfigurationData ; + DataIndex < (CompressedPacket.ConfigurationData + + CompressedPacket.ConfigurationDataLength) ; + DataIndex++ ) { + WRITE_REGISTER_UCHAR( &NvConfiguration->Data[DataIndex], *Data++); + } + + // + // Fix the checksum. + // + + FwConfigurationSetChecksum(); + + return; +} + + +ULONG +FwZeroCompressLength ( + IN ULONG DataLength, + IN PVOID ConfigurationData + ) + +/*++ + +Routine Description: + + This routine returns the compressed length of a configuration data sample. + +Arguments: + + DataLength - Supplies the uncompressed length of the data. + + ConfigurationData - Supplies a pointer to the uncompressed configuration data. + +Return Value: + + Returns the compressed length of the configuration data. + +--*/ + +{ + ULONG Index; + ULONG CompressedLength; + ULONG Zero; + PUCHAR In; + + CompressedLength = 2; + Zero = 0; + In = ConfigurationData; + + for (Index = 0; Index < DataLength ; Index++ ) { + if (*In++) { + CompressedLength++; + Zero = 0; + } else { + if (Zero++) { + if (Zero == 0x100) { + Zero = 1; + CompressedLength += 2; + } + } else { + CompressedLength += 2; + } + } + } + return(CompressedLength); +} + + +ULONG +FwZeroCompress ( + IN ULONG DataLength, + IN PVOID ConfigurationData, + OUT PVOID OutputBuffer + ) + +/*++ + +Routine Description: + + This routine compresses configuration data. + +Arguments: + + DataLength - Supplies the uncompressed length of the data. + + ConfigurationData - Supplies a pointer to the uncompressed configuration data. + + OutputBuffer - Supplies a pointer to the buffer to receive the compressed data. + +Return Value: + + Returns the compressed length of the configuration data. + +--*/ + +{ + ULONG Index; + ULONG CompressedLength; + ULONG Zero; + PUCHAR In, Out; + + In = (PUCHAR)ConfigurationData; + Out = (PUCHAR)OutputBuffer; + CompressedLength = 2; + Zero = 0; + + for (Index = 0; Index < DataLength ; Index++ ) { + if (*In) { + if (Zero) { + Out++; + Zero = 0; + } + *Out++ = *In; + CompressedLength++; + } else { + if (Zero++) { + if (Zero == 0x100) { + *Out++ = 0xFF; + *Out++ = 0; + *Out = 1; + Zero = 1; + CompressedLength += 2; + } else { + *Out += 1; + } + } else { + *Out++ = 0; + *Out = 1; + CompressedLength += 2; + } + } + In++; + } + + if (Zero) { + Out++; + } + + *Out++ = 0; + *Out = 0; + + return(CompressedLength); +} + + +VOID +FwZeroDecompress ( + IN PVOID InBuffer, + IN ULONG Index, + OUT PVOID ConfigurationData, + IN ULONG Length + ) + +/*++ + +Routine Description: + + This routine compresses configuration data. + +Arguments: + + InBuffer - Supplies a pointer to the compressed configuration data. + + Index - Supplies the index into the uncompressed data to start returning. + + ConfigurationData - Supplies a pointer to the output buffer. + + Length - Supplies the length of data to uncompress. + +Return Value: + + None. + +--*/ + +{ + ULONG DecompressedLength; + ULONG Zero; + PUCHAR In, Out; + UCHAR OutChar; + + if (InBuffer == NULL) { + return; + } + + In = (PUCHAR)InBuffer; + Out = (PUCHAR)ConfigurationData; + DecompressedLength = 0; + Zero = 0; + + while (DecompressedLength++ < Index + Length) { + + if (Zero) { + Zero--; + } else if (*In) { + OutChar = *In++; + } else { + OutChar = 0; + Zero = *(++In) - 1; + In++; + } + + if (DecompressedLength > Index) { + *Out++ = OutChar; + } + + } + +} +#endif -- cgit v1.2.3