/* * Copyright (c) 1995 FirePower Systems, Inc. * DO NOT DISTRIBUTE without permission * * $RCSfile: pxenviro.c $ * $Revision: 1.12 $ * $Date: 1996/05/18 00:28:50 $ * $Locker: $ */ /*********************************************************************** Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file contains copyrighted material. Use of this file is restricted by the provisions of a Motorola Software License Agreement. File Name: PXENVIRO.C Purpose: Provides the interface to the PowerPC ARC firmware. Globals: none Functions: ULONG HalGetEnvironmentVariable(); ULONG HalSetEnvironmentVariable(); History: 27-Jul-1993 Steve Johns Original version 31-Jan-1994 Steve Johns Added checksum logic 08-Jul-1994 Steve Johns Made Environment variable routines PReP compliant 12-20-94 Heavly re-written by Sol Kavy at FirePower to clean-up the code and properly suppor the Prep spec. NOTES: The fields in the NVRAM structure follow Big-Endian byte ordering. Each environment variable is stored as an zero-terminated ASCII string: =,0 ***********************************************************************/ #define USE_SPINLOCKS FALSE #include "halp.h" //#include "fpdebug.h" #include "arccodes.h" #include "eisa.h" #include "pxnvrsup.h" #include "fpnvram.h" USHORT HalpComputeCrc(VOID); // // Debug Define (first paramter is a place holder for future // level handling: 1 = Calls, 2 = Routine Info). // #define NDBG(_lvl, _print) PKSPIN_LOCK NVRAM_Spinlock; #define NVSIZE 4096 // // Location of the NVRAM registers // // #include "phsystem.h" // extern PVOID HalpIoControlBase; #define NVRAM ((PNVRAM_CONTROL) (HalpIoControlBase)) // #define NVRAM ((PNVRAM_CONTROL) 0xb1000000) // // Dummy pointer used to byte get offset information // PVOID NvramPtr=0; #define NVMAP ((PHEADER) NvramPtr) extern BOOLEAN NvramFailure; // // Use the routine from fpds1385.c to access the nvram chip. These // routines protect their accesses with the appropriate spin locks // to make sure the actions are atomic // USHORT HalpReadNvramUshort(USHORT Index) { return (HalpDS1385ReadNVRAM(Index) << 8) + HalpDS1385ReadNVRAM((USHORT)(Index+1)); } ULONG HalpReadNvramUlong(USHORT Index) { ULONG ReturnValue; // // Read Big-Endian ULONG value & convert to Little-Endian // ReturnValue = ((ULONG) HalpReadNvramUshort(Index) << 16) + (ULONG) HalpReadNvramUshort((USHORT)(Index+2)); return ReturnValue; } VOID HalpWriteNvramUshort(USHORT Index, USHORT Value) { // // Write USHORT value in Big-Endian // HalpDS1385WriteNVRAM(Index, (UCHAR) (Value >> 8)); HalpDS1385WriteNVRAM((USHORT)(Index+1),(UCHAR) Value); } VOID HalpWriteNvramUlong( USHORT Index, ULONG Value) { // // Write ULONG value in Big-Endian // HalpWriteNvramUshort(Index, (USHORT) (Value >> 16)); HalpWriteNvramUshort((USHORT)(Index+2),(USHORT) Value); } // // DumpNVRAM // // Description: // Used during bring-up to ensure that NVRAM is being handled // correctly. Nothing more than a bunch of DbgPrint of NVRAM // VOID DumpNVRAM() { DbgPrint("HalpIoControlBase is at 0x%x\n", HalpIoControlBase); DbgPrint("NVRAM is at 0x%x\n", NVRAM); DbgPrint("NvramIndexLo is at 0x%x\n", &(NVRAM->NvramIndexLo)); DbgPrint("NvramIndexHi is at 0x%x\n", &(NVRAM->NvramIndexHi)); DbgPrint("NvramData is at 0x%x\n", &(NVRAM->NvramData)); DbgPrint("NVRAM USHORT Size(%d): %d\n", (USHORT)&NVMAP->Size, HalpReadNvramUshort((USHORT)&NVMAP->Size)); DbgPrint("NVRAM UCHAR Version(%d): %d\n", (USHORT)&NVMAP->Version, HalpDS1385ReadNVRAM((USHORT)&NVMAP->Version)); DbgPrint("NVRAM UCHAR Revision(%d): %d\n", (USHORT)&NVMAP->Revision, HalpDS1385ReadNVRAM((USHORT)&NVMAP->Revision)); DbgPrint("NVRAM USHORT Crc1(%d): 0x%x\n", (USHORT)&NVMAP->Crc1, HalpReadNvramUshort((USHORT)&NVMAP->Crc1)); DbgPrint("NVRAM USHORT Crc2(%d): 0x%x\n", (USHORT)&NVMAP->Crc2, HalpReadNvramUshort((USHORT)&NVMAP->Crc2)); DbgPrint("NVRAM UCHAR LastOS(%d): %d\n", (USHORT)&NVMAP->LastOS, HalpDS1385ReadNVRAM((USHORT)&NVMAP->LastOS)); DbgPrint("NVRAM UCHAR Endian(%d): %d\n", (USHORT)&NVMAP->Endian, HalpDS1385ReadNVRAM((USHORT)&NVMAP->Endian)); DbgPrint("NVRAM UCHAR OSAreaUsage(%d): %d\n", (USHORT)&NVMAP->OSAreaUsage, HalpDS1385ReadNVRAM((USHORT)&NVMAP->OSAreaUsage)); DbgPrint("NVRAM UCHAR PMMode(%d): %d\n", (USHORT)&NVMAP->PMMode, HalpDS1385ReadNVRAM((USHORT)&NVMAP->PMMode)); DbgPrint("NVRAM ULONG GEAddress(%d): %d\n", (USHORT)&NVMAP->GEAddress, HalpReadNvramUlong((USHORT)&NVMAP->GEAddress)); DbgPrint("NVRAM ULONG GELength(%d): %d\n", (USHORT)&NVMAP->GELength, HalpReadNvramUlong((USHORT)&NVMAP->GELength)); { USHORT StartIndex, LastIndex, Index; UCHAR NvramChar; BOOLEAN LastNull = TRUE; // Assume it DbgPrint("NVRAM Global Environment Area:\n"); StartIndex = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GEAddress)); LastIndex = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GELength)); LastIndex += StartIndex - 1; for (Index = StartIndex; Index <= LastIndex; Index++) { NvramChar = HalpDS1385ReadNVRAM(Index); if (NvramChar == '\0') { LastNull = TRUE; } else { if (LastNull == TRUE) { DbgPrint("\n[%d]: ", Index); } DbgPrint("%c", NvramChar); LastNull = FALSE; } } DbgPrint("\n"); } DbgPrint("Checking Our version of CRC"); DbgPrint("Compute CRC returns 0x%x\n", HalpComputeCrc()); } UCHAR HalpGetEnvironmentInfo( OPTIONAL PUSHORT TotalSize, OPTIONAL PUSHORT FreeSize, OPTIONAL PULONG pCrc) { USHORT Index; USHORT InUse, TotalLength; UCHAR DataByte1, DataByte2; NDBG(1, DbgPrint("HalpGetEnvironmentInfo: called\n");); TotalLength = (USHORT) HalpReadNvramUlong((USHORT) &NVMAP->GELength); if (TotalSize != NULL) *TotalSize = TotalLength; if (FreeSize != NULL) { // // Compute how much NVRAM is in use // InUse = 0; Index = (USHORT)HalpReadNvramUlong ((USHORT) &NVMAP->GEAddress); DataByte1 = HalpDS1385ReadNVRAM(Index++); DataByte2 = DataByte1; while (DataByte1 | DataByte2) { DataByte1 = DataByte2; DataByte2 = HalpDS1385ReadNVRAM(Index++); InUse++; } *FreeSize = TotalLength - InUse; } if (pCrc != NULL) { *pCrc = HalpReadNvramUshort((USHORT) &NVMAP->Crc1); } return(HalpDS1385ReadNVRAM((USHORT) &NVMAP->Version)); } // // HalpAddByteCrc // // Description: // Use the X^16 + X^12 + X^5 + 1, Polynomial for CRC // // Input: // Stored in NVRAM // // Output: // New Crc Value // USHORT HalpAddByteCrc(USHORT CurrentCrc, USHORT Index) { UCHAR Byte; UCHAR CrcLo, CrcHi; USHORT x,y,z; Byte = HalpDS1385ReadNVRAM(Index); CrcLo = CurrentCrc &0xff; CrcHi = CurrentCrc >> 8; x = (CrcLo << 8) | (CrcHi^Byte); y = (CrcHi^Byte) << 8; z = ((y >> 12) | (y << 4)) & 0xf00f; x = x^z; z = ((y << 13) | (y >> 3)) & 0x1fe0; x = x^z; z = y&0xf000; x = x^z; z = ((y<<9) | (y>>7)) & 0x1e0; x = x^z; return(x); } // // HalpComputeCrc // // Description: // Find the parts that are part of the crc and compute the // crc against them. // // Input: // Stored in NVRAM // // Output: // USHORT HalpComputeCrc(VOID) { USHORT CurrentCrc = 0xffff; USHORT Index, EndIndex; // // Loop through different parts computing CRC // This is from Size to Revision inclusive // for (Index = 0; Index <= 3; Index++) { CurrentCrc = HalpAddByteCrc(CurrentCrc, Index); } // // Compute ending offset // EndIndex = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->OSAreaAddress)); // // Loop through second half // This is from LastOS to OSArea (Note: 9 should be 8; however, // IBM screwed up and we are all just going along with it). // for (Index = 9; Index < EndIndex; Index++) { CurrentCrc = HalpAddByteCrc(CurrentCrc, Index); } return(CurrentCrc); } // // HalpUpdateCrc // // Description: // Compute the required Crc value and update the Header. This // code only updates crc1. // VOID HalpUpdateCrc() { ULONG Crc; NDBG(1, DbgPrint("HalpUpdateCrc: called\n");); Crc = HalpComputeCrc(); HalpWriteNvramUshort((USHORT) &NVMAP->Crc1, (USHORT) Crc); } // // Returns the number of bytes removed // USHORT HalpCompressEnvironmentSpace(IN USHORT StartIndex) { USHORT Index, BytesRemoved; UCHAR PreviousChar, NvramChar; Index = StartIndex+1; while(HalpDS1385ReadNVRAM(Index++) != '=') { /* Do Nothing */ } while(HalpDS1385ReadNVRAM(Index++) != 0) { /* Do Nothing */ } BytesRemoved = Index - StartIndex; // Adjust amount of free space NvramChar = 0; // // Copy subsequent variables // do { PreviousChar = NvramChar; NvramChar = HalpDS1385ReadNVRAM(Index++); HalpDS1385WriteNVRAM(StartIndex++, NvramChar); } while (PreviousChar | NvramChar); // // Make sure unused NVRAM area is zeroed // for (Index=0; Index = NVSIZE) { break; } HalpDS1385WriteNVRAM((USHORT)(Index+StartIndex), 0); } return(BytesRemoved); } // //HalpFindEnviroVar // Description: // Searches the NVRAM for an environment variable. // // Parameters: // Variable - ptr to the variable to search for. // // Return value: // The NVRAM index where the environment variable's VALUE is stored. // Returns 0 if the variable was not found. // // Assumes NVRAM_Spinlock has already been acquired by the caller. // USHORT HalpFindEnviroVar(IN CHAR *Variable) { USHORT Index, StartIndex, LastIndex; CHAR *VariablePtr, UserChar, NvramChar; NDBG(1, DbgPrint("HalpFindEnviroVar: called for %s\n", Variable);); StartIndex = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GEAddress)); LastIndex = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GELength)); LastIndex += StartIndex - 1; // // Search the NVRAM for the variable. // VariablePtr = Variable; for (Index = StartIndex ; Index <= LastIndex; ) { // // Get a character from the NVRAM // NvramChar = HalpDS1385ReadNVRAM(Index++); if (NvramChar == 0) { break; } // // Are we at the end of the variable name in both the // input string and the NVRAM ? // If so, then it is an exact match. Return the NVRAM index. // UserChar = *VariablePtr++; if (UserChar == 0 && NvramChar == '=') { NDBG(2, DbgPrint("HalpFindEnviroVar: found %s at %d\n", Variable, Index);); return(Index); } // // Convert variable to UPPER case // UserChar = (UserChar >= 'a' && UserChar <= 'z') ? UserChar-0x20 : UserChar; // // Is there a match on this character ? // if (UserChar != NvramChar) { // // No, then skip over this variable in NVRAM and begin // search again at start of variable NAME. // VariablePtr = Variable; while (Index <= LastIndex) { NvramChar = HalpDS1385ReadNVRAM(Index++); if (NvramChar == '=') break; } while (Index <= LastIndex) { NvramChar = HalpDS1385ReadNVRAM(Index++); if (NvramChar == 0) { break; } } } } // // The variable was not found // NDBG(2, DbgPrint("HalpFindEnviroVar: %s not found\n", Variable);); return(0); } // // HalGetEnvironmentVariable // // Parameters: // // Variables: // Supplies a pointer to the zero-terminated, case ASCII string that contains // the name of the environment variable to be returned. // Length - Supplies the length of the buffer in bytes. // Buffer - Supplies a pointer to a buffer that receives the variable value. // // Return Value: // If the variable, the function returns the value ESUCCESS and its // value in Buffer. Otherwise, ENOENT is returned. // ULONG HalGetEnvironmentVariable(IN CHAR *Variable, IN USHORT Length, OUT CHAR *Buffer) { USHORT Index; static DumpNVRAMOnce = FALSE; ULONG retVal = ENOENT NDBG(1, DbgPrint("HalpGetEnvironmentVariable: called\n");); // // Check input parameters // if (!Variable) { if (*Variable == 0 || Length < 1 || Buffer == NULL) { NDBG(2, DbgPrint("HalpGetEnvironmentVariable: return ENOENT\n");); return(retVal); } } if (!DumpNVRAMOnce) { NDBG(2, DumpNVRAM();); DumpNVRAMOnce = TRUE; } // // Grab control of NVRAM // #if USE_SPINLOCKS KIRQL Irql; KeAcquireSpinLock(NVRAM_Spinlock, &Irql); #endif NvramFailure = FALSE; // // Get NVRAM index of environment variable // Index = HalpFindEnviroVar(Variable); if (Index == 0) { // // Environment variable was not found // #if USE_SPINLOCKS KeReleaseSpinLock(NVRAM_Spinlock, Irql); #endif return(retVal); } // // Copy the environment variable's value to Buffer // do { *Buffer = HalpDS1385ReadNVRAM(Index++); if (*Buffer++ == 0) { if (NvramFailure == TRUE) { retVal = ENOMEM; } else { retVal = ESUCCESS; } #if USE_SPINLOCKS KeReleaseSpinLock(NVRAM_Spinlock, Irql); #endif return(retVal); } } while (--Length); // // Truncate the returned string. The buffer was too short. // *--Buffer = 0; #if USE_SPINLOCKS KeReleaseSpinLock(NVRAM_Spinlock, Irql); #endif return(ENOMEM); } // // HalSetEnvironmentVariable // // Parameters: // Variable // Supplies a pointer to the zero-terminated ASCII string that contains // the name of the environment variable to be returned. The string is // converted to UPPER CASE. // // Value // Supplies a pointer to the zero-terminated string that contains the new // value of the environment variable. // // There are 4 cases: // 1) The environment variable is deleted if Value is a null string. // 2) The environment variable does not currently exist. It is appended // if there is enough NVRAM available. // 3) The environment variable already exists, and the new Value is // shorter than the old value. // 4) The environment variable already exists, and the new Value is longer than // the old value. // // In all cases the environment space will be compressed after // insertion/deletion. // ULONG HalSetEnvironmentVariable( IN CHAR *Variable, IN CHAR *Value) { USHORT TotalSize, FreeSize, Index; USHORT OldLength, NewLength; USHORT StartIndex; USHORT i; USHORT NameLength, ValueLength; CHAR *VariablePtr, *ValuePtr, Char; ARC_STATUS ReturnValue; NDBG(1, DbgPrint("HalSetEnvironmentVariable: called set %s to %s\n", Variable, Value);); if (Value == NULL) { NDBG(2, DbgPrint("HalSetEnvironmentVariable: returning ENOENT\n");); return(ENOENT); } // // Compute length of environment NAME // VariablePtr = Variable; NameLength = 0; while (*VariablePtr != 0) { NameLength++; VariablePtr++; } // // Compute length of environment VALUE // ValuePtr = Value; ValueLength = 0; while (*ValuePtr != 0) { ValueLength++; ValuePtr++; } #if USE_SPINLOCKS KIRQL Irql; KeAcquireSpinLock(NVRAM_Spinlock, &Irql); // Grab control of NVRAM #endif NvramFailure = FALSE; HalpGetEnvironmentInfo(&TotalSize, &FreeSize, NULL); // Get index of environment variable Index = HalpFindEnviroVar(Variable); ReturnValue = ESUCCESS; // Index to start of NAME StartIndex = Index-NameLength-1; // DELETE environment variable if (ValueLength == 0) { if (Index != 0) { HalpCompressEnvironmentSpace(StartIndex); } } else { // ADD or REPLACE environment variable // Compute # bytes needed to store variable NewLength = ValueLength + NameLength + 2; // REPLACE environment variable. // First we see if there is room. If so, delete the current // variable & fall through to the code that ADDs a new variable. if (Index != 0) { // Compute current length of variable OldLength = 0; i = Index; do { OldLength++; } while (HalpDS1385ReadNVRAM(i++) != 0); // Is there room for the new variable ? if (FreeSize-NewLength+OldLength >= 0) FreeSize += HalpCompressEnvironmentSpace(StartIndex); } // // ADD environment variable // if ((FreeSize-NewLength) >= 0) { // Room for new Index = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GEAddress)); Index += (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GELength)); Index -= FreeSize; // // Write Variable NVRAM. Convert to UPPER case first. // while (*Variable != 0) { Char = *Variable++; // // Convert Variable to UPPER case // Char = (Char >= 'a' && Char <= 'z') ? Char-0x20 : Char; HalpDS1385WriteNVRAM(Index++,Char); } HalpDS1385WriteNVRAM(Index++,'='); // Write a "=" do { // Write VALUE to NVRAM HalpDS1385WriteNVRAM(Index++,*Value); } while (*Value++ != 0); ReturnValue = ESUCCESS; } } // // Update NVRAM checksum // HalpUpdateCrc(); if (NvramFailure == TRUE) { ReturnValue = ENOMEM; } #if USE_SPINLOCKS KeReleaseSpinLock(NVRAM_Spinlock, Irql); #endif return(ReturnValue); }