1956 lines
46 KiB
C
1956 lines
46 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
Copyright (c) 1993 Digital Equipment 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 an Alpha/Jensen machine.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David M. Robinson (davidro) 13-June-1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
30-April-1992 John DeRosa [DEC]
|
|||
|
|
|||
|
Added Alpha/Jensen hooks.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "fwp.h"
|
|||
|
|
|||
|
|
|||
|
#if !defined(FAILSAFE_BOOTER)
|
|||
|
//
|
|||
|
// 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",
|
|||
|
"line",
|
|||
|
"netper",
|
|||
|
"memory"
|
|||
|
};
|
|||
|
#endif // !defined(FAILSAFE_BOOTER)
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Function prototypes.
|
|||
|
//
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
FwRestoreConfiguration (
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
FwConfigurationCheckChecksum (
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
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
|
|||
|
);
|
|||
|
|
|||
|
#if !defined(FAILSAFE_BOOTER)
|
|||
|
//
|
|||
|
// 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;
|
|||
|
#endif // !defined(FAILSAFE_BOOTER)
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// 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;
|
|||
|
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
(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 and restore the configuration from ROM.
|
|||
|
//
|
|||
|
|
|||
|
FwRestoreConfiguration();
|
|||
|
#endif
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
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 {
|
|||
|
|
|||
|
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);
|
|||
|
|
|||
|
#else // FAILSAFE_BOOTER
|
|||
|
|
|||
|
return NULL;
|
|||
|
|
|||
|
#endif // ndef FAILSAFE_BOOTER
|
|||
|
}
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
EACCES Component has children, and cannot be freed until they
|
|||
|
are deleted.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
PCONFIGURATION_PACKET Packet;
|
|||
|
PCONFIGURATION_PACKET SearchPacket;
|
|||
|
|
|||
|
if (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;
|
|||
|
|
|||
|
#else // FAILSAFE_BOOTER
|
|||
|
return EINVAL;
|
|||
|
|
|||
|
#endif // ndef FAILSAFE_BOOTER
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
PCONFIGURATION_COMPONENT
|
|||
|
FwCoreGetComponent (
|
|||
|
IN PCHAR Pathname,
|
|||
|
IN PCONFIGURATION_COMPONENT MatchComponent
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function does the work for FwGetComponent.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pathname - Supplies a string containing the pathname to search.
|
|||
|
|
|||
|
MatchComponent - A pointer to the current node in the tree in the
|
|||
|
recursive search.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns a pointer to the configuration component that best matches
|
|||
|
pathname.
|
|||
|
|
|||
|
Algorithm:
|
|||
|
|
|||
|
If MatchComponent == NULL, return NULL.
|
|||
|
|
|||
|
else..
|
|||
|
|
|||
|
Check this node. If a successful match, then:
|
|||
|
- if we are at the end of the Pathname, return this node.
|
|||
|
- otherwise, check the children of this node for the
|
|||
|
remainder of the pathname.
|
|||
|
|
|||
|
If there is a better match in one of the children,
|
|||
|
return that pointer. Else, return the pointer to this node.
|
|||
|
|
|||
|
else..
|
|||
|
|
|||
|
Check the peers of this node. If a successful match is returned
|
|||
|
back, return the pointer returned.
|
|||
|
|
|||
|
else..
|
|||
|
|
|||
|
return NULL.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
PCONFIGURATION_COMPONENT Component;
|
|||
|
PCHAR MatchString;
|
|||
|
PCHAR Token;
|
|||
|
ULONG Key;
|
|||
|
BOOLEAN NodeMatch = FALSE;
|
|||
|
|
|||
|
if (MatchComponent == NULL) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check this node.
|
|||
|
//
|
|||
|
|
|||
|
Token = Pathname;
|
|||
|
MatchString = MnemonicTable[MatchComponent->Type];
|
|||
|
|
|||
|
//
|
|||
|
// Compare strings.
|
|||
|
//
|
|||
|
|
|||
|
while ((*MatchString == tolower(*Token)) &&
|
|||
|
(*MatchString != 0)){
|
|||
|
MatchString++;
|
|||
|
Token++;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Strings compare if the first mismatch is the terminator for each.
|
|||
|
//
|
|||
|
|
|||
|
if ((*MatchString == 0) &&
|
|||
|
((*Token == '(') || (*Token == 0))) {
|
|||
|
|
|||
|
//
|
|||
|
// Form key.
|
|||
|
//
|
|||
|
|
|||
|
Key = 0;
|
|||
|
if (*Token == '(') {
|
|||
|
Token++;
|
|||
|
}
|
|||
|
while ((*Token != ')') && (*Token != 0)) {
|
|||
|
Key = (Key * 10) + *Token++ - '0';
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the key matches the component matches, we have a match.
|
|||
|
//
|
|||
|
|
|||
|
if (MatchComponent->Key == Key) {
|
|||
|
NodeMatch = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (NodeMatch) {
|
|||
|
|
|||
|
//
|
|||
|
// This node matches the first component specified in Pathname.
|
|||
|
// Token points at either a ')' or the NULL terminating the
|
|||
|
// Pathname string.
|
|||
|
//
|
|||
|
|
|||
|
if ((*Token == 0) ||
|
|||
|
((*Token == ')' && (*(Token+1) == 0)))
|
|||
|
) {
|
|||
|
|
|||
|
return MatchComponent;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Component = FwCoreGetComponent (Token+1,
|
|||
|
FwGetChild(MatchComponent)
|
|||
|
);
|
|||
|
if (Component == NULL) {
|
|||
|
return MatchComponent;
|
|||
|
} else {
|
|||
|
return Component;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This node does not match our current location in the String.
|
|||
|
// Check the peers.
|
|||
|
//
|
|||
|
// If the search fails with the peers of this node, NULL will be
|
|||
|
// returned, which is what we want to return from this call as well.
|
|||
|
//
|
|||
|
|
|||
|
return FwCoreGetComponent(Pathname, FwGetPeer(MatchComponent));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endif // ndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
PCONFIGURATION_COMPONENT Component;
|
|||
|
|
|||
|
//
|
|||
|
// Start searching from the first child of the root component.
|
|||
|
//
|
|||
|
|
|||
|
if ((Component = FwCoreGetComponent(Pathname,
|
|||
|
FwGetChild(FwGetChild(NULL))))
|
|||
|
!= NULL) {
|
|||
|
return Component;
|
|||
|
} else {
|
|||
|
return FwGetChild(NULL);
|
|||
|
}
|
|||
|
|
|||
|
#else // FAILSAFE_BOOTER
|
|||
|
|
|||
|
return NULL;
|
|||
|
|
|||
|
#endif // ndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
PCONFIGURATION_PACKET Packet;
|
|||
|
|
|||
|
if (Component == NULL) {
|
|||
|
return &Configuration->Packet[0].Component;
|
|||
|
} else {
|
|||
|
Packet = CONTAINING_RECORD(Component,
|
|||
|
CONFIGURATION_PACKET,
|
|||
|
Component);
|
|||
|
|
|||
|
return &((PCONFIGURATION_PACKET)(Packet->Child))->Component;
|
|||
|
}
|
|||
|
|
|||
|
#else // FAILSAFE_BOOTER
|
|||
|
|
|||
|
return NULL;
|
|||
|
|
|||
|
#endif // ndef FAILSAFE_BOOTER
|
|||
|
}
|
|||
|
|
|||
|
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).
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
PCONFIGURATION_PACKET Packet;
|
|||
|
|
|||
|
Packet = CONTAINING_RECORD(Component,
|
|||
|
CONFIGURATION_PACKET,
|
|||
|
Component);
|
|||
|
|
|||
|
if (Packet->Parent == NULL) {
|
|||
|
return NULL;
|
|||
|
} else {
|
|||
|
return &((PCONFIGURATION_PACKET)(Packet->Parent))->Component;
|
|||
|
}
|
|||
|
|
|||
|
#else // FAILSAFE_BOOTER
|
|||
|
|
|||
|
return NULL;
|
|||
|
|
|||
|
#endif // FAILSAFE_BOOTER
|
|||
|
}
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
PCONFIGURATION_PACKET Packet;
|
|||
|
|
|||
|
Packet = CONTAINING_RECORD(Component,
|
|||
|
CONFIGURATION_PACKET,
|
|||
|
Component);
|
|||
|
|
|||
|
if (Packet->Peer == NULL) {
|
|||
|
return NULL;
|
|||
|
} else {
|
|||
|
return &((PCONFIGURATION_PACKET)(Packet->Peer))->Component;
|
|||
|
}
|
|||
|
|
|||
|
#else // FAILSAFE_BOOTER
|
|||
|
|
|||
|
return NULL;
|
|||
|
|
|||
|
#endif // ndef FAILSAFE_BOOTER
|
|||
|
}
|
|||
|
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
ARC_STATUS
|
|||
|
FwGetConfigurationDataIndex(
|
|||
|
OUT PVOID ConfigurationData,
|
|||
|
IN PCONFIGURATION_COMPONENT Component,
|
|||
|
IN ULONG Index,
|
|||
|
IN ULONG Length
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function 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.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCONFIGURATION_PACKET Packet;
|
|||
|
ULONG DataSize;
|
|||
|
PUCHAR SourceData;
|
|||
|
PUCHAR DestinationData;
|
|||
|
|
|||
|
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;
|
|||
|
}
|
|||
|
#endif // ndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
return(FwGetConfigurationDataIndex(ConfigurationData,
|
|||
|
Component,
|
|||
|
0,
|
|||
|
Component->ConfigurationDataLength));
|
|||
|
#else
|
|||
|
|
|||
|
return EINVAL;
|
|||
|
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
#if !defined(FAILSAFE_BOOTER)
|
|||
|
ARC_STATUS
|
|||
|
FwEnvironmentStore (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This loads the entire environment into the non-volatile environment area.
|
|||
|
|
|||
|
Alpha/Jensen uses a segmented block-erase PROM. When the code wants
|
|||
|
to store one environment variable, it must store all of them.
|
|||
|
|
|||
|
This routine must *only* be called from FwSaveConfiguration, which
|
|||
|
does the block-erase and the store of the other part of the
|
|||
|
non-volatile configuration information.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ESUCCESS if the writes were OK.
|
|||
|
EIO otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG Index;
|
|||
|
PNV_CONFIGURATION NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
|||
|
PUCHAR NvChars, VChars;
|
|||
|
|
|||
|
|
|||
|
VChars = VolatileEnvironment;
|
|||
|
NvChars = (PUCHAR)&NvConfiguration->Environment[0];
|
|||
|
|
|||
|
for (Index = 0; Index < LENGTH_OF_ENVIRONMENT; Index++) {
|
|||
|
if (FwROMByteWrite(NvChars++, *VChars++) != ESUCCESS) {
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (FwEnvironmentSetChecksum() != ESUCCESS) {
|
|||
|
return EIO;
|
|||
|
} else {
|
|||
|
return ESUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif // !defined(FAILSAFE_BOOTER)
|
|||
|
|
|||
|
ARC_STATUS
|
|||
|
FwSaveConfiguration (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine stores all of the configuration entries into NVRAM,
|
|||
|
including the associated identifier strings and configuration data.
|
|||
|
|
|||
|
Alpha/Jensen saves the entire configuration structure, i.e.
|
|||
|
including the environment variables, because the ARC CDS + environment
|
|||
|
variables are all in one structure and Jensen has a segmented
|
|||
|
block-erase PROM. Doing a complete save changes the least code.
|
|||
|
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
EIO Some write error happened in the PROM.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
#ifndef FAILSAFE_BOOTER
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#ifdef JENSEN
|
|||
|
//
|
|||
|
// Erase the PROM block we are going to update.
|
|||
|
//
|
|||
|
// N.B. This call erases one block in the underlying ROM set. Therefore,
|
|||
|
// the block size of the ROM had better be at least the size of the
|
|||
|
// ARC data to be written.
|
|||
|
//
|
|||
|
|
|||
|
if (FwROMEraseBlock((PUCHAR)NVRAM_CONFIGURATION) != ESUCCESS) {
|
|||
|
return ENOSPC;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// 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++ ) {
|
|||
|
|
|||
|
if (FwROMByteWrite(NvChars++, 0) != ESUCCESS) {
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
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 is 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++ ) {
|
|||
|
|
|||
|
if (FwROMByteWrite(&NvConfiguration->Identifier[NvIdentifierIndex++],
|
|||
|
Component->Identifier[Index]) !=
|
|||
|
ESUCCESS) {
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
} 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++ ) {
|
|||
|
|
|||
|
if (FwROMByteWrite(&NvConfiguration->EisaData[NvEisaDataIndex++],
|
|||
|
*Data++) != ESUCCESS) {
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If we have written at least two bytes and the last two
|
|||
|
// bytes were zero we are 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++ ) {
|
|||
|
|
|||
|
if (FwROMByteWrite(&NvConfiguration->Data[NvDataIndex++],
|
|||
|
*Data++) != ESUCCESS) {
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Write compressed packet to NVRAM.
|
|||
|
//
|
|||
|
|
|||
|
CompressedChars = (PUCHAR)&CompressedPacket;
|
|||
|
NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
|
|||
|
|
|||
|
for ( Index = 0 ;
|
|||
|
Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
|
|||
|
Index++ ) {
|
|||
|
if (FwROMByteWrite(NvChars++, *CompressedChars++) != ESUCCESS) {
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Zero the rest of the identifier and configuration data areas.
|
|||
|
//
|
|||
|
|
|||
|
for ( Index = NvIdentifierIndex ; Index < LENGTH_OF_IDENTIFIER ; Index++ ) {
|
|||
|
if (FwROMByteWrite(&NvConfiguration->Identifier[Index], 0) != ESUCCESS) {
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
for ( Index = NvDataIndex ; Index < LENGTH_OF_DATA ; Index++ ) {
|
|||
|
if (FwROMByteWrite(&NvConfiguration->Data[Index] ,0) != ESUCCESS) {
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for ( Index = NvEisaDataIndex ; Index < LENGTH_OF_EISA_DATA ; Index++ ) {
|
|||
|
if (FwROMByteWrite(&NvConfiguration->EisaData[Index] ,0) != ESUCCESS) {
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Write configuration data checksum.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
#ifdef ALPHA
|
|||
|
|
|||
|
if ((FwConfigurationSetChecksum() != ESUCCESS)
|
|||
|
||
|
|||
|
(FwEnvironmentStore() != ESUCCESS)
|
|||
|
) {
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
|
|||
|
#else
|
|||
|
FwConfigurationSetChecksum();
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Restore configuration information out of NVRAM. This acts to compress
|
|||
|
// the identifier and configuration data areas if any deletes have been
|
|||
|
// performed.
|
|||
|
//
|
|||
|
|
|||
|
return FwRestoreConfiguration();
|
|||
|
|
|||
|
|
|||
|
#else // !defined(FAILSAFE_BOOTER)
|
|||
|
|
|||
|
//
|
|||
|
// The FailSafe Booter needs this function defined for a call in
|
|||
|
// the scsidisk.c module.
|
|||
|
//
|
|||
|
|
|||
|
return ESUCCESS;
|
|||
|
|
|||
|
#endif // !defined(FAILSAFE_BOOTER)
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#if !defined(FAILSAFE_BOOTER)
|
|||
|
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++ = HalpReadNVByte( 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 parents 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 packets 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++] =
|
|||
|
HalpReadNVByte(
|
|||
|
&NvConfiguration->Identifier[NvIdentifierIndex] );
|
|||
|
Index++;
|
|||
|
} while ( HalpReadNVByte(&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++] =
|
|||
|
HalpReadNVByte( &NvConfiguration->EisaData[NvEisaDataIndex++] );
|
|||
|
|
|||
|
//
|
|||
|
// If at least two bytes have been written and the last
|
|||
|
// two bytes are zero, we are 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++] =
|
|||
|
HalpReadNVByte( &NvConfiguration->Data[NvDataIndex++] );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return(ESUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
#endif // !defined(FAILSAFE_BOOTER)
|
|||
|
|
|||
|
#if !defined(FAILSAFE_BOOTER)
|
|||
|
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)NVRAM_CONFIGURATION;
|
|||
|
|
|||
|
for ( Index = 0 ;
|
|||
|
Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES +
|
|||
|
LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA;
|
|||
|
Index++ ) {
|
|||
|
Checksum1 += HalpReadNVByte( NvChars++ );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Reconstitute checksum and return error if no compare.
|
|||
|
//
|
|||
|
|
|||
|
Checksum2 = (ULONG)HalpReadNVByte( &NvConfiguration->Checksum1[0] ) |
|
|||
|
(ULONG)HalpReadNVByte( &NvConfiguration->Checksum1[1] ) << 8 |
|
|||
|
(ULONG)HalpReadNVByte( &NvConfiguration->Checksum1[2] ) << 16 |
|
|||
|
(ULONG)HalpReadNVByte( &NvConfiguration->Checksum1[3] ) << 24 ;
|
|||
|
|
|||
|
if (Checksum1 != Checksum2) {
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Repeat for the eisa data area.
|
|||
|
//
|
|||
|
|
|||
|
Checksum1 = 0;
|
|||
|
NvChars = (PUCHAR)NvConfiguration->EisaData;
|
|||
|
|
|||
|
for ( Index = 0 ;
|
|||
|
Index < LENGTH_OF_EISA_DATA;
|
|||
|
Index++ ) {
|
|||
|
Checksum1 += HalpReadNVByte( NvChars++ );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Reconstitute checksum and return error if no compare.
|
|||
|
//
|
|||
|
|
|||
|
Checksum2 = (ULONG)HalpReadNVByte( &NvConfiguration->Checksum3[0] ) |
|
|||
|
(ULONG)HalpReadNVByte( &NvConfiguration->Checksum3[1] ) << 8 |
|
|||
|
(ULONG)HalpReadNVByte( &NvConfiguration->Checksum3[2] ) << 16 |
|
|||
|
(ULONG)HalpReadNVByte( &NvConfiguration->Checksum3[3] ) << 24 ;
|
|||
|
|
|||
|
if (Checksum1 != Checksum2) {
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
|
|||
|
return(ESUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
#endif // !defined(FAILSAFE_BOOTER)
|
|||
|
|
|||
|
#if !defined(FAILSAFE_BOOTER)
|
|||
|
ARC_STATUS
|
|||
|
FwConfigurationSetChecksum (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets the configuration checksum.
|
|||
|
|
|||
|
This has been coded for Alpha/Jensen. It assumes that the
|
|||
|
block containing the checksum has already been erased and
|
|||
|
written to, and that the status of these previous operations
|
|||
|
has already been checked.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ESUCCESS if the checksum was written OK.
|
|||
|
EIO otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUCHAR NvChars;
|
|||
|
PNV_CONFIGURATION NvConfiguration;
|
|||
|
ULONG Index;
|
|||
|
ULONG Checksum1;
|
|||
|
|
|||
|
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
|||
|
|
|||
|
FwROMSetARCDataToReadMode();
|
|||
|
|
|||
|
//
|
|||
|
// 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 += HalpReadNVByte( NvChars++ );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set checksum.
|
|||
|
//
|
|||
|
|
|||
|
FwROMResetStatus(&NvConfiguration->Checksum1[0]);
|
|||
|
|
|||
|
if ((FwROMByteWrite(&NvConfiguration->Checksum1[0],
|
|||
|
(UCHAR)(Checksum1 & 0xFF)) != ESUCCESS) ||
|
|||
|
(FwROMByteWrite(&NvConfiguration->Checksum1[1],
|
|||
|
(UCHAR)((Checksum1 >> 8) & 0xFF)) != ESUCCESS) ||
|
|||
|
(FwROMByteWrite(&NvConfiguration->Checksum1[2],
|
|||
|
(UCHAR)((Checksum1 >> 16) & 0xFF)) != ESUCCESS) ||
|
|||
|
(FwROMByteWrite(&NvConfiguration->Checksum1[3],
|
|||
|
(UCHAR)(Checksum1 >> 24)) != ESUCCESS)) {
|
|||
|
return EIO;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Repeat for the eisa data area.
|
|||
|
//
|
|||
|
|
|||
|
Checksum1 = 0;
|
|||
|
NvChars = (PUCHAR)NvConfiguration->EisaData;
|
|||
|
|
|||
|
for ( Index = 0 ;
|
|||
|
Index < LENGTH_OF_EISA_DATA;
|
|||
|
Index++ ) {
|
|||
|
Checksum1 += HalpReadNVByte( NvChars++ );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set checksum.
|
|||
|
//
|
|||
|
|
|||
|
FwROMResetStatus(&NvConfiguration->Checksum3[0]);
|
|||
|
|
|||
|
if ((FwROMByteWrite(&NvConfiguration->Checksum3[0],
|
|||
|
(UCHAR)(Checksum1 & 0xFF)) != ESUCCESS) ||
|
|||
|
(FwROMByteWrite(&NvConfiguration->Checksum3[1],
|
|||
|
(UCHAR)((Checksum1 >> 8) & 0xFF)) != ESUCCESS) ||
|
|||
|
(FwROMByteWrite(&NvConfiguration->Checksum3[2],
|
|||
|
(UCHAR)((Checksum1 >> 16) & 0xFF)) != ESUCCESS) ||
|
|||
|
(FwROMByteWrite(&NvConfiguration->Checksum3[3],
|
|||
|
(UCHAR)(Checksum1 >> 24)) != ESUCCESS)) {
|
|||
|
return EIO;
|
|||
|
} else {
|
|||
|
return ESUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
#endif // !defined(FAILSAFE_BOOTER)
|
|||
|
|
|||
|
#if !defined(FAILSAFE_BOOTER)
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
#endif // !defined(FAILSAFE_BOOTER)
|
|||
|
|
|||
|
#if !defined(FAILSAFE_BOOTER)
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
#endif // !defined(FAILSAFE_BOOTER)
|
|||
|
|
|||
|
#if !defined(FAILSAFE_BOOTER)
|
|||
|
VOID
|
|||
|
FwZeroDecompress (
|
|||
|
IN PVOID InBuffer,
|
|||
|
IN ULONG Index,
|
|||
|
OUT PVOID ConfigurationData,
|
|||
|
IN ULONG Length
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine decompresses 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 // !defined(FAILSAFE_BOOTER)
|