mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1451 lines
28 KiB
1451 lines
28 KiB
/*++
|
|
|
|
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;
|
|
}
|