534 lines
12 KiB
C
534 lines
12 KiB
C
#if defined(TAGGED_NVRAM)
|
||
|
||
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation
|
||
|
||
Module Name:
|
||
|
||
nvenv.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.
|
||
|
||
Author:
|
||
|
||
David M. Robinson (davidro) 13-June-1991
|
||
|
||
|
||
Revision History:
|
||
|
||
Dave Richards 94.11.03
|
||
|
||
Added support for the tagged NVRAM layout/API.
|
||
|
||
James Livingston 94.05.17
|
||
|
||
Fix a coding error that caused NVRAM to get trashed in the attempt
|
||
to update a nearly full environment variable space.
|
||
|
||
Steve Jenness 93.12.20
|
||
|
||
The firmware still requires the naked checksum set and check
|
||
routines. Add them back in under the AXP_FIRMWARE conditional
|
||
until the jxenvir.c in the firmware and the environ.c files
|
||
are rationalized.
|
||
|
||
Steve Jenness. 93.12.17
|
||
|
||
Reduce the reads and writes to the NVRAM part. Some parts are
|
||
slow to access (especially on writes). Do NVRAM access only when
|
||
really necessary. Remove use of HalpCopyNVRamBuffer because it is
|
||
too difficult to make generically fast (put more intelligence
|
||
in higher code instead).
|
||
|
||
Steve Brooks. 6-Oct 1993 remove all platform and device specific references
|
||
|
||
These routines have been restructured to be platform and device
|
||
independant. All calls access the NVRAM via the calls
|
||
HalpReadNVRamBuffer, HalpWriteNVRamBuffer, and HalpCopyNVRamBuffer
|
||
|
||
Jeff McLeman (DEC) 31-Jul-1992 modify for Jensen
|
||
|
||
--*/
|
||
|
||
#include "arccodes.h"
|
||
#include "halp.h"
|
||
#include "nvram.h"
|
||
|
||
//
|
||
// Routine prototypes.
|
||
//
|
||
|
||
ARC_STATUS
|
||
HalpFindEnvironmentVariable (
|
||
IN PCHAR Variable,
|
||
OUT PULONG VariableIndex,
|
||
OUT PULONG ValueIndex
|
||
);
|
||
|
||
ARC_STATUS
|
||
HalGetEnvironmentVariable (
|
||
IN PCHAR Variable,
|
||
IN USHORT length,
|
||
OUT PCHAR Buffer
|
||
);
|
||
|
||
ARC_STATUS
|
||
HalSetEnvironmentVariable (
|
||
IN PCHAR Variable,
|
||
IN PCHAR Value
|
||
);
|
||
|
||
#ifdef AXP_FIRMWARE
|
||
|
||
#pragma alloc_text(DISTEXT, HalpFindEnvironmentVariable )
|
||
#pragma alloc_text(DISTEXT, HalGetEnvironmentVariable )
|
||
#pragma alloc_text(DISTEXT, HalSetEnvironmentVariable )
|
||
|
||
#endif // AXP_FIRMWARE
|
||
|
||
ARC_STATUS
|
||
HalpFindEnvironmentVariable (
|
||
IN PCHAR Variable,
|
||
OUT PULONG VariableIndex,
|
||
OUT PULONG ValueIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine searches (not case sensitive) the supplied NVRAM image
|
||
for the given Variable.
|
||
|
||
Arguments:
|
||
|
||
Variable - Supplies a zero terminated string containing an environment
|
||
variable.
|
||
VariableIndex - Returned byte offset into Environment of the
|
||
Variable if found.
|
||
ValueIndex - Returned byte offset into Environment of the
|
||
value of the Variable if found.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS - Variable found and indicies returned.
|
||
ENOENT - Variable not found.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG EnvironmentOffset;
|
||
ULONG EnvironmentLength;
|
||
PUCHAR String;
|
||
UCHAR Char;
|
||
ULONG Index;
|
||
|
||
//
|
||
// If Variable is null, return immediately.
|
||
//
|
||
|
||
if (*Variable == 0) {
|
||
return ENOENT;
|
||
}
|
||
|
||
//
|
||
// Get the offset and length of the environment in NVRAM.
|
||
//
|
||
|
||
EnvironmentOffset = HalpGetNVRamEnvironmentOffset();
|
||
EnvironmentLength = HalpGetNVRamEnvironmentLength();
|
||
|
||
Index = 0;
|
||
|
||
while (TRUE) {
|
||
|
||
//
|
||
// Set string to beginning of Variable.
|
||
//
|
||
|
||
String = Variable;
|
||
*VariableIndex = EnvironmentOffset + Index;
|
||
|
||
//
|
||
// Search until the end of NVRAM.
|
||
//
|
||
|
||
while ( Index < EnvironmentLength ) {
|
||
|
||
//
|
||
// Convert to uppercase and break if mismatch.
|
||
//
|
||
|
||
Char = HalpGetNVRamUchar(EnvironmentOffset + Index);
|
||
|
||
if ( Char != ((*String >= 'a') && (*String <= 'z') ?
|
||
(*String - 'a' + 'A') : *String) ) {
|
||
break;
|
||
}
|
||
|
||
String++;
|
||
Index++;
|
||
}
|
||
|
||
if ( Index == EnvironmentLength )
|
||
return ENOENT;
|
||
|
||
//
|
||
// Check to see if we're at the end of the string and the variable,
|
||
// which means a match.
|
||
//
|
||
|
||
Char = HalpGetNVRamUchar(EnvironmentOffset + Index);
|
||
if ((*String == 0) && (Char == '=')) {
|
||
*ValueIndex = EnvironmentOffset + ++Index;
|
||
return ESUCCESS;
|
||
}
|
||
|
||
//
|
||
// Move index to the start of the next variable.
|
||
//
|
||
|
||
do {
|
||
Char = HalpGetNVRamUchar(EnvironmentOffset + Index++);
|
||
|
||
if (Index >= EnvironmentLength) {
|
||
return ENOENT;
|
||
}
|
||
|
||
} while (Char != 0);
|
||
|
||
}
|
||
}
|
||
|
||
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 value buffer in bytes
|
||
|
||
Buffer - Supplies a pointer to a buffer that will recieve the
|
||
environment variable.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS - Buffer contains the zero terminated string value of Variable.
|
||
ENOENT - The variable doesn't exist in the environment.
|
||
ENOMEM - The variable exists, but the value is longer than Length.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG NvChars;
|
||
ULONG VariableIndex;
|
||
ULONG ValueIndex;
|
||
ULONG Index;
|
||
ARC_STATUS Status;
|
||
|
||
//
|
||
// If checksum is wrong, or the variable can't be found, return NULL.
|
||
//
|
||
|
||
if ((!HalpIsNVRamRegion0Valid()) ||
|
||
(HalpFindEnvironmentVariable(Variable,
|
||
&VariableIndex,
|
||
&ValueIndex) != ESUCCESS)) {
|
||
Status = ENOENT;
|
||
} else {
|
||
|
||
//
|
||
// Copy value to an output string, break on zero terminator
|
||
// or string max.
|
||
//
|
||
|
||
NvChars = ValueIndex;
|
||
for ( Index = 0 ; Index < length ; Index += 1 ) {
|
||
if ( (*Buffer++ = HalpGetNVRamUchar(NvChars++)) == 0 ) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (Index == length) {
|
||
Status = ENOMEM;
|
||
} else {
|
||
Status = ESUCCESS;
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
HalSetEnvironmentVariable (
|
||
IN PCHAR Variable,
|
||
IN PCHAR Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets Variable (not case sensitive) to Value.
|
||
|
||
Arguments:
|
||
|
||
Variable - Supplies a zero terminated string containing an environment
|
||
variable.
|
||
|
||
Value - Supplies a zero terminated string containing an environment
|
||
variable value.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS - The set completed successfully
|
||
ENOSPC - No space in NVRAM for set operation.
|
||
EIO - Invalid Checksum.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG EnvironmentOffset;
|
||
ULONG EnvironmentLength;
|
||
ULONG VariableIndex;
|
||
ULONG ValueIndex;
|
||
ULONG TopOfEnvironment;
|
||
PCHAR String;
|
||
ULONG NvChars;
|
||
LONG Count;
|
||
CHAR Char;
|
||
|
||
//
|
||
// If checksum is wrong, return EIO;
|
||
//
|
||
|
||
if (!HalpIsNVRamRegion0Valid()) {
|
||
return EIO;
|
||
}
|
||
|
||
//
|
||
// Get the offset and length of the environment in NVRAM.
|
||
//
|
||
|
||
EnvironmentOffset = HalpGetNVRamEnvironmentOffset();
|
||
EnvironmentLength = HalpGetNVRamEnvironmentLength();
|
||
|
||
//
|
||
//smjfix - examine the boundary condition where the environment space
|
||
// is exactly filled.
|
||
|
||
//
|
||
// Determine the top of the environment space by looking for the first
|
||
// non-null character from the top.
|
||
//
|
||
|
||
TopOfEnvironment = EnvironmentOffset + EnvironmentLength - 1;
|
||
|
||
do {
|
||
Char = HalpGetNVRamUchar(TopOfEnvironment);
|
||
|
||
} while ( Char == 0 && (--TopOfEnvironment > EnvironmentOffset) );
|
||
|
||
//
|
||
// Adjust TopOfEnvironment to the first new character, unless environment
|
||
// space is empty, or the environment is exactly full. In the latter
|
||
// case, the new value MUST fit into the space taken by the old.
|
||
//
|
||
|
||
if (TopOfEnvironment != EnvironmentOffset &&
|
||
TopOfEnvironment < EnvironmentOffset + EnvironmentLength - 2) {
|
||
TopOfEnvironment += 2;
|
||
}
|
||
|
||
//
|
||
// Handle the case where the content of the NVRAM has been corrupted
|
||
// such that the last character in the environment is non-zero.
|
||
//
|
||
|
||
Count = (EnvironmentOffset + EnvironmentLength - 1) - TopOfEnvironment;
|
||
if (Count < 0) {
|
||
return ENOSPC;
|
||
}
|
||
|
||
|
||
//
|
||
// Check to see if the variable already has a value.
|
||
//
|
||
|
||
if (HalpFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex)
|
||
== ESUCCESS) {
|
||
ULONG SizeOfValue = strlen(Value);
|
||
|
||
if (SizeOfValue == HalpGetNVRamStringLength(ValueIndex)) {
|
||
|
||
//
|
||
// Overwrite the current variable in place.
|
||
//
|
||
|
||
HalpMoveMemoryToNVRam(ValueIndex, Value, SizeOfValue);
|
||
|
||
//
|
||
// Suppress the append of the variable to the end of the
|
||
// environment variable data.
|
||
//
|
||
|
||
*Value = 0;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Count free space, starting with the free area at the top and
|
||
// adding the old variable value.
|
||
//
|
||
|
||
for ( NvChars = ValueIndex;
|
||
NvChars <= TopOfEnvironment;
|
||
NvChars++ ) {
|
||
|
||
Char = HalpGetNVRamUchar(NvChars);
|
||
if ( Char == 0 )
|
||
break;
|
||
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) {
|
||
return ENOSPC;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Move ValueIndex to the end of the value and compress strings.
|
||
//
|
||
|
||
do {
|
||
Char = HalpGetNVRamUchar(ValueIndex++);
|
||
} while( Char != 0 );
|
||
|
||
Count = TopOfEnvironment - ValueIndex;
|
||
|
||
HalpMoveNVRamToNVRam(VariableIndex, ValueIndex, Count);
|
||
|
||
//
|
||
// Adjust new top of environment.
|
||
//
|
||
|
||
TopOfEnvironment = VariableIndex+Count;
|
||
|
||
//
|
||
// Zero to the end.
|
||
//
|
||
|
||
Count = EnvironmentOffset + EnvironmentLength - TopOfEnvironment;
|
||
Char = 0;
|
||
while ( Count -- ) {
|
||
HalpSetNVRamUchar(TopOfEnvironment + Count, Char);
|
||
}
|
||
}
|
||
|
||
} 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) {
|
||
return ENOSPC;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// If Value is not zero, append the new variable and value.
|
||
//
|
||
|
||
if (*Value != 0) {
|
||
|
||
//
|
||
// Write new variable, converting to upper case.
|
||
//
|
||
while ( *Variable != 0 ) {
|
||
|
||
Char = ((*Variable >= 'a') && (*Variable <= 'z') ?
|
||
(*Variable - 'a' + 'A') : *Variable);
|
||
|
||
HalpSetNVRamUchar(TopOfEnvironment, Char);
|
||
|
||
Variable ++;
|
||
TopOfEnvironment ++;
|
||
}
|
||
|
||
//
|
||
// Write equal sign.
|
||
//
|
||
|
||
Char = '=';
|
||
HalpSetNVRamUchar(TopOfEnvironment++, Char);
|
||
|
||
//
|
||
// Write new value.
|
||
//
|
||
|
||
for ( Count = 0; Value[Count] != 0; Count ++ )
|
||
;
|
||
|
||
HalpMoveMemoryToNVRam(TopOfEnvironment, Value, Count);
|
||
|
||
}
|
||
|
||
//
|
||
// Write the environment variables out to NVRAM and checksum it.
|
||
//
|
||
|
||
if (HalpSynchronizeNVRamRegion0(TRUE)) {
|
||
return ESUCCESS;
|
||
} else {
|
||
return EIO;
|
||
}
|
||
}
|
||
|
||
#endif // TAGGED_NVRAM
|