1452 lines
28 KiB
C
1452 lines
28 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
Copyright (c) 1992 Digital Equipment Corporation
|
||
|
||
Module Name:
|
||
|
||
xxenvir.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the ARC firmware Environment Variable functions as
|
||
described in the Advanced Risc Computing Specification (Revision 1.00),
|
||
section 3.3.3.11, for the Alpha Jensen system.
|
||
|
||
Author:
|
||
|
||
David M. Robinson (davidro) 13-June-1991
|
||
|
||
|
||
Revision History:
|
||
|
||
Jeff McLeman (DEC) 31-Jul-1992
|
||
|
||
modify for Jensen
|
||
|
||
|
||
This module is for Jensen only. Jensen uses a 1 Mbyte sector eraseable
|
||
flash prom. Due to the long delays needed to store the environment in the
|
||
prom, we must implement a timer, instead of using
|
||
KeStallExecutionProcessor(). The prom may take up to a second to perform
|
||
the function, so we will go away while it is still running, and comeback
|
||
when it is done.
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
|
||
#if defined(JENSEN)
|
||
#include "jxenv.h"
|
||
#endif
|
||
|
||
#include "arccodes.h"
|
||
|
||
//
|
||
// Static data.
|
||
//
|
||
|
||
UCHAR OutputString[MAXIMUM_ENVIRONMENT_VALUE];
|
||
PUCHAR VolatileEnvironment;
|
||
PCHAR VolatileConfig;
|
||
PCHAR VolatileEisaData;
|
||
PCONFIGURATION Configuration;
|
||
|
||
PROMTIMER PromTimer;
|
||
KEVENT PromEvent;
|
||
|
||
//
|
||
// Routine prototypes.
|
||
//
|
||
|
||
ARC_STATUS
|
||
HalpEnvironmentCheckChecksum (
|
||
VOID
|
||
);
|
||
|
||
ARC_STATUS
|
||
HalpEnvironmentSetChecksum (
|
||
VOID
|
||
);
|
||
|
||
ARC_STATUS
|
||
HalpConfigurationSetChecksum (
|
||
VOID
|
||
);
|
||
|
||
ARC_STATUS
|
||
HalpEisaSetChecksum (
|
||
VOID
|
||
);
|
||
|
||
ARC_STATUS
|
||
HalpFindEnvironmentVariable (
|
||
IN PCHAR Variable,
|
||
OUT PULONG VariableIndex,
|
||
OUT PULONG ValueIndex
|
||
);
|
||
|
||
VOID
|
||
HalpInitializePromTimer(
|
||
IN OUT PPROMTIMER PrmTimer,
|
||
IN PVOID FunctionContext
|
||
);
|
||
|
||
VOID
|
||
HalpSetPromTimer(
|
||
IN PPROMTIMER PrmTimer,
|
||
IN ULONG MillisecondsToDelay
|
||
);
|
||
|
||
VOID
|
||
HalpPromDpcHandler(
|
||
IN PVOID SystemSpecific,
|
||
IN PVOID Context,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
);
|
||
|
||
VOID
|
||
HalpPromDelay(
|
||
IN ULONG Milliseconds
|
||
);
|
||
|
||
|
||
ARC_STATUS
|
||
HalpEnvironmentInitialize (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes the environment routine addresses.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
ULONG status = 0;
|
||
|
||
//
|
||
// Determine the ROM type in this machine
|
||
//
|
||
if (HalpROMDetermineMachineROMType() != ESUCCESS) {
|
||
HalDisplayString("*** Unknown ROM Type in Machine ***\n");
|
||
HalDisplayString(" Please contact Digital Field Services \n");
|
||
HalpPromDelay(10*1000);
|
||
HalpReboot();
|
||
}
|
||
|
||
//
|
||
// Allocate enough memory to load the environment for loaded programs.
|
||
//
|
||
|
||
VolatileEnvironment = ExAllocatePool(NonPagedPool, LENGTH_OF_ENVIRONMENT);
|
||
|
||
if (VolatileEnvironment == 0) {
|
||
status = FALSE;
|
||
}
|
||
|
||
HalpEnvironmentLoad();
|
||
|
||
HalpInitializePromTimer(&PromTimer,0);
|
||
|
||
return(status);
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
HalpEnvironmentCheckChecksum (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks the environment area 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->Environment[0];
|
||
|
||
for ( Index = 0 ;
|
||
Index < LENGTH_OF_ENVIRONMENT;
|
||
Index++ ) {
|
||
Checksum1 += READ_PORT_UCHAR( NvChars++ );
|
||
}
|
||
|
||
//
|
||
// Reconstitute checksum and return error if no compare.
|
||
//
|
||
|
||
Checksum2 = (ULONG)READ_PORT_UCHAR( &NvConfiguration->Checksum2[0] ) |
|
||
(ULONG)READ_PORT_UCHAR( &NvConfiguration->Checksum2[1] ) << 8 |
|
||
(ULONG)READ_PORT_UCHAR( &NvConfiguration->Checksum2[2] ) << 16 |
|
||
(ULONG)READ_PORT_UCHAR( &NvConfiguration->Checksum2[3] ) << 24 ;
|
||
|
||
if (Checksum1 != Checksum2) {
|
||
return EIO;
|
||
} else {
|
||
return ESUCCESS;
|
||
}
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
HalGetEnvironmentVariable (
|
||
IN PCHAR Variable,
|
||
IN USHORT length,
|
||
OUT PCHAR Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine searches (not case sensitive) the non-volatile ram for
|
||
Variable, and if found returns a pointer to a zero terminated string that
|
||
contains the value, otherwise a NULL pointer is returned.
|
||
|
||
|
||
Arguments:
|
||
|
||
Variable - Supplies a zero terminated string containing an environment
|
||
variable.
|
||
Length - Supplies the length of the vlaue buffer in bytes
|
||
|
||
Buffer - Supplies a pointer to a buffer that will recieve the
|
||
environment variable.
|
||
|
||
Return Value:
|
||
|
||
If successful, returns a zero terminated string that is the value of
|
||
Variable, otherwise NULL is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
ULONG VariableIndex;
|
||
ULONG ValueIndex;
|
||
ULONG Index;
|
||
ARC_STATUS Status;
|
||
KIRQL OldIrql;
|
||
|
||
//
|
||
// Raise IRQL to synchronize
|
||
//
|
||
|
||
KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
//
|
||
// If checksum is wrong, or the variable can't be found, return NULL.
|
||
//
|
||
|
||
if ((HalpEnvironmentCheckChecksum() != ESUCCESS) ||
|
||
(HalpFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex) != ESUCCESS)) {
|
||
Status = ENOENT;
|
||
} else {
|
||
|
||
//
|
||
// Copy value to an output string, break on zero terminator or string max.
|
||
//
|
||
|
||
for ( Index = 0 ; Index < length ; Index += 1 ) {
|
||
|
||
*Buffer =
|
||
READ_PORT_UCHAR( &NvConfiguration->Environment[ValueIndex] );
|
||
|
||
if (*Buffer== 0) {
|
||
break;
|
||
}
|
||
|
||
Buffer += 1;
|
||
|
||
ValueIndex += 1;
|
||
|
||
}
|
||
if (Index == length) {
|
||
Status = ENOMEM;
|
||
} else {
|
||
Status = ESUCCESS;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Lower IRQL back to where it was
|
||
//
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
#ifdef JENSEN
|
||
|
||
ARC_STATUS
|
||
HalSetEnvironmentVariable (
|
||
IN PCHAR Variable,
|
||
IN PCHAR Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets Variable (not case sensitive) to Value.
|
||
|
||
The MIPS version of this code modified the NVRAM directly.
|
||
For Alpha/Jensen, we have to modify the volatile area and then
|
||
update the PROM configuration block.
|
||
|
||
|
||
Arguments:
|
||
|
||
Variable - Supplies a zero terminated string containing an environment
|
||
variable.
|
||
|
||
Value - Supplies a zero terminated string containing an environment
|
||
variable value.
|
||
|
||
Return Value:
|
||
|
||
Returns ESUCCESS if the set completed successfully, otherwise one of
|
||
the following error codes is returned.
|
||
|
||
ENOSPC No space in NVRAM for set operation.
|
||
|
||
EIO Invalid Checksum.
|
||
|
||
--*/
|
||
|
||
{
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
ULONG VariableIndex;
|
||
ULONG ValueIndex;
|
||
ULONG TopOfEnvironment;
|
||
PCHAR String;
|
||
PUCHAR VChars;
|
||
LONG Count;
|
||
CHAR Char;
|
||
KIRQL OldIrql;
|
||
ARC_STATUS Status;
|
||
|
||
//
|
||
// Raise Irql to Synchronize
|
||
//
|
||
|
||
KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
|
||
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
//
|
||
// If checksum is wrong, return EIO;
|
||
//
|
||
|
||
if (HalpEnvironmentCheckChecksum() != ESUCCESS) {
|
||
KeLowerIrql(OldIrql);
|
||
return EIO;
|
||
}
|
||
|
||
|
||
VChars = VolatileEnvironment;
|
||
|
||
|
||
//
|
||
// Determine the top of the environment space by looking for the first
|
||
// non-null character from the top.
|
||
//
|
||
|
||
TopOfEnvironment = LENGTH_OF_ENVIRONMENT - 1;
|
||
while (VChars[--TopOfEnvironment] == 0) {
|
||
if (TopOfEnvironment == 0) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Adjust TopOfEnvironment to the first new character, unless environment
|
||
// space is empty.
|
||
//
|
||
|
||
if (TopOfEnvironment != 0) {
|
||
TopOfEnvironment += 2;
|
||
}
|
||
|
||
//
|
||
// Check to see if the variable already has a value.
|
||
//
|
||
|
||
Count = LENGTH_OF_ENVIRONMENT - TopOfEnvironment;
|
||
|
||
if (HalpFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex) == ESUCCESS) {
|
||
|
||
//
|
||
// Count free space, starting with the free area at the top and adding
|
||
// the old variable value.
|
||
//
|
||
|
||
for ( String = VChars + ValueIndex ;
|
||
*String != 0 ;
|
||
String++ ) {
|
||
Count++;
|
||
}
|
||
|
||
//
|
||
// Determine if free area is large enough to handle new value, if not
|
||
// return error.
|
||
//
|
||
|
||
for ( String = Value ; *String != 0 ; String++ ) {
|
||
if (Count-- == 0) {
|
||
KeLowerIrql(OldIrql);
|
||
return ENOSPC;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Move ValueIndex to the end of the value and compress strings.
|
||
//
|
||
|
||
while(VChars[ValueIndex++] != 0) {
|
||
}
|
||
|
||
while (ValueIndex < TopOfEnvironment ) {
|
||
VChars[VariableIndex++] = VChars[ValueIndex++];
|
||
}
|
||
|
||
//
|
||
// Adjust new top of environment.
|
||
//
|
||
|
||
TopOfEnvironment = VariableIndex;
|
||
|
||
//
|
||
// Zero to the end.
|
||
//
|
||
|
||
while (VariableIndex < LENGTH_OF_ENVIRONMENT) {
|
||
VChars[VariableIndex++] = 0;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Variable is new.
|
||
//
|
||
|
||
//
|
||
// Determine if free area is large enough to handle new value, if not
|
||
// return error.
|
||
//
|
||
|
||
//
|
||
// From the length of free space subtract new variable's length,
|
||
// Value's length and 2 chars, one for the '=' sign and one of the
|
||
// null terminator.
|
||
//
|
||
|
||
Count -= ( strlen(Variable) + strlen(Value) + 2 );
|
||
|
||
//
|
||
// Check if there is space to fit the new variable.
|
||
//
|
||
|
||
if (Count < 0) {
|
||
KeLowerIrql(OldIrql);
|
||
return ENOSPC;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If Value is not zero, write new variable and value.
|
||
//
|
||
|
||
if (*Value != 0) {
|
||
|
||
//
|
||
// Write new variable, converting to upper case.
|
||
//
|
||
|
||
while (*Variable != 0) {
|
||
VChars[TopOfEnvironment++] =
|
||
((*Variable >= 'a') && (*Variable <= 'z') ? (*Variable - 'a' + 'A') : *Variable);
|
||
Variable++;
|
||
}
|
||
|
||
//
|
||
// Write equal sign.
|
||
//
|
||
|
||
VChars[TopOfEnvironment++] = '=';
|
||
|
||
//
|
||
// Write new value.
|
||
//
|
||
|
||
while (*Value != 0) {
|
||
VChars[TopOfEnvironment++] = *Value++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Lower Irql back to where it was
|
||
//
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
|
||
/* Now update the Jensen PROM */
|
||
|
||
Status = HalpSaveConfiguration();
|
||
|
||
return Status;
|
||
// return ESUCCESS;
|
||
|
||
}
|
||
|
||
#endif
|
||
|
||
ARC_STATUS
|
||
HalpFindEnvironmentVariable (
|
||
IN PCHAR Variable,
|
||
OUT PULONG VariableIndex,
|
||
OUT PULONG ValueIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine searches (not case sensitive) the non-volatile ram for
|
||
Variable.
|
||
|
||
|
||
Arguments:
|
||
|
||
Variable - Supplies a zero terminated string containing an environment
|
||
variable.
|
||
|
||
Return Value:
|
||
|
||
If successful, returns ESUCCESS, otherwise returns ENOENT.
|
||
|
||
--*/
|
||
|
||
{
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
PUCHAR String;
|
||
PUCHAR Environment;
|
||
ULONG Index;
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
//
|
||
// If Variable is null, return immediately.
|
||
//
|
||
|
||
if (*Variable == 0) {
|
||
return ENOENT;
|
||
}
|
||
|
||
Environment = NvConfiguration->Environment;
|
||
Index = 0;
|
||
|
||
while (TRUE) {
|
||
|
||
//
|
||
// Set string to beginning of Variable.
|
||
//
|
||
|
||
String = Variable;
|
||
*VariableIndex = Index;
|
||
|
||
//
|
||
// Search until the end of NVRAM.
|
||
//
|
||
|
||
while ( Index < LENGTH_OF_ENVIRONMENT ) {
|
||
|
||
//
|
||
// Convert to uppercase and break if mismatch.
|
||
//
|
||
|
||
if ( READ_PORT_UCHAR( &Environment[Index] ) !=
|
||
((*String >= 'a') &&
|
||
(*String <= 'z') ?
|
||
(*String - 'a' + 'A') : *String) ) {
|
||
break;
|
||
}
|
||
|
||
String++;
|
||
Index++;
|
||
}
|
||
|
||
//
|
||
// Check to see if we're at the end of the string and the variable,
|
||
// which means a match.
|
||
//
|
||
|
||
if ((*String == 0) && (READ_PORT_UCHAR( &Environment[Index] ) == '=')) {
|
||
*ValueIndex = ++Index;
|
||
return ESUCCESS;
|
||
}
|
||
|
||
//
|
||
// Move index to the start of the next variable.
|
||
//
|
||
|
||
while (READ_PORT_UCHAR( &Environment[Index++] ) != 0) {
|
||
if (Index >= LENGTH_OF_ENVIRONMENT) {
|
||
return ENOENT;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
PCHAR
|
||
HalpEnvironmentLoad (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine loads the entire environment into the volatile environment
|
||
area.
|
||
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
If the checksum is good, a pointer to the environment in returned,
|
||
otherwise NULL is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Index;
|
||
PUCHAR NvChars;
|
||
PUCHAR VChars;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
|
||
if (HalpEnvironmentCheckChecksum() == ESUCCESS) {
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
//
|
||
// Copy the data into the volatile area.
|
||
//
|
||
|
||
NvChars = (PUCHAR)&NvConfiguration->Environment[0];
|
||
VChars = VolatileEnvironment;
|
||
|
||
// READ_PORT_BUFFER_UCHAR(NvChars, VChars, LENGTH_OF_ENVIRONMENT);
|
||
|
||
for ( Index = 0 ;
|
||
Index < LENGTH_OF_ENVIRONMENT;
|
||
Index++ ) {
|
||
*VChars++ = READ_PORT_UCHAR( NvChars++ );
|
||
}
|
||
|
||
return (PCHAR)VolatileEnvironment;
|
||
} else {
|
||
return NULL;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
HalpEnvironmentSetChecksum (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the environment area checksum.
|
||
|
||
For Alpha/Jensen builds, this must ONLY be called from
|
||
HalpEnvironmentStore, as the previous block erase & storage
|
||
of the entire environment variable area must have been done.
|
||
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR NvChars;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
ULONG Index;
|
||
ULONG Checksum;
|
||
KIRQL OldIrql;
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
//
|
||
// Form checksum from NVRAM data.
|
||
//
|
||
|
||
Checksum = 0;
|
||
NvChars = (PUCHAR)&NvConfiguration->Environment[0];
|
||
|
||
HalpROMSetReadMode(NvChars);
|
||
|
||
KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
|
||
|
||
for ( Index = 0 ;
|
||
Index < LENGTH_OF_ENVIRONMENT;
|
||
Index++ ) {
|
||
Checksum += READ_PORT_UCHAR( NvChars++ );
|
||
}
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
//
|
||
// Write environment checksum.
|
||
//
|
||
|
||
|
||
HalpROMResetStatus((PUCHAR)&NvConfiguration->Environment[0]);
|
||
|
||
if ((HalpROMByteWrite( &NvConfiguration->Checksum2[0],
|
||
(UCHAR)(Checksum & 0xFF)) != ESUCCESS) ||
|
||
(HalpROMByteWrite( &NvConfiguration->Checksum2[1],
|
||
(UCHAR)((Checksum >> 8) & 0xFF)) != ESUCCESS) ||
|
||
(HalpROMByteWrite( &NvConfiguration->Checksum2[2],
|
||
(UCHAR)((Checksum >> 16) & 0xFF)) != ESUCCESS) ||
|
||
(HalpROMByteWrite( &NvConfiguration->Checksum2[3],
|
||
(UCHAR)(Checksum >> 24)) != ESUCCESS)) {
|
||
return EIO;
|
||
} else {
|
||
return ESUCCESS;
|
||
|
||
}
|
||
}
|
||
|
||
ARC_STATUS
|
||
HalpEnvironmentStore (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This loads the entire environment into the non-volatile environment area.
|
||
|
||
It's needed only in Jensen, which uses a segmented block-erase
|
||
PROM. When the code wants to store one environment variable,
|
||
it has to store all of them. This causes the least pertubations
|
||
in the firmware code.
|
||
|
||
This routine must *only* be called from HalpSaveConfiguration, 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;
|
||
PUCHAR NvChars, VChars;
|
||
extern PUCHAR VolatileEnvironment; // defined in jxenvir.c
|
||
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
VChars = VolatileEnvironment;
|
||
NvChars = (PUCHAR)&NvConfiguration->Environment[0];
|
||
|
||
|
||
#if DBG
|
||
DbgPrint("WriteEnv: NvChars=%x, VChars=%x, loe = %x\n",
|
||
NvChars,VChars,LENGTH_OF_ENVIRONMENT);
|
||
|
||
#endif
|
||
|
||
for (Index = 0; Index < LENGTH_OF_ENVIRONMENT; Index++) {
|
||
if (HalpROMByteWrite(NvChars++, *VChars++) != ESUCCESS) {
|
||
return EIO;
|
||
}
|
||
|
||
}
|
||
|
||
if (HalpEnvironmentSetChecksum() != ESUCCESS) {
|
||
return EIO;
|
||
}
|
||
|
||
return ESUCCESS;
|
||
|
||
}
|
||
|
||
ARC_STATUS
|
||
HalpSaveConfiguration (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine stores all of the configuration entries into NVRAM,
|
||
including the associated identifier strings and configuration data.
|
||
|
||
The Alpha/Jensen version of this code saves the entire configuration
|
||
structure, i.e. including the environment variables. The ARC CDS
|
||
+ environment variables are all in one structure, and unfortunately
|
||
Jensen has a segmented block-erase PROM instead of an NVRAM. Doing
|
||
a complete save is a change that is least likely to break anything.
|
||
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG EntryIndex;
|
||
ULONG Index;
|
||
// ULONG NumBytes;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
PUCHAR NvChars, VChars;
|
||
ULONG ConfigSize;
|
||
KIRQL OldIrql;
|
||
ULONG EisaSize = LENGTH_OF_EISA_DATA;
|
||
|
||
|
||
#if DBG
|
||
DbgPrint("HalpSaveConfiguration: Entered\n");
|
||
|
||
#endif
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
ConfigSize= (
|
||
(sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES) +
|
||
LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA);
|
||
|
||
|
||
VolatileConfig = ExAllocatePool(NonPagedPool, PAGE_SIZE);
|
||
if (VolatileConfig == NULL) {
|
||
return(ENOMEM);
|
||
}
|
||
|
||
VolatileEisaData = ExAllocatePool(NonPagedPool, PAGE_SIZE);
|
||
if (VolatileEisaData == NULL) {
|
||
ExFreePool(VolatileConfig);
|
||
return(ENOMEM);
|
||
}
|
||
|
||
//
|
||
// Copy the component structure first
|
||
//
|
||
|
||
VChars = VolatileConfig;
|
||
NvChars = (PUCHAR)NVRAM_CONFIGURATION;
|
||
|
||
KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
|
||
|
||
//
|
||
// Copy the config data from the rom to the volatile pool
|
||
//
|
||
|
||
#if DBG
|
||
DbgPrint("HalpSaveConfiguration: Reading Config data\n");
|
||
DbgPrint("Prom address = %x, Volatile Address = %x\n",NvChars,VChars);
|
||
DbgPrint("ConfigSize = %X\n",ConfigSize);
|
||
|
||
#endif
|
||
|
||
for (Index = 0; Index < ConfigSize; Index++) {
|
||
*VChars++ = READ_PORT_UCHAR(NvChars++);
|
||
}
|
||
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
//
|
||
// Now copy the EISA data
|
||
//
|
||
|
||
VChars = VolatileEisaData;
|
||
NvChars = (PUCHAR)&NvConfiguration->EisaData[0];
|
||
|
||
|
||
KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
|
||
|
||
//
|
||
// Copy the eisa data from the rom to the volatile pool
|
||
//
|
||
|
||
#if DBG
|
||
DbgPrint("HalpSaveConfiguration: Reading Eisa data\n");
|
||
DbgPrint("Prom address = %x, Volatile Address = %x\n",NvChars,VChars);
|
||
DbgPrint("ConfigSize = %X\n",EisaSize);
|
||
|
||
#endif
|
||
|
||
for (Index = 0; Index < EisaSize; Index++) {
|
||
*VChars++ = READ_PORT_UCHAR(NvChars++);
|
||
}
|
||
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
/*
|
||
* Erase the PROM block we are going to update.
|
||
*/
|
||
|
||
#if DBG
|
||
DbgPrint("HalpSaveConfiguration: Erasing prom block \n");
|
||
|
||
#endif
|
||
if (HalpROMEraseBlock((PUCHAR)NVRAM_CONFIGURATION) != ESUCCESS) {
|
||
ExFreePool(VolatileEisaData);
|
||
ExFreePool(VolatileConfig);
|
||
return ENOSPC;
|
||
}
|
||
|
||
|
||
//
|
||
// Write the configuration stuff back into the rom.
|
||
//
|
||
|
||
VChars = VolatileConfig;
|
||
NvChars = (PUCHAR)NVRAM_CONFIGURATION;
|
||
|
||
#if DBG
|
||
DbgPrint("HalpSaveConfiguration: Writing Config data\n");
|
||
DbgPrint("Prom address = %x, Volatile Address = %x\n",NvChars,VChars);
|
||
DbgPrint("ConfigSize = %X\n",ConfigSize);
|
||
|
||
#endif
|
||
for (Index = 0; Index < ConfigSize; Index++) {
|
||
if (HalpROMByteWrite(NvChars++, *VChars++) != ESUCCESS) {
|
||
DbgPrint("HalpSaveConfig: Error Writing the Prom byte\n");
|
||
DbgPrint("ERROR: Prom address = %x, Volatile Address = %x\n",NvChars,VChars);
|
||
ExFreePool(VolatileEisaData);
|
||
ExFreePool(VolatileConfig);
|
||
return EIO;
|
||
}
|
||
}
|
||
|
||
#if DBG
|
||
DbgPrint("HalpSaveConfig: Wrote Config data to rom\n");
|
||
|
||
|
||
DbgPrint("Writing Config Checksum...\n");
|
||
|
||
#endif
|
||
if (HalpConfigurationSetChecksum() != ESUCCESS) {
|
||
DbgPrint("HalpSaveConfig: Error setting checksum\n");
|
||
HalpROMSetReadMode((PUCHAR)NvConfiguration);
|
||
ExFreePool(VolatileEisaData);
|
||
ExFreePool(VolatileConfig);
|
||
return EIO;
|
||
}
|
||
|
||
|
||
//
|
||
// Free up the pool
|
||
//
|
||
|
||
ExFreePool(VolatileConfig);
|
||
|
||
|
||
/*
|
||
* If the PROM status is OK then update the environment
|
||
* variables. If *that* is done OK too, return ESUCCESS.
|
||
*/
|
||
|
||
#if DBG
|
||
DbgPrint("HalpSaveConfiguration: Writing Environment Variables\n");
|
||
|
||
#endif
|
||
if (HalpEnvironmentStore() != ESUCCESS) {
|
||
HalpROMSetReadMode((PUCHAR)NVRAM_CONFIGURATION);
|
||
return EIO;
|
||
}
|
||
|
||
|
||
//
|
||
// Write the eisa data back into the rom.
|
||
//
|
||
|
||
VChars = VolatileEisaData;
|
||
NvChars = (PUCHAR)&NvConfiguration->EisaData[0];
|
||
|
||
|
||
#if DBG
|
||
DbgPrint("HalpSaveConfiguration: Writing Eisa Data to Prom\n");
|
||
|
||
DbgPrint("Prom address = %x, Volatile Address = %x\n",NvChars,VChars);
|
||
DbgPrint("ConfigSize = %X\n",EisaSize);
|
||
|
||
#endif
|
||
for (Index = 0; Index < EisaSize; Index++) {
|
||
if (HalpROMByteWrite(NvChars++, *VChars++) != ESUCCESS) {
|
||
return EIO;
|
||
}
|
||
}
|
||
|
||
|
||
if (HalpEisaSetChecksum() != ESUCCESS) {
|
||
HalpROMSetReadMode((PUCHAR)NVRAM_CONFIGURATION);
|
||
return EIO;
|
||
}
|
||
|
||
|
||
//
|
||
// Free up the pool
|
||
//
|
||
|
||
ExFreePool(VolatileEisaData);
|
||
|
||
HalpROMSetReadMode((PUCHAR)NVRAM_CONFIGURATION);
|
||
|
||
//
|
||
// Re-read the prom block back into pool for later use
|
||
//
|
||
|
||
#if DBG
|
||
DbgPrint("HalpSaveConfiguration: ReLoading Environment\n");
|
||
|
||
#endif
|
||
HalpEnvironmentLoad();
|
||
|
||
return ESUCCESS;
|
||
}
|
||
|
||
ARC_STATUS
|
||
HalpConfigurationSetChecksum (
|
||
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. This is because we have to set the
|
||
PROM into ReadArray mode in order to compute the checksum,
|
||
and this will cause previous status to be lost.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None. The PROM status is *not* checked by this function!
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR NvChars;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
ULONG Index;
|
||
ULONG Checksum1;
|
||
KIRQL OldIrql;
|
||
|
||
#if DBG
|
||
|
||
DbgPrint("In set Config Checksum\n");
|
||
|
||
#endif
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
|
||
//
|
||
// Form checksum from NVRAM data.
|
||
//
|
||
|
||
Checksum1 = 0;
|
||
NvChars = (PUCHAR)NvConfiguration;
|
||
|
||
HalpROMSetReadMode(NvChars);
|
||
|
||
KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
|
||
|
||
for ( Index = 0 ;
|
||
Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES +
|
||
LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA;
|
||
Index++ ) {
|
||
Checksum1 += READ_PORT_UCHAR( NvChars++ );
|
||
}
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
//
|
||
// Set checksum.
|
||
//
|
||
|
||
HalpROMResetStatus((PUCHAR)NvConfiguration);
|
||
|
||
if ((HalpROMByteWrite( &NvConfiguration->Checksum1[0],
|
||
(UCHAR)(Checksum1 & 0xFF)) != ESUCCESS) ||
|
||
(HalpROMByteWrite( &NvConfiguration->Checksum1[1],
|
||
(UCHAR)((Checksum1 >> 8) & 0xFF)) != ESUCCESS) ||
|
||
(HalpROMByteWrite( &NvConfiguration->Checksum1[2],
|
||
(UCHAR)((Checksum1 >> 16) & 0xFF)) != ESUCCESS) ||
|
||
(HalpROMByteWrite( &NvConfiguration->Checksum1[3],
|
||
(UCHAR)(Checksum1 >> 24)) != ESUCCESS)) {
|
||
return EIO;
|
||
} else {
|
||
return ESUCCESS;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
ARC_STATUS
|
||
HalpEisaSetChecksum (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the eisa data 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. This is because we have to set the
|
||
PROM into ReadArray mode in order to compute the checksum,
|
||
and this will cause previous status to be lost.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None. The PROM status is *not* checked by this function!
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR NvChars;
|
||
PNV_CONFIGURATION NvConfiguration;
|
||
ULONG Index;
|
||
ULONG Checksum3;
|
||
KIRQL OldIrql;
|
||
|
||
|
||
NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
|
||
|
||
|
||
//
|
||
// Form checksum from NVRAM data.
|
||
//
|
||
|
||
Checksum3 = 0;
|
||
NvChars = (PUCHAR)&NvConfiguration->EisaData[0];
|
||
|
||
HalpROMSetReadMode(NvChars);
|
||
|
||
KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
|
||
|
||
for ( Index = 0 ;
|
||
Index < LENGTH_OF_EISA_DATA;
|
||
Index++ ) {
|
||
Checksum3 += READ_PORT_UCHAR( NvChars++ );
|
||
}
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
//
|
||
// Set checksum.
|
||
//
|
||
|
||
|
||
HalpROMResetStatus((PUCHAR)&NvConfiguration->EisaData[0]);
|
||
|
||
if ((HalpROMByteWrite( &NvConfiguration->Checksum3[0],
|
||
(UCHAR)(Checksum3 & 0xFF)) != ESUCCESS) ||
|
||
(HalpROMByteWrite( &NvConfiguration->Checksum3[1],
|
||
(UCHAR)((Checksum3 >> 8) & 0xFF)) != ESUCCESS) ||
|
||
(HalpROMByteWrite( &NvConfiguration->Checksum3[2],
|
||
(UCHAR)((Checksum3 >> 16) & 0xFF)) != ESUCCESS) ||
|
||
(HalpROMByteWrite( &NvConfiguration->Checksum3[3],
|
||
(UCHAR)(Checksum3 >> 24)) != ESUCCESS)) {
|
||
return EIO;
|
||
} else {
|
||
return ESUCCESS;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
VOID
|
||
HalpInitializePromTimer(
|
||
IN OUT PPROMTIMER PrmTimer,
|
||
IN PVOID FunctionContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will initialize the timer needed for waits on prom updates
|
||
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Initialize the signaling event
|
||
//
|
||
|
||
KeInitializeEvent(
|
||
&PromEvent,
|
||
NotificationEvent,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// Initialize the timer
|
||
//
|
||
|
||
KeInitializeTimer(
|
||
&(PrmTimer->Timer)
|
||
);
|
||
|
||
|
||
//
|
||
// Setup the DPC that will signal the event
|
||
//
|
||
|
||
KeInitializeDpc(
|
||
&(PrmTimer->Dpc),
|
||
(PKDEFERRED_ROUTINE)HalpPromDpcHandler,
|
||
FunctionContext
|
||
);
|
||
|
||
|
||
}
|
||
|
||
VOID
|
||
HalpSetPromTimer(
|
||
IN PPROMTIMER PrmTimer,
|
||
IN ULONG MillisecondsToDelay
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will initialize the timer needed for waits on prom updates
|
||
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
LARGE_INTEGER FireUpTime;
|
||
|
||
if (MillisecondsToDelay == 0 ) {
|
||
MillisecondsToDelay = 1;
|
||
}
|
||
|
||
FireUpTime.LowPart = -10000 * MillisecondsToDelay;
|
||
FireUpTime.HighPart = -1;
|
||
|
||
//
|
||
// Set the timer
|
||
//
|
||
|
||
KeSetTimer(
|
||
&PrmTimer->Timer,
|
||
FireUpTime,
|
||
&PrmTimer->Dpc
|
||
);
|
||
}
|
||
|
||
VOID
|
||
HalpPromDpcHandler(
|
||
IN PVOID SystemSpecific,
|
||
IN PVOID Context,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the DPC handler for the prom timer
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
UNREFERENCED_PARAMETER(SystemSpecific);
|
||
UNREFERENCED_PARAMETER(SystemArgument1);
|
||
UNREFERENCED_PARAMETER(SystemArgument2);
|
||
|
||
|
||
//
|
||
// Set the event so the waiting thread will continue.
|
||
//
|
||
|
||
KeSetEvent(
|
||
&PromEvent,
|
||
0L,
|
||
FALSE
|
||
);
|
||
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
HalpPromDelay(
|
||
IN ULONG Milliseconds
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine calls the timer and waits for it to fire
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
LARGE_INTEGER TimeOut;
|
||
NTSTATUS status;
|
||
|
||
TimeOut.LowPart = -10000 * (Milliseconds * 2);
|
||
TimeOut.HighPart = -1;
|
||
|
||
|
||
//
|
||
// Start the timer
|
||
//
|
||
|
||
HalpSetPromTimer(&PromTimer, Milliseconds);
|
||
|
||
//
|
||
// Wait for the event to be signaled
|
||
//
|
||
|
||
status =
|
||
KeWaitForSingleObject(
|
||
&PromEvent,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
&TimeOut
|
||
);
|
||
|
||
//
|
||
// Reset the event
|
||
//
|
||
|
||
KeResetEvent(
|
||
&PromEvent
|
||
);
|
||
|
||
|
||
return;
|
||
}
|