/*++ Copyright (c) 1991 Microsoft Corporation Copyright (c) 1993 Digital Equipment Corporation Module Name: jxenvir.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 a MIPS R3000 or R4000 Jazz system. Author: David M. Robinson (davidro) 13-June-1991 Revision History: 26-May-1992 John DeRosa [DEC] Added Alpha/Jensen hooks. --*/ #include "fwp.h" // // Static data. // UCHAR OutputString[MAXIMUM_ENVIRONMENT_VALUE]; PUCHAR VolatileEnvironment; // // Routine prototypes. // #ifdef MORGAN UCHAR HalpReadNVByte ( IN PUCHAR RAddress ); #endif ARC_STATUS FwEnvironmentSetChecksum ( VOID ); ARC_STATUS FwFindEnvironmentVariable ( IN PCHAR Variable, OUT PULONG VariableIndex, OUT PULONG ValueIndex ); ARC_STATUS FwFindVolatileEnvironmentVariable ( IN PCHAR Variable, OUT PULONG VariableIndex, OUT PULONG ValueIndex ); BOOLEAN EnvironmentVariableIsProtected ( IN PCHAR Variable ); VOID FwEnvironmentInitialize ( VOID ) /*++ Routine Description: This routine initializes the environment routine addresses. Arguments: None. Return Value: None. --*/ { // // Allocate enough memory to load the environment for loaded programs. // VolatileEnvironment = FwAllocatePool(LENGTH_OF_ENVIRONMENT); // // Initialize the environment routine addresses in the system // parameter block. // (PARC_GET_ENVIRONMENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetEnvironmentRoutine] = FwGetEnvironmentVariable; (PARC_SET_ENVIRONMENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SetEnvironmentRoutine] = FwSetEnvironmentVariable; return; } ARC_STATUS FwEnvironmentSetChecksum ( VOID ) /*++ Routine Description: This routine sets the environment area checksum. This must ONLY be called from FwEnvironmentStore, which does the required block erase & storage of the environment variable area. Arguments: None. Return Value: ESUCCESS if the checksum was written OK. EIO otherwise. --*/ { PUCHAR NvChars; PNV_CONFIGURATION NvConfiguration; ULONG Index; ULONG Checksum; NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; // // Form checksum from NVRAM data. // Checksum = 0; NvChars = (PUCHAR)&NvConfiguration->Environment[0]; FwROMSetARCDataToReadMode(); for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT; Index++ ) { Checksum += HalpReadNVByte( NvChars++ ); } // // Write environment checksum. // if ((FwROMByteWrite(&NvConfiguration->Checksum2[0], (UCHAR)(Checksum & 0xFF)) != ESUCCESS) || (FwROMByteWrite(&NvConfiguration->Checksum2[1], (UCHAR)((Checksum >> 8) & 0xFF)) != ESUCCESS) || (FwROMByteWrite(&NvConfiguration->Checksum2[2], (UCHAR)((Checksum >> 16) & 0xFF)) != ESUCCESS) || (FwROMByteWrite(&NvConfiguration->Checksum2[3], (UCHAR)(Checksum >> 24)) != ESUCCESS)) { return EIO; } else { return ESUCCESS; } } PCHAR FwGetEnvironmentVariable ( IN PCHAR Variable ) /*++ 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. If the variable specified by Variable is protected, we get the information from special global variables. See also the jnsetset.c and jxboot.c modules. Arguments: Variable - Supplies a zero terminated string containing an environment variable. Return Value: If successful, returns a zero terminated string that is the value of Variable, otherwise NULL is returned. --*/ { CHAR TempString[MAXIMUM_ENVIRONMENT_VALUE]; PNV_CONFIGURATION NvConfiguration; ULONG VariableIndex; ULONG ValueIndex; ULONG Outdex; EXTENDED_SYSTEM_INFORMATION SystemInfo; // // If Variable is protected, create string and return // if (EnvironmentVariableIsProtected(Variable)) { // // Convert environment variable to uppercase. // Outdex = 0; TempString[0] = 0; while ((*Variable != 0) && (Outdex < MAXIMUM_ENVIRONMENT_VALUE)) { TempString[Outdex] = (((*Variable >= 'a') && (*Variable <= 'z')) ? (*Variable - 'a' + 'A') : *Variable); Outdex++; Variable++; } if (Outdex == MAXIMUM_ENVIRONMENT_VALUE) { // Something is very wrong! return NULL; } TempString[Outdex] = 0; FwReturnExtendedSystemInformation(&SystemInfo); // Hack - I should be a static list of protected // environment variables. if (strstr(TempString, "PHYSICALADDRESSBITS")) { sprintf(OutputString, "PHYSICALADDRESSBITS=%d", SystemInfo.NumberOfPhysicalAddressBits); return OutputString; } else if (strstr(TempString, "MAXIMUMADDRESSSPACENUMBER")) { sprintf(OutputString, "MAXIMUMADDRESSSPACENUMBER=%d", SystemInfo.MaximumAddressSpaceNumber); return OutputString; } else if (strstr(TempString, "SYSTEMSERIALNUMBER")) { sprintf(OutputString, "SYSTEMSERIALNUMBER=%s", SystemInfo.SystemSerialNumber); return OutputString; } else if (strstr(TempString, "CYCLECOUNTERPERIOD")) { sprintf(OutputString, "CYCLECOUNTERPERIOD=%d", SystemInfo.ProcessorCycleCounterPeriod); return OutputString; } else if (strstr(TempString, "PROCESSORPAGESIZE")) { sprintf(OutputString, "PROCESSORPAGESIZE=%d", SystemInfo.ProcessorPageSize); return OutputString; } else { // The requestion environment variable is supposed to // be a protected one, so if we get to here then there // is some internal error in the firmware. Error return. return NULL; } } NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; // // If checksum is wrong, or the variable can not be found, return NULL. // if ((JzEnvironmentCheckChecksum() != ESUCCESS) || (FwFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex) != ESUCCESS)) { return NULL; } // // Copy value to an output string, break on zero terminator or string max. // for ( Outdex = 0 ; Outdex < (MAXIMUM_ENVIRONMENT_VALUE - 1) ; Outdex++ ) { if (HalpReadNVByte(&NvConfiguration->Environment[ValueIndex]) == 0) { break; } OutputString[Outdex] = HalpReadNVByte( &NvConfiguration->Environment[ValueIndex++] ); } // // Zero terminate string, and return. // OutputString[Outdex] = 0; return OutputString; } PCHAR FwGetVolatileEnvironmentVariable ( IN PCHAR Variable ) /*++ Routine Description: This routine searches (not case sensitive) the volatile variables for Variable, and if found returns a pointer to a zero terminated string that contains the value, otherwise a NULL pointer is returned. If the variable specified by Variable is protected, we get the information from special global variables. See also the jnsetset.c and jxboot.c modules. This is used by the Setup utility to provide quick access to the variables. It could completely take the place of FwGetEnvironmentVariable() if there are no calls to it before the volatile area is set up. Arguments: Variable - Supplies a zero terminated string containing an environment variable. Return Value: If successful, returns a zero terminated string that is the value of Variable, otherwise NULL is returned. --*/ { CHAR TempString[MAXIMUM_ENVIRONMENT_VALUE]; PUCHAR String; ULONG Index; ULONG ValueIndex; ULONG VariableIndex; ULONG Outdex; EXTENDED_SYSTEM_INFORMATION SystemInfo; // // If Variable is protected, create string and return // if (EnvironmentVariableIsProtected(Variable)) { // // Convert environment variable to uppercase. // Outdex = 0; TempString[0] = 0; while ((*Variable != 0) && (Outdex < MAXIMUM_ENVIRONMENT_VALUE)) { TempString[Outdex] = (((*Variable >= 'a') && (*Variable <= 'z')) ? (*Variable - 'a' + 'A') : *Variable); Outdex++; Variable++; } if (Outdex == MAXIMUM_ENVIRONMENT_VALUE) { // Something is very wrong! return NULL; } TempString[Outdex] = 0; FwReturnExtendedSystemInformation(&SystemInfo); // Hack - I should be a static list of protected // environment variables. if (strstr(TempString, "PHYSICALADDRESSBITS")) { sprintf(OutputString, "PHYSICALADDRESSBITS=%d", SystemInfo.NumberOfPhysicalAddressBits); return OutputString; } else if (strstr(TempString, "MAXIMUMADDRESSSPACENUMBER")) { sprintf(OutputString, "MAXIMUMADDRESSSPACENUMBER=%d", SystemInfo.MaximumAddressSpaceNumber); return OutputString; } else if (strstr(TempString, "SYSTEMSERIALNUMBER")) { sprintf(OutputString, "SYSTEMSERIALNUMBER=%s", SystemInfo.SystemSerialNumber); return OutputString; } else if (strstr(TempString, "CYCLECOUNTERPERIOD")) { sprintf(OutputString, "CYCLECOUNTERPERIOD=%d", SystemInfo.ProcessorCycleCounterPeriod); return OutputString; } else if (strstr(TempString, "PROCESSORPAGESIZE")) { sprintf(OutputString, "PROCESSORPAGESIZE=%d", SystemInfo.ProcessorPageSize); return OutputString; } else { // The requestion environment variable is supposed to // be a protected one, so if we get to here then there // is some internal error in the firmware. Error return. return NULL; } } if (FwFindVolatileEnvironmentVariable(Variable, &VariableIndex, &ValueIndex) != ESUCCESS) { return NULL; } // // Copy value to an output string, break on zero terminator or string max. // for ( Outdex = 0 ; Outdex < (MAXIMUM_ENVIRONMENT_VALUE - 1) ; Outdex++ ) { if (*(VolatileEnvironment + ValueIndex) == 0) { break; } OutputString[Outdex] = *(VolatileEnvironment + ValueIndex++); } // // Zero terminate string, and return. // OutputString[Outdex] = 0; return OutputString; } #ifdef ALPHA ARC_STATUS FwSetEnvironmentVariable( IN PCHAR Variable, IN PCHAR Value ) /*++ Routine Description: This routine sets Variable (not case sensitive) to Value in the Volatile and ROM areas. Arguments: Variable - Supplies a zero terminated string containing an environment variable. Value - Supplies a zero terminated string containing an environment variable value. Return Value: Whatever is returned from FwCoreSetEnvironmentVariable. This should be: 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. EACCES A protected environment variable cannot be changed. --*/ { return(FwCoreSetEnvironmentVariable(Variable, Value, TRUE)); } #endif #ifdef ALPHA ARC_STATUS FwCoreSetEnvironmentVariable ( IN PCHAR Variable, IN PCHAR Value, IN BOOLEAN UpdateTheROM ) /*++ Routine Description: This routine sets Variable (not case sensitive) to Value. The MIPS version of this code modified the NVRAM directly. Alpha/Jensen has a Flash ROM with a much slower write algorithm. This function is therefore used in two ways: a) By the ARC SetEnvironmentVariable function, to modify the Volatile area and then the PROM configuration block. b) By the setup utility, to modify just the Volatile area. The ROM is updated upon exit from Setup. This checks to see if the variable is protected. If so, an error return is taken. Arguments: Variable - Supplies a zero terminated string containing an environment variable. Value - Supplies a zero terminated string containing an environment variable value. UpdateTheROM - TRUE = update the Volatile area and the ROM. FALSE = update the Volatile area only. 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. EACCES A protected environment variable cannot be changed. --*/ { ULONG VariableIndex; ULONG ValueIndex; ULONG TopOfEnvironment; PCHAR String; PUCHAR VChars; ULONG Count; CHAR Char; // // If checksum is wrong, return EIO; // if (UpdateTheROM && (JzEnvironmentCheckChecksum() != ESUCCESS)) { return EIO; } // // If the environment variable is protected, return EACCES. // if (EnvironmentVariableIsProtected(Variable)) { return EACCES; } 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 (FwFindVolatileEnvironmentVariable(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) { 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; } // // Variable is new. // } else { // // 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; } } } // // 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++; } } if (UpdateTheROM) { // // Now update the Jensen configuration/environment PROM block, // including the appropriate checksums. // return FwSaveConfiguration(); } else { return(ESUCCESS); } } #endif ARC_STATUS FwFindEnvironmentVariable ( 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 ( HalpReadNVByte( &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) && (HalpReadNVByte( &Environment[Index] ) == '=')) { *ValueIndex = ++Index; return ESUCCESS; } // // Move index to the start of the next variable. // while (HalpReadNVByte( &Environment[Index++] ) != 0) { if (Index >= LENGTH_OF_ENVIRONMENT) { return ENOENT; } } } } ARC_STATUS FwFindVolatileEnvironmentVariable ( IN PCHAR Variable, OUT PULONG VariableIndex, OUT PULONG ValueIndex ) /*++ Routine Description: This routine searches (not case sensitive) the Volatile area for Variable. Arguments: Variable - Supplies a zero terminated string containing an environment variable. Return Value: If successful, returns ESUCCESS, otherwise returns ENOENT. --*/ { PUCHAR String; ULONG Index; // // If Variable is null, return immediately. // if (*Variable == 0) { return ENOENT; } Index = 0; while (TRUE) { // // Set string to beginning of Variable. // String = Variable; *VariableIndex = Index; // // Search until the end of the volatile environment. // while (Index < LENGTH_OF_ENVIRONMENT) { // // Convert to uppercase and break if mismatch. // if (*(VolatileEnvironment + Index) != ((*String >= 'a') && (*String <= 'z') ? (*String - 'a' + 'A') : *String) ) { break; } String++; Index++; } // // Check to see if we are at the end of the string and the variable, // which means a match. // if ((*String == 0) && (*(VolatileEnvironment + Index) == '=')) { *ValueIndex = ++Index; return ESUCCESS; } // // Return if we are at the end of the Volatile Environment. // if (Index >= LENGTH_OF_ENVIRONMENT) { return ENOENT; } // // Move index to the start of the next variable. // while (*(VolatileEnvironment + Index++) != 0) { if (Index >= LENGTH_OF_ENVIRONMENT) { return ENOENT; } } } } PCHAR FwEnvironmentLoad ( 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 (JzEnvironmentCheckChecksum() == ESUCCESS) { NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION; // // Copy the data into the volatile area. // NvChars = (PUCHAR)&NvConfiguration->Environment[0]; VChars = VolatileEnvironment; for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT; Index++ ) { *VChars++ = HalpReadNVByte( NvChars++ ); } return (PCHAR)VolatileEnvironment; } else { return NULL; } } BOOLEAN EnvironmentVariableIsProtected ( IN PCHAR Variable ) /*++ Routine Description: Some environment variables are not allowed to be modified by the user. This function checks to see if the argument is such a variable. Arguments: Variable - A zero-terminated string containing an environment variable name. Return Value: TRUE if the environment variable exists and is protected. FALSE if the environment variables does not exist, or is not protected, or if an error occurred. --*/ { CHAR TempString[MAXIMUM_ENVIRONMENT_VALUE]; ULONG Index; // Convert environment variable to uppercase. Index = 0; TempString[0] = 0; while ((*Variable != 0) && (Index < MAXIMUM_ENVIRONMENT_VALUE)) { TempString[Index] = (((*Variable >= 'a') && (*Variable <= 'z')) ? (*Variable - 'a' + 'A') : *Variable); Index++; Variable++; } // Check for string-too-long if (Index == MAXIMUM_ENVIRONMENT_VALUE) { return FALSE; } TempString[Index] = 0; // Check whether this is a protected variable. if ((strstr(TempString, "PHYSICALADDRESSBITS")) || (strstr(TempString, "MAXIMUMADDRESSSPACENUMBER")) || (strstr(TempString, "SYSTEMSERIALNUMBER")) || (strstr(TempString, "CYCLECOUNTERPERIOD")) || (strstr(TempString, "PROCESSORPAGESIZE"))) { return TRUE; } else { return FALSE; } }