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.
2033 lines
48 KiB
2033 lines
48 KiB
////////////////////////////////////////////////////////////////////////// ++
|
|
//
|
|
// FWNVR.C
|
|
//
|
|
// Copyright 1991-94 IBM, Motorola, Microsoft
|
|
//
|
|
// Functions to access Non-Volatile Ram on PowerPC systems.
|
|
//
|
|
// This module is used exactly as-is by both ARC and HAL. By convention,
|
|
// it originates in the ARC environment and is copied to the HAL tree.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////// --
|
|
|
|
/*
|
|
YET TO DO:
|
|
Fix and use NVR size-sensing
|
|
Use nvr_set_variable() function.
|
|
Allocate memory even in the ARC environment, since later the size of
|
|
the buffers required may vary wildly. This won't be a
|
|
problem (for either HAL or ARC) IF we go to NVR-direct use.
|
|
NOTE: must handle pool-clearing problems FIRST (ARC only)
|
|
Q: handle buffer-size changes when nvr_read_nvram() gets actual
|
|
NVR size? Bufferless fixes this problem too.
|
|
Handle 24-bit access
|
|
*/
|
|
|
|
#ifdef _HALNVR_ /////// BUILDING FOR USE IN HAL ///////
|
|
|
|
#include "halp.h"
|
|
|
|
#else /////// BUILDING FOR USE IN ARC ///////
|
|
|
|
#include "fwp.h"
|
|
#define ExAllocatePool(type,size) FwAllocatePool(size)
|
|
|
|
#endif // _HALNVR_ /////////////////////////////////////////
|
|
|
|
|
|
#include "prepnvr.h"
|
|
#include "fwstatus.h"
|
|
|
|
|
|
typedef struct _nvr_object
|
|
{
|
|
struct _nvr_object *self ;
|
|
HEADER * bhead ;
|
|
HEADER * lhead ;
|
|
UCHAR bend [NVSIZE*2] ;
|
|
UCHAR lend [NVSIZE*2] ;
|
|
} NVR_OBJECT, *PNVR_OBJECT ;
|
|
|
|
typedef NVRAM_MAP *PNVRAM_MAP ;
|
|
|
|
extern PVOID HalpIoControlBase ;
|
|
|
|
#define ENDSWAP_SHORT(_x) (((_x<<8)&0xff00)|((_x>>8)&0x00ff))
|
|
#define ENDSWAP_LONG(_x)\
|
|
(((_x<<24)&0xff000000)|((_x<<8)&0x00ff0000)|\
|
|
((_x>>8)&0x0000ff00)|((_x>>24)&0x000000ff))
|
|
|
|
#define _toupr_(_c) (((_c >= 'a') && (_c <= 'z')) ? (_c - 'a' + 'A') : _c)
|
|
|
|
// Define the maximum size required for fetching any item from NVRAM, which
|
|
// is defined to be the maximum size OF the NVRAM.
|
|
// NOTE this is a poor assumption and needs to be sensed at run-time !!
|
|
#define MAXNVRFETCH NVSIZE*2
|
|
|
|
#define MAXIMUM_ENVIRONMENT_VALUE 1024
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// LOCAL DATA, NOT VISIBLE TO OTHER MODULES
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
static UCHAR _currentstring[MAXIMUM_ENVIRONMENT_VALUE] ;
|
|
static UCHAR _currentfetch[MAXNVRFETCH] ;
|
|
|
|
#ifndef _HALNVR_
|
|
NVR_OBJECT nvrobj ;
|
|
#endif // _HALNVR_
|
|
|
|
PNVR_OBJECT pnvrobj = NULL ;
|
|
|
|
// The access method varies with planar construction, and is switched
|
|
// based on the Planar ID Register.
|
|
#define NVR_ACCESS_UNKNOWN 0
|
|
#define NVR_ACCESS_SANDALFOOT 1
|
|
#define NVR_ACCESS_STANDARD 2
|
|
LONG NvrAccessMethod = NVR_ACCESS_UNKNOWN ;
|
|
// The use of 24-bit NVRAM addressing is enable with this flag:
|
|
LONG NvrAccess24bit = FALSE ;
|
|
// These are the ISA port addresses for NVRAM Registers
|
|
#define NVRREG_AD0 0x74 // LS byte of address (bits 0-7)
|
|
#define NVRREG_AD1 0x75 // next byte of address (bits 8-15)
|
|
// Below to be added when register definition finalized
|
|
// #define NVRREG_AD2 0x?? // MS byte of address (bits 16-23)
|
|
#define NVRREG_STDDATA 0x76 // Data Port (R/W), standard
|
|
#define NVRREG_SFTDATA 0x77 // Data Port (R/W), Sandalfoot only
|
|
|
|
// The size below is used for error recovery, to either set NVRAM to
|
|
// a default state (a dubious proposition) or to clear it entirely.
|
|
ULONG NvrFillSize = 4096 ; // "safe" default value
|
|
|
|
USHORT NvrVersion = 0 ; // MSB=version, LSB=revision
|
|
|
|
//////// Bring in prototypes automatically generated by CPROTO. These
|
|
//////// should be placed AFTER any other headers and any module data
|
|
//////// and data definitions, and BEFORE module code begins.
|
|
#define _CPROTO_FW_SCOPE_
|
|
#define _CPROTO_FWNVR_STATICS_
|
|
#include "fwdebug.h"
|
|
#include "fwnvr.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// !=
|
|
PNVR_OBJECT
|
|
nvr_alloc (
|
|
ULONG size
|
|
)
|
|
{
|
|
PNVR_OBJECT p ;
|
|
|
|
#ifdef _HALNVR_
|
|
// HAL allocates memory for it so it doesn't sit around all the time
|
|
p = ExAllocatePool (NonPagedPool, size) ;
|
|
#else
|
|
// FW uses static allocation (probably change later...)
|
|
p = &nvrobj ;
|
|
#endif // _HALNVR_
|
|
|
|
return (p) ;
|
|
}
|
|
|
|
|
|
// !=
|
|
VOID
|
|
nvr_free (
|
|
PVOID p
|
|
)
|
|
{
|
|
if ( !p )
|
|
return ;
|
|
|
|
NvrAccessMethod = NVR_ACCESS_UNKNOWN ;
|
|
NvrAccess24bit = 0 ;
|
|
|
|
#ifdef _HALNVR_
|
|
ExFreePool (p) ; // de-allocate HAL memory
|
|
#endif // _HALNVR_
|
|
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// ==
|
|
USHORT
|
|
NvrGetVersion (
|
|
VOID
|
|
)
|
|
{
|
|
return ( NvrVersion ) ;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ==
|
|
ULONG
|
|
NvrGetSize (
|
|
VOID
|
|
)
|
|
// Performs a hardware scan of NVRAM and returns it's size in bytes.
|
|
// The algorithm accepts the fact that the bridge will return the last
|
|
// byte written, even if it did NOT come from a memory location (it's
|
|
// just a latch which is left with a stale value). So in order to get
|
|
// a new value in the latch, we write to NVRAM location 0 between other
|
|
// accesses.
|
|
{
|
|
ULONG size = 1 ;
|
|
UCHAR b0, b1, b2, b3, b4 ;
|
|
|
|
// Since we'll be writing to location 0 for each byte tested, we
|
|
// can't test byte 0 without some special gyrations. Instead, we
|
|
// just start the test at byte 1. Recall that this is not intended
|
|
// so much as a memory TEST, but more a SIZE check.
|
|
size = 1 ;
|
|
|
|
b4 = nvr_read (0) ; // save byte 0 so the test is non-destructive
|
|
while ( size < 250000 )
|
|
{
|
|
b0 = nvr_read (size) ;
|
|
nvr_write (size,(UCHAR)(size&0xFF)) ;
|
|
nvr_write (0,(UCHAR)~(size&0xFF)) ;
|
|
b1 = nvr_read (size) ;
|
|
nvr_write (size,(UCHAR)~(size&0xFF)) ;
|
|
nvr_write (0,(UCHAR)(size&0xFF)) ;
|
|
b2 = nvr_read (size) ;
|
|
nvr_write (size,b0) ;
|
|
b3 = nvr_read (size) ;
|
|
if ( b3!=b0 || b1 != (UCHAR)(size&0xFF) || b2 != (UCHAR)~(size&0xFF) )
|
|
break ;
|
|
size++ ;
|
|
}
|
|
nvr_write (0,b4) ; // set first byte back again
|
|
if ( size == 1 )
|
|
size = 0 ;
|
|
return ( size ) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
BOOLEAN
|
|
NvrSetSize (
|
|
LONG NvramSize // size of NVRAM in bytes if non-zero
|
|
)
|
|
{
|
|
ULONG size = 1 ;
|
|
UCHAR b0, b1, b2, b3, b4 ;
|
|
|
|
if ( NvramSize )
|
|
{
|
|
// Caller has specified what fill size is required. Just set
|
|
// the global variable and return.
|
|
NvrFillSize = NvramSize ;
|
|
DEBUG_PRINT (1,"NvrSetSize: fill size caller-set to %d bytes\n",NvrFillSize) ;
|
|
return TRUE ;
|
|
}
|
|
else
|
|
{
|
|
// Caller didn't know how big NVRAM is. We try to find out
|
|
// with a hardware test, and if successful we fill in the
|
|
// value. If we can't find out either, we disable clearing
|
|
// of NVRAM by setting NvrFillSize to zero.
|
|
|
|
size = NvrGetSize() & 0xFFFFF000 ; // size modulo-4k
|
|
DEBUG_PRINT (1,"NvrSetSize: fill size measured at %d bytes\n",size) ;
|
|
|
|
// Overridden temporarily until we decide how to handle caller issues as to
|
|
// whether clearing NVRAM is even legitimate to do. Code above works OK.
|
|
|
|
NvrFillSize = 0 ;
|
|
DEBUG_PRINT (1,"NvrSetSize: fill disabled by setting size to 0 bytes\n") ;
|
|
}
|
|
return TRUE ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
// ==
|
|
LONG
|
|
NvrGetMethod (
|
|
VOID
|
|
)
|
|
// Returns the access method in use. If it has not yet been set, a
|
|
// check of the hardware is made in an attempt to set it properly.
|
|
{
|
|
if ( NvrAccessMethod == NVR_ACCESS_UNKNOWN )
|
|
NvrSetMethod (0) ;
|
|
return ( NvrAccessMethod ) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
BOOLEAN
|
|
NvrSetMethod (
|
|
LONG ForcedValue // if Non-zero, set to this value regardless
|
|
)
|
|
// Decide how to access NVRAM, so that the nvr_read() and nvr_write()
|
|
// functions can work properly. If a non-zero parameter is passed in,
|
|
// the method is simply set to this value. If ZERO is passed in, then
|
|
// local code tries to determine the proper method. Either way, the
|
|
// operation is checked afterwards, and FALSE is returned if the access
|
|
// method does recognize values inside NVRAM. If OK, TRUE returned.
|
|
{
|
|
UCHAR PlanarID = 0;
|
|
UCHAR endian = '*' ;
|
|
HEADER *hp = (HEADER *)0;
|
|
|
|
// If caller sets it explicitly, just check the results. Otherwise,
|
|
// use the Planar ID Register to decide what method to use.
|
|
|
|
if ( ForcedValue )
|
|
NvrAccessMethod = ForcedValue ;
|
|
else
|
|
{
|
|
PlanarID = READ_REGISTER_UCHAR ((ULONG)HalpIoControlBase+0x852) ;
|
|
|
|
// NOTE that while the 0xDE value is documented as a
|
|
// Sandalfoot, it was never used as one. Instead, it is used
|
|
// on Woodfield. Unclear if 0xDD used, but it's defined in
|
|
// DAKOARCH as a Sandalfoot.
|
|
if ( (PlanarID >= 0xFC && PlanarID < 0xFF) // Sandalfoot
|
|
|| (PlanarID >= 0xDC && PlanarID < 0xDE) // more Sandalfoot
|
|
|| (PlanarID == 0x95) // Victory
|
|
|| (PlanarID == 0x0C) // Harley
|
|
|| (PlanarID == 0x5a) // Zapatos
|
|
)
|
|
NvrAccessMethod = NVR_ACCESS_SANDALFOOT ; // Carolina
|
|
else
|
|
NvrAccessMethod = NVR_ACCESS_STANDARD ;
|
|
}
|
|
|
|
endian = nvr_read((ULONG)((ULONG)(&hp->Endian)-(ULONG)hp)) ;
|
|
|
|
DEBUG_PRINT (1,"NvrSetMethod: PlanarID=0x%02X, Method set to %d (Endian shown as '%c')\n",
|
|
PlanarID,NvrAccessMethod,endian) ;
|
|
|
|
if ( endian != 'B' && endian != 'L' )
|
|
{
|
|
DEBUG_PRINT (0,"NvrSetMethod FAILED: Endian value was '%c'\n",
|
|
endian) ;
|
|
return FALSE ;
|
|
}
|
|
|
|
return TRUE ;
|
|
}
|
|
|
|
|
|
// ==
|
|
UCHAR
|
|
nvr_read (
|
|
ULONG addr
|
|
)
|
|
{
|
|
UCHAR uc = 0 ;
|
|
|
|
if ( !NvrAccessMethod )
|
|
NvrSetMethod (0) ;
|
|
|
|
switch ( NvrAccessMethod )
|
|
{
|
|
case 0:
|
|
DEBUG_PRINT (1,"nvr_read: NO NvrAccessMethod\n") ;
|
|
return 0 ;
|
|
case 1:
|
|
WRITE_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_AD0,
|
|
(UCHAR)(addr&0xFF)) ;
|
|
WRITE_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_AD1,
|
|
(UCHAR)((addr>>8)&0x1F)) ;
|
|
uc = READ_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_SFTDATA) ;
|
|
break ;
|
|
case 2:
|
|
WRITE_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_AD0,
|
|
(UCHAR)(addr&0xFF)) ;
|
|
WRITE_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_AD1,
|
|
(UCHAR)((addr>>8)&0x1F)) ;
|
|
uc = READ_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_STDDATA) ;
|
|
break ;
|
|
}
|
|
|
|
return ( uc ) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
VOID
|
|
nvr_write (
|
|
ULONG addr,
|
|
UCHAR data
|
|
)
|
|
{
|
|
if ( !NvrAccessMethod )
|
|
NvrSetMethod (0) ;
|
|
|
|
switch ( NvrAccessMethod )
|
|
{
|
|
case 0:
|
|
DEBUG_PRINT (1,"nvr_write: NO NvrAccessMethod\n") ;
|
|
return ;
|
|
case 1:
|
|
WRITE_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_AD0,
|
|
(UCHAR)(addr&0xFF)) ;
|
|
WRITE_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_AD1,
|
|
(UCHAR)((addr>>8)&0x1F)) ;
|
|
WRITE_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_SFTDATA,
|
|
data) ;
|
|
break ;
|
|
case 2:
|
|
WRITE_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_AD0,
|
|
(UCHAR)(addr&0xFF)) ;
|
|
WRITE_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_AD1,
|
|
(UCHAR)((addr>>8)&0x1F)) ;
|
|
WRITE_REGISTER_UCHAR((ULONG)HalpIoControlBase+NVRREG_STDDATA,
|
|
data) ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// !=
|
|
VOID
|
|
nvr_swap_Header (
|
|
HEADER* dest,
|
|
HEADER* src
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PUCHAR cp ;
|
|
|
|
if ( !dest || !src )
|
|
return ; // invalid pointer
|
|
|
|
dest->Size = ENDSWAP_SHORT(src->Size) ;
|
|
dest->Version = src->Version ;
|
|
dest->Revision = src->Revision ;
|
|
dest->Crc1 = ENDSWAP_SHORT(src->Crc1) ;
|
|
dest->Crc2 = ENDSWAP_SHORT(src->Crc2) ;
|
|
dest->LastOS = src->LastOS ;
|
|
dest->Endian = src->Endian ;
|
|
dest->OSAreaUsage = src->OSAreaUsage ;
|
|
dest->PMMode = src->PMMode ;
|
|
|
|
|
|
// NOTE THIS CHANGES WITH UPDATED PPCNVR01.H
|
|
/* convert NVRRESTART_BLOCK structure of Header */
|
|
dest->ResumeBlock.CheckSum = ENDSWAP_LONG(src->ResumeBlock.CheckSum) ;
|
|
dest->ResumeBlock.BootStatus = ENDSWAP_LONG(src->ResumeBlock.BootStatus) ;
|
|
dest->ResumeBlock.ResumeAddr =
|
|
(PVOID) ENDSWAP_LONG((ULONG)src->ResumeBlock.ResumeAddr) ;
|
|
dest->ResumeBlock.SaveAreaAddr =
|
|
(PVOID) ENDSWAP_LONG((ULONG)src->ResumeBlock.SaveAreaAddr) ;
|
|
dest->ResumeBlock.SaveAreaLength =
|
|
ENDSWAP_LONG((ULONG)src->ResumeBlock.SaveAreaLength) ;
|
|
dest->ResumeBlock.HibResumeImageRBA =
|
|
ENDSWAP_LONG((ULONG)src->ResumeBlock.HibResumeImageRBA) ;
|
|
dest->ResumeBlock.HibResumeImageRBACount =
|
|
ENDSWAP_LONG((ULONG)src->ResumeBlock.HibResumeImageRBACount) ;
|
|
dest->ResumeBlock.Reserved =
|
|
ENDSWAP_LONG((ULONG)src->ResumeBlock.Reserved) ;
|
|
|
|
|
|
/* convert SECURITY structure */
|
|
dest->Security.BootErrCnt =
|
|
ENDSWAP_LONG(src->Security.BootErrCnt) ;
|
|
dest->Security.ConfigErrCnt =
|
|
ENDSWAP_LONG(src->Security.ConfigErrCnt) ;
|
|
dest->Security.BootErrorDT[0] =
|
|
ENDSWAP_LONG(src->Security.BootErrorDT[0]) ;
|
|
dest->Security.BootErrorDT[1] =
|
|
ENDSWAP_LONG(src->Security.BootErrorDT[1]) ;
|
|
dest->Security.ConfigErrorDT[0] =
|
|
ENDSWAP_LONG(src->Security.ConfigErrorDT[0]) ;
|
|
dest->Security.ConfigErrorDT[1] =
|
|
ENDSWAP_LONG(src->Security.ConfigErrorDT[1]) ;
|
|
dest->Security.BootCorrectDT[0] =
|
|
ENDSWAP_LONG(src->Security.BootCorrectDT[0]) ;
|
|
dest->Security.BootCorrectDT[1] =
|
|
ENDSWAP_LONG(src->Security.BootCorrectDT[1]) ;
|
|
dest->Security.ConfigCorrectDT[0] =
|
|
ENDSWAP_LONG(src->Security.ConfigCorrectDT[0]) ;
|
|
dest->Security.ConfigCorrectDT[1] =
|
|
ENDSWAP_LONG(src->Security.ConfigCorrectDT[1]) ;
|
|
dest->Security.BootSetDT[0] =
|
|
ENDSWAP_LONG(src->Security.BootSetDT[0]) ;
|
|
dest->Security.BootSetDT[1] =
|
|
ENDSWAP_LONG(src->Security.BootSetDT[1]) ;
|
|
dest->Security.ConfigSetDT[0] =
|
|
ENDSWAP_LONG(src->Security.ConfigSetDT[0]) ;
|
|
dest->Security.ConfigSetDT[1] =
|
|
ENDSWAP_LONG(src->Security.ConfigSetDT[1]) ;
|
|
for (i = 0 ; i < 16 ; i++)
|
|
dest->Security.Serial[i] = src->Security.Serial[i] ;
|
|
|
|
/* convert ERROR_LOG 0 and ERROR_LOG 1 structure */
|
|
// ASAP: use sizeof() instead of 40 below...
|
|
for (i = 0 ; i < 40 ; i++)
|
|
{
|
|
dest->ErrorLog[0].ErrorLogEntry[i] = src->ErrorLog[0].ErrorLogEntry[i] ;
|
|
dest->ErrorLog[1].ErrorLogEntry[i] = src->ErrorLog[1].ErrorLogEntry[i] ;
|
|
}
|
|
|
|
/* convert remainder of Header */
|
|
dest->GEAddress = (PVOID) ENDSWAP_LONG((ULONG)src->GEAddress) ;
|
|
dest->GELength = ENDSWAP_LONG((ULONG)src->GELength) ;
|
|
dest->GELastWriteDT[0] = ENDSWAP_LONG(src->GELastWriteDT[0]) ;
|
|
dest->GELastWriteDT[1] = ENDSWAP_LONG(src->GELastWriteDT[1]) ;
|
|
|
|
dest->ConfigAddress =
|
|
(PVOID) ENDSWAP_LONG((ULONG)src->ConfigAddress) ;
|
|
dest->ConfigLength = ENDSWAP_LONG(src->ConfigLength) ;
|
|
dest->ConfigLastWriteDT[0] =
|
|
ENDSWAP_LONG(src->ConfigLastWriteDT[0]) ;
|
|
dest->ConfigLastWriteDT[1] =
|
|
ENDSWAP_LONG(src->ConfigLastWriteDT[1]) ;
|
|
dest->ConfigCount = ENDSWAP_LONG(src->ConfigCount) ;
|
|
|
|
dest->OSAreaAddress =
|
|
(PVOID) ENDSWAP_LONG((ULONG)src->OSAreaAddress) ;
|
|
dest->OSAreaLength = ENDSWAP_LONG(src->OSAreaLength) ;
|
|
dest->OSAreaLastWriteDT[0] =
|
|
ENDSWAP_LONG(src->OSAreaLastWriteDT[0]) ;
|
|
dest->OSAreaLastWriteDT[1] =
|
|
ENDSWAP_LONG(src->OSAreaLastWriteDT[1]) ;
|
|
}
|
|
|
|
|
|
// !=
|
|
VOID
|
|
nvr_headb2l (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
if ( !p || p != p->self )
|
|
return ; // invalid pointer
|
|
|
|
nvr_swap_Header (p->lhead,p->bhead) ;
|
|
}
|
|
|
|
|
|
// !=
|
|
VOID
|
|
nvr_headl2b (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
if ( !p || p != p->self )
|
|
return ; // invalid pointer
|
|
|
|
nvr_swap_Header (p->bhead,p->lhead) ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// !=
|
|
VOID
|
|
nvr_default_nvram (
|
|
PNVR_OBJECT p
|
|
)
|
|
// Attempts to protect operation from faulty intitialization of NVRAM
|
|
// by early versions of ROS. Called only from nvr_read_nvram() when a
|
|
// bad 'endian' indicator or CRC is found.
|
|
{
|
|
ULONG i ;
|
|
PUCHAR cp ;
|
|
HEADER * bethp ;
|
|
|
|
if ( !p || p != p->self )
|
|
return ; // invalid pointer
|
|
|
|
DEBUG_PRINT (1,"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n") ;
|
|
DEBUG_PRINT (1,">>>>> CAUTION: Continuing from here will attempt to CLEAR NVRAM ! >>>>>>\n") ;
|
|
DEBUG_PRINT (1,"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n") ;
|
|
DEBUG_BREAK (1) ;
|
|
|
|
if ( NvrFillSize == 0 )
|
|
{
|
|
DEBUG_PRINT (1,">>>>>>>>>> nvr_default_nvram: CAN'T SET NVRAM TO DEFAULT (NO SIZE INFO)!\n") ;
|
|
DEBUG_BREAK (1) ;
|
|
return ;
|
|
}
|
|
|
|
DEBUG_PRINT (1,">>>>>>>>>> nvr_default_nvram: SETTING NVRAM TO DEFAULT VALUES!\n") ;
|
|
|
|
nvr_clear_nvram () ; // empty the physical NVRAM
|
|
|
|
bethp = (HEADER *)p->bend ;
|
|
cp = (PUCHAR)p->bend ;
|
|
/* clear internal header */
|
|
for (i = 0 ; i < sizeof(HEADER) ; i++)
|
|
*cp++ = 0 ;
|
|
|
|
// ASAP: interlock with the (allocated) memory space available. We have to
|
|
// never clear more memory than we have allocated!
|
|
|
|
// ASAP: save size of volatile buffer in struct itself.
|
|
|
|
/* clear internal data areas */
|
|
for (i = 0 ; i < NvrFillSize ; i++)
|
|
p->bend[i] = p->lend[i] = 0 ;
|
|
|
|
bethp->Endian = 'B' ;
|
|
bethp->Size = ENDSWAP_SHORT((USHORT)NvrFillSize/1024) ;
|
|
|
|
// Watch it -- these could come back and byte us !!
|
|
bethp->Version = 1 ;
|
|
bethp->Revision = 4 ;
|
|
|
|
// Global Environment starts right after header, and uses all the
|
|
// space not reserved for the OS and CONFIG areas below.
|
|
bethp->GEAddress = (PVOID) ENDSWAP_LONG((ULONG)sizeof(HEADER)) ;
|
|
bethp->GELength =
|
|
ENDSWAP_LONG((ULONG)NvrFillSize-CONFSIZE-OSAREASIZE-sizeof(HEADER)) ;
|
|
|
|
// OS Area follows, taking up a default amount of space
|
|
bethp->OSAreaAddress =
|
|
(PVOID) ENDSWAP_LONG((ULONG)(NvrFillSize-CONFSIZE-OSAREASIZE)) ;
|
|
bethp->OSAreaLength = ENDSWAP_LONG((ULONG)OSAREASIZE) ;
|
|
|
|
// Set the config area such that it isn't used. This leaves some
|
|
// free space (CONFSIZE bytes) for it to grow downward into. This is
|
|
// counterintuitive, but matches what ROS uses for initialization.
|
|
bethp->ConfigAddress = (PVOID) ENDSWAP_LONG(NvrFillSize) ;
|
|
bethp->ConfigLength = ENDSWAP_LONG((ULONG)0) ;
|
|
|
|
nvr_headb2l (p) ; // copy data to Little-Endian (internal) side
|
|
nvr_write_Header (p) ; // write header to the hardware
|
|
}
|
|
|
|
static BOOLEAN crc2_short = FALSE;
|
|
|
|
USHORT
|
|
nvr_calc2crc_read (
|
|
PNVR_OBJECT p
|
|
)
|
|
// Checksum the CONFIGURATION AREA ONLY.
|
|
{
|
|
ULONG ul ;
|
|
PUCHAR cp ;
|
|
PUCHAR end ;
|
|
|
|
if ( !p || p != p->self )
|
|
return 0xFFFF ; // invalid pointer
|
|
// Original version returned indeterminate value here !!
|
|
// ASAP: check with ESW for proper resolution!
|
|
// return ;
|
|
|
|
ul = 0xFFFF ;
|
|
|
|
// ASAP: revisit the calculation size. The first Wiltwick had a "gap"
|
|
// between the OS and CFG areas, and it may NOT have been checksummed.
|
|
|
|
cp = (PUCHAR)((ULONG)p->bhead + (ULONG)p->lhead->ConfigAddress) ;
|
|
#if 0
|
|
// end = (PUCHAR)((ULONG)p->bhead +
|
|
// (ULONG)(((ULONG)p->lhead->Size << 10) - 1)) ;
|
|
end = (PUCHAR)((ULONG)p->bhead +
|
|
(ULONG)(((ULONG)p->lhead->Size << 10) )) ;
|
|
#endif
|
|
|
|
//
|
|
// PLJ reverted to original code to avoid blowing checksum in config
|
|
// area on sandalfoot.
|
|
//
|
|
|
|
end = (PUCHAR)((ULONG)p->bhead +
|
|
(ULONG)(((ULONG)p->lhead->Size << 10) - 1)) ;
|
|
|
|
// end PLJ change
|
|
|
|
for ( ; cp < end ; cp++)
|
|
ul = nvr_computecrc(ul, *cp) ;
|
|
|
|
//
|
|
// Note that we checksummed 1 byte too few, this is to
|
|
// allow for OLD versions of the firmware. If the checksum
|
|
// now == expected value, set the boolean crc2_short to TRUE
|
|
// so we calculate the right value when writing and return
|
|
// the current value. If it is not currently correct,
|
|
// checksum 1 more byte and return that value.
|
|
//
|
|
|
|
if ((USHORT)(ul & 0xFFFF) == p->lhead->Crc2) {
|
|
crc2_short = TRUE;
|
|
} else {
|
|
ul = nvr_computecrc(ul, *cp) ;
|
|
}
|
|
|
|
return ( (USHORT)(ul & 0xFFFF) ) ;
|
|
}
|
|
|
|
USHORT
|
|
nvr_calc2crc_write (
|
|
PNVR_OBJECT p
|
|
)
|
|
// Checksum the CONFIGURATION AREA ONLY.
|
|
{
|
|
ULONG ul ;
|
|
PUCHAR cp ;
|
|
PUCHAR end ;
|
|
|
|
if ( !p || p != p->self )
|
|
return 0xFFFF ; // invalid pointer
|
|
// Original version returned indeterminate value here !!
|
|
// ASAP: check with ESW for proper resolution!
|
|
// return ;
|
|
|
|
ul = 0xFFFF ;
|
|
|
|
// ASAP: revisit the calculation size. The first Wiltwick had a "gap"
|
|
// between the OS and CFG areas, and it may NOT have been checksummed.
|
|
|
|
cp = (PUCHAR)((ULONG)p->bhead + (ULONG)p->lhead->ConfigAddress) ;
|
|
|
|
// end = (PUCHAR)((ULONG)p->bhead +
|
|
// (ULONG)(((ULONG)p->lhead->Size << 10) - 1)) ;
|
|
end = (PUCHAR)((ULONG)p->bhead +
|
|
(ULONG)(((ULONG)p->lhead->Size << 10) )) ;
|
|
|
|
|
|
//
|
|
// PLJ if we were short 1 byte on the read, calculate the new checksum
|
|
// 1 byte short also. This is to support old firmware.
|
|
//
|
|
|
|
if ( crc2_short ) {
|
|
end--;
|
|
}
|
|
|
|
// end PLJ change
|
|
|
|
for ( ; cp < end ; cp++)
|
|
ul = nvr_computecrc(ul, *cp) ;
|
|
|
|
return ( (USHORT)(ul & 0xFFFF) ) ;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// !=
|
|
BOOLEAN
|
|
nvr_read_nvram (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PUCHAR cp ;
|
|
HEADER * bhp ; // ptr to BE header
|
|
USHORT crc1a = 0 , crc1c = 0 ; // actual and calculated
|
|
USHORT crc2a = 0 , crc2c = 0 ; // values for each CRC
|
|
ULONG nvr_selfsize = 0 ;
|
|
|
|
DEBUG_PRINT (2,"nvr_read_nvram: entry\n") ;
|
|
|
|
if ( !p || p != p->self )
|
|
return FALSE ; // invalid pointer
|
|
|
|
/* read the HEADER from the NVRAM chip */
|
|
bhp = p->bhead ;
|
|
cp = (PUCHAR)p->bend ;
|
|
for (i = 0 ; i < sizeof(HEADER) ; i++)
|
|
*cp++ = nvr_read(i) ;
|
|
|
|
if ((bhp->Endian != 'B') && (bhp->Endian != 'L'))
|
|
goto error ;
|
|
|
|
// convert big endian header to little endian
|
|
nvr_headb2l (p) ;
|
|
|
|
// read the data areas. We have to do this before calculating the
|
|
// checksum, since these areas are checked.
|
|
nvr_read_GEArea(p) ;
|
|
nvr_read_OSArea(p) ;
|
|
nvr_read_CFArea(p) ;
|
|
|
|
// validate checksum 1
|
|
crc1a = ENDSWAP_SHORT(bhp->Crc1) ;
|
|
crc1c = nvr_calc1crc(p) ;
|
|
if ( crc1a != crc1c )
|
|
goto error ;
|
|
|
|
// validate checksum 2
|
|
crc2a = ENDSWAP_SHORT(bhp->Crc2) ;
|
|
crc2c = nvr_calc2crc_read(p) ;
|
|
if ( crc2a != crc2c )
|
|
goto error ;
|
|
|
|
// At this point the checksum matches, and we have good confidence of
|
|
// having valid data. We use the data within the NVRAM to firm up
|
|
// our notion of how big NVRAM is, in case we later have to clear it.
|
|
nvr_selfsize = ((ULONG)(ENDSWAP_SHORT(bhp->Size))) * 1024 ;
|
|
NvrSetSize (nvr_selfsize) ;
|
|
|
|
// Save the NVR version for later query if required
|
|
NvrVersion = (bhp->Version<<8) | bhp->Revision ;
|
|
|
|
// ASAP: cross-check NvrFillSize with all three addresses and sizes stored
|
|
// in NVRAM to see if the values make sense.
|
|
|
|
return TRUE ;
|
|
|
|
// We get below only if there was an error reading NVRAM. If so,
|
|
// show whatever we can for debugging and then go set NVRAM to the
|
|
// "default" state.
|
|
error:
|
|
DEBUG_PRINT (1,"NVRAM READ ERROR ! Endian byte = '%c'\n",bhp->Endian) ;
|
|
DEBUG_PRINT (1," CRC1 as read: 0x%04X Calculated: 0x%04X\n",crc1a,crc1c) ;
|
|
DEBUG_PRINT (1," CRC2 as read: 0x%04X Calculated: 0x%04X\n",crc2a,crc2c) ;
|
|
nvr_print_object () ; // if debugging, show before deleting
|
|
nvr_default_nvram (p) ;
|
|
return FALSE ;
|
|
}
|
|
|
|
|
|
// !=
|
|
VOID
|
|
nvr_read_GEArea (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PUCHAR lp ;
|
|
PUCHAR bp ;
|
|
ULONG offset ;
|
|
|
|
if ( !p || p != p->self )
|
|
return ; // invalid pointer
|
|
|
|
// Read Global Environment data into both BE and LE areas
|
|
offset = (ULONG)p->lhead->GEAddress ;
|
|
lp = (PUCHAR)((ULONG)p->lhead + offset) ;
|
|
bp = (PUCHAR)((ULONG)p->bhead + offset) ;
|
|
for (i = 0 ; i < p->lhead->GELength ; i++, bp++, lp++)
|
|
*bp = *lp = nvr_read(offset + i) ;
|
|
}
|
|
|
|
|
|
// !=
|
|
VOID
|
|
nvr_read_OSArea (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PUCHAR lp ;
|
|
PUCHAR bp ;
|
|
ULONG offset ;
|
|
|
|
if ( !p || p != p->self )
|
|
return ; // invalid pointer
|
|
|
|
// Read OS-Specific Environment data into both BE and LE areas
|
|
offset = (ULONG)p->lhead->OSAreaAddress ;
|
|
lp = (PUCHAR)((ULONG)p->lhead + offset) ;
|
|
bp = (PUCHAR)((ULONG)p->bhead + offset) ;
|
|
for (i = 0 ; i < p->lhead->OSAreaLength ; i++, bp++, lp++)
|
|
*bp = *lp = nvr_read(offset + i) ;
|
|
}
|
|
|
|
|
|
// !=
|
|
VOID
|
|
nvr_read_CFArea (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PUCHAR lp ;
|
|
PUCHAR bp ;
|
|
ULONG offset ;
|
|
|
|
if ( !p || p != p->self )
|
|
return ; // invalid pointer
|
|
|
|
// Read Configuration data into both BE and LE areas
|
|
offset = (ULONG) p->lhead->ConfigAddress ;
|
|
lp = (PUCHAR) ((ULONG)p->lhead + offset) ;
|
|
bp = (PUCHAR) ((ULONG)p->bhead + offset) ;
|
|
for (i = 0 ; i < p->lhead->ConfigLength ; i++)
|
|
bp[i] = lp[i] = nvr_read(offset + i) ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// !=
|
|
VOID
|
|
nvr_write_Header (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PUCHAR cp ;
|
|
USHORT us ;
|
|
|
|
if ( !p || p != p->self )
|
|
return ; // invalid pointer
|
|
|
|
// We treat the LE header as the 'master', so first convert it's
|
|
// contents into BE format to be written ti NVRAM
|
|
nvr_headl2b(p) ;
|
|
|
|
// Fill in the CRC values. NOTE that changes are made to the LE
|
|
// header WITHOUT updating the CRC, so we have to do it before
|
|
// writing the header. It's the BE data that's being checksummed.
|
|
us = nvr_calc1crc(p) ;
|
|
p->bhead->Crc1 = ENDSWAP_SHORT(us) ;
|
|
us = nvr_calc2crc_write(p) ;
|
|
p->bhead->Crc2 = ENDSWAP_SHORT(us) ;
|
|
|
|
// spit out data
|
|
cp = (PUCHAR)p->bend ;
|
|
for ( i = 0 ; i < sizeof(HEADER) ; i++ )
|
|
nvr_write (i, *cp++) ;
|
|
}
|
|
|
|
|
|
// !=
|
|
VOID
|
|
nvr_write_GEArea (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PUCHAR dest ;
|
|
PUCHAR src ;
|
|
ULONG offset ;
|
|
|
|
if ( !p || p != p->self )
|
|
return ; // invalid pointer
|
|
|
|
/* copy from little endian to big endian staging area */
|
|
offset = (ULONG)p->lhead->GEAddress ;
|
|
src = (PUCHAR)((ULONG)p->lhead + offset) ;
|
|
dest = (PUCHAR)((ULONG)p->bhead + offset) ;
|
|
for (i = 0 ; i < p->lhead->GELength ; i++, dest++, src++)
|
|
*dest = *src ;
|
|
|
|
/* convert to big endian, compute crc, and write header */
|
|
nvr_write_Header(p) ;
|
|
|
|
/* spit out global environment data */
|
|
src = (PUCHAR)((ULONG)p->bhead + offset) ;
|
|
for (i = 0 ; i < p->lhead->GELength ; i++, src++)
|
|
nvr_write (i+offset, *src) ;
|
|
}
|
|
|
|
|
|
// !=
|
|
VOID
|
|
nvr_write_OSArea (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
ULONG i ;
|
|
ULONG offset ;
|
|
PUCHAR src ;
|
|
PUCHAR dest ;
|
|
|
|
if ( !p || p != p->self )
|
|
return ; // invalid pointer
|
|
|
|
/* copy from little endian to big endian staging area */
|
|
offset = (ULONG) p->lhead->OSAreaAddress ;
|
|
src = (PUCHAR) ((ULONG)p->lhead + offset) ;
|
|
dest = (PUCHAR) ((ULONG)p->bhead + offset) ;
|
|
for (i = 0 ; i < p->lhead->OSAreaLength ; i++, dest++, src++)
|
|
*dest = *src ;
|
|
|
|
/* spit out OS specific data */
|
|
/* header not needed - no crc for OS Area in Header */
|
|
src = (PUCHAR)((ULONG)p->bhead + offset) ;
|
|
for (i = 0 ; i < p->lhead->OSAreaLength ; i++, src++)
|
|
nvr_write (i+offset, *src) ;
|
|
}
|
|
|
|
|
|
// !=
|
|
VOID
|
|
nvr_write_CFArea (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PUCHAR dest ;
|
|
PUCHAR src ;
|
|
ULONG offset ;
|
|
|
|
if ( !p || p != p->self )
|
|
return ; // invalid pointer
|
|
|
|
/* copy from little endian to big endian staging area */
|
|
offset = (ULONG)p->lhead->ConfigAddress ;
|
|
dest = (PUCHAR) ((ULONG)p->bhead + offset - 1) ;
|
|
src = (PUCHAR) ((ULONG)p->lhead + offset - 1) ;
|
|
for (i = 0 ; i < p->lhead->ConfigLength ; i++, dest--, src--)
|
|
*dest = *src ;
|
|
|
|
/* convert to big endian, compute crc, and write header */
|
|
nvr_write_Header(p) ;
|
|
|
|
/* spit out configuration data */
|
|
src = (PUCHAR)((ULONG)p->bhead + offset - 1) ;
|
|
for (i = 1 ; i <= p->lhead->ConfigLength ; i++, src--)
|
|
nvr_write (i+offset, *src) ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// USED_BY_HAL:
|
|
// ==
|
|
VOID
|
|
nvr_delete_object (
|
|
VOID
|
|
)
|
|
{
|
|
if ( !pnvrobj || pnvrobj != pnvrobj->self )
|
|
return ;
|
|
|
|
pnvrobj->self = NULL ;
|
|
nvr_free (pnvrobj) ;
|
|
pnvrobj = NULL ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// !=
|
|
PNVR_OBJECT
|
|
nvr_create_object (
|
|
VOID
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PUCHAR cp ;
|
|
UCHAR pid ;
|
|
|
|
// Allocate (or just find) memory for the local NVR Object
|
|
pnvrobj = nvr_alloc (sizeof(NVR_OBJECT)) ;
|
|
if ( !pnvrobj )
|
|
return NULL ; // ERROR: couldn't get memory
|
|
|
|
// Zero out the object
|
|
for (i = 0, cp = (PUCHAR)pnvrobj ; i < sizeof(NVR_OBJECT) ; i++, cp++)
|
|
*cp = 0 ;
|
|
|
|
// initialize internal elements
|
|
pnvrobj->self = pnvrobj ;
|
|
pnvrobj->bhead = (HEADER *) pnvrobj->bend ;
|
|
pnvrobj->lhead = (HEADER *) pnvrobj->lend ;
|
|
|
|
return (pnvrobj) ;
|
|
}
|
|
|
|
|
|
// USED_BY_HAL:
|
|
|
|
// ==
|
|
STATUS_TYPE
|
|
nvr_initialize_object (
|
|
LONG AccessMethod,
|
|
ULONG Size // NVR size in bytes
|
|
)
|
|
// Set up everything required to be able to access and modify NVRAM.
|
|
// The parameters are "optional" (may be zero).
|
|
//
|
|
// If AccessMethod == 0, the actual value will be derived from the
|
|
// hardware (at this point the hardware test is reliable).
|
|
//
|
|
// If Size == 0, the program will attempt to determine the actual NVRAM
|
|
// size by a hardware test (at this point this is in-op). After the
|
|
// NVRAM is read successfully and the CRC checks, the value will be
|
|
// updated based on the value found inside NVRAM itself. If the caller
|
|
// furnishes no value AND a valid value is NOT found, clearing of NVRAM
|
|
// will be disabled.
|
|
//
|
|
// NOTE that this module must somehow know the Method in order to
|
|
// perform ANY accesses, but that Size is only used in error cases to
|
|
// destroy the entire NVRAM.
|
|
{
|
|
DEBUG_PRINT (1,"enter nvr_initialize_object\n") ;
|
|
|
|
if ( pnvrobj )
|
|
return stat_exist ; // object ALREADY initialized!
|
|
|
|
// create object or get static address
|
|
if ( !(pnvrobj = nvr_create_object()) )
|
|
return stat_error ;
|
|
|
|
NvrFillSize = Size ;
|
|
|
|
// Decide HOW to access NVRAM and set global variable
|
|
NvrSetMethod (AccessMethod) ;
|
|
|
|
// ASAP: figure how to handle an error properly. If zero returned from
|
|
// above, the endian indicator didn't show up and we probably can't
|
|
// read NVRAM at all. What to do, what to do??
|
|
|
|
NvrSetSize (Size) ;
|
|
|
|
// read the header from NVRAM and convert to little endian
|
|
nvr_read_nvram (pnvrobj) ;
|
|
|
|
nvr_print_object() ; // if debugging, print the values
|
|
|
|
return stat_ok ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// !=
|
|
VOID
|
|
nvr_clear_nvram (
|
|
VOID
|
|
)
|
|
// Set ALL of NVRAM to zeros: header, checksum, EVERYTHING! This is
|
|
// used to set default values in case a corrupted system is found, OR
|
|
// from the (user-initiated) nvr_destory() function.
|
|
{
|
|
ULONG i ;
|
|
|
|
for ( i = 0 ; i < NvrFillSize ; i++ )
|
|
nvr_write (i,0) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
VOID
|
|
nvr_destroy (
|
|
LONG AccessMethod,
|
|
ULONG Size // size of NVRAM
|
|
)
|
|
// This is used as a debugging and recovery feature only. It is accessed
|
|
// via a secret back door in the FWBOOT.C module, and is never executed,
|
|
// other than manually by the user.
|
|
{
|
|
if ( !pnvrobj || pnvrobj != pnvrobj->self )
|
|
return ; // invalid pointer
|
|
|
|
nvr_delete_object () ; // delete in case corrupt
|
|
nvr_initialize_object (AccessMethod,Size) ; // get new copy
|
|
nvr_clear_nvram () ; // EMPTY THE PHYSICAL NVRAM
|
|
nvr_delete_object() ; // delete local copy
|
|
|
|
// re-read so local copy matches
|
|
nvr_initialize_object (AccessMethod,Size) ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// The CRC computation algorithm must match that used by the resident
|
|
// firmware (ROS). The algorithms below were obtained from the ESW Group
|
|
// that develops Dakota Firmware. Whenever there are changes in their
|
|
// algorithms, they must be changed here also.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define rol(x,y) ( ( ((x)<<(y)) | ((x)>>(16 - (y))) ) & 0x0FFFF)
|
|
#define ror(x,y) ( ( ((x)>>(y)) | ((x)<<(16 - (y))) ) & 0x0FFFF)
|
|
|
|
// !=
|
|
ULONG
|
|
nvr_computecrc (
|
|
ULONG oldcrc,
|
|
UCHAR data
|
|
)
|
|
{
|
|
ULONG pd, crc ;
|
|
|
|
pd = ((oldcrc>>8) ^ data) << 8 ;
|
|
|
|
crc = 0xFF00 & (oldcrc << 8) ;
|
|
crc |= pd >> 8 ;
|
|
crc ^= rol(pd,4) & 0xF00F ;
|
|
crc ^= ror(pd,3) & 0x1FE0 ;
|
|
crc ^= pd & 0xF000 ;
|
|
crc ^= ror(pd,7) & 0x01E0 ;
|
|
return crc ;
|
|
}
|
|
|
|
|
|
// !=
|
|
USHORT
|
|
nvr_calc1crc (
|
|
PNVR_OBJECT p
|
|
)
|
|
{
|
|
ULONG ul ;
|
|
ULONG i ;
|
|
PUCHAR cp ;
|
|
ULONG len1 ;
|
|
ULONG len2 ;
|
|
USHORT us ;
|
|
|
|
if ( !p || p != p->self )
|
|
return 0 ; // invalid pointer
|
|
|
|
ul = 0x0ffff ;
|
|
|
|
// do not include current Crc1/Crc2 in checksum
|
|
len1 = (sizeof(p->bhead->Size) +
|
|
sizeof(p->bhead->Version) +
|
|
sizeof(p->bhead->Revision)) ;
|
|
len2 = (ULONG) p->lhead->OSAreaAddress ;
|
|
|
|
|
|
// calculate the area before Crc1/Crc2 in the header
|
|
for (cp = (PUCHAR)p->bhead, i = 0 ; i < len1 ; i++)
|
|
ul = nvr_computecrc(ul, cp[i]) ;
|
|
|
|
// NOTE: this switch was required starting with NVR 1.4 as shipped on Delmar.
|
|
// It's unclear whether the change is really related to 1.4 format or
|
|
// to some other ROS change, but we're switching on 1.4 anyway. If a
|
|
// problem develops where the CRC of a new Machine or ROS goes bad,
|
|
// check this out early. Originally this switch was done at compile-
|
|
// time, and was labelled FIX_D852. Defining this name enabled the
|
|
// (now) post-1.3 code.
|
|
if ( p->bhead->Version <= 1 && p->bhead->Revision < 4 )
|
|
i += (sizeof(p->bhead->Crc1) + sizeof(p->bhead->Crc2)) + 1 ;
|
|
else
|
|
i += (sizeof(p->bhead->Crc1) + sizeof(p->bhead->Crc2)) ;
|
|
|
|
for (i = i ; i < len2 ; i++)
|
|
ul = nvr_computecrc(ul, cp[i]) ;
|
|
|
|
us = (USHORT)(ul & 0x0ffff) ;
|
|
|
|
return (us) ;
|
|
}
|
|
|
|
|
|
// !=
|
|
USHORT
|
|
nvr_calc2crc (
|
|
PNVR_OBJECT p
|
|
)
|
|
// Checksum the CONFIGURATION AREA ONLY.
|
|
{
|
|
ULONG ul ;
|
|
PUCHAR cp ;
|
|
PUCHAR end ;
|
|
|
|
if ( !p || p != p->self )
|
|
return 0xFFFF ; // invalid pointer
|
|
// Original version returned indeterminate value here !!
|
|
// ASAP: check with ESW for proper resolution!
|
|
// return ;
|
|
|
|
ul = 0xFFFF ;
|
|
|
|
// ASAP: revisit the calculation size. The first Wiltwick had a "gap"
|
|
// between the OS and CFG areas, and it may NOT have been checksummed.
|
|
|
|
cp = (PUCHAR)((ULONG)p->bhead + (ULONG)p->lhead->ConfigAddress) ;
|
|
#if 0
|
|
// end = (PUCHAR)((ULONG)p->bhead +
|
|
// (ULONG)(((ULONG)p->lhead->Size << 10) - 1)) ;
|
|
end = (PUCHAR)((ULONG)p->bhead +
|
|
(ULONG)(((ULONG)p->lhead->Size << 10) )) ;
|
|
#endif
|
|
|
|
//
|
|
// PLJ reverted to original code to avoid blowing checksum in config
|
|
// area on sandalfoot.
|
|
//
|
|
|
|
end = (PUCHAR)((ULONG)p->bhead +
|
|
(ULONG)(((ULONG)p->lhead->Size << 10) - 1)) ;
|
|
|
|
// end PLJ change
|
|
|
|
for ( ; cp < end ; cp++)
|
|
ul = nvr_computecrc(ul, *cp) ;
|
|
|
|
return ( (USHORT)(ul & 0xFFFF) ) ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// FUNCTIONS PUBLIC TO THE HIGHER LAYERS OF SOFTWARE
|
|
// The functions below operate on the little endian section of the
|
|
// data structure internal to this file. Little endian is the internal
|
|
// (volatile RAM) representation of the NVRAM contents. All access to
|
|
// NVRAM data (variables, etc) are performed on this internal
|
|
// representation. When necessary, the internal representation is
|
|
// loaded back into NVRAM.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ==
|
|
VOID
|
|
nvr_print_object (
|
|
VOID
|
|
)
|
|
// Called by SFENVIR.C after nvr_initialize()
|
|
{
|
|
PUCHAR cp ;
|
|
PUCHAR max ;
|
|
UCHAR tmp ;
|
|
PNVRAM_MAP mp ;
|
|
HEADER* hp ;
|
|
LONG i ;
|
|
CHAR buf[100] ; // buffer for string creation
|
|
|
|
if ( !pnvrobj || pnvrobj != pnvrobj->self )
|
|
return ; // invalid pointer
|
|
|
|
if ( DEBUG_GETLEVEL() < 1 )
|
|
return ;
|
|
|
|
mp = (PNVRAM_MAP) pnvrobj->lend ;
|
|
hp = pnvrobj->lhead ;
|
|
|
|
DEBUG_PRINT (1,"================= INTERNAL NVRAM DISPLAY ==================\n") ;
|
|
DEBUG_PRINT (1," Object Addr: 0x%08lx\n", (ULONG)pnvrobj->self) ;
|
|
DEBUG_PRINT (1," BE Header addr: 0x%08lx\n", (ULONG)pnvrobj->bhead) ;
|
|
DEBUG_PRINT (1," LE Header addr: 0x%08lx\n", (ULONG)pnvrobj->lhead) ;
|
|
|
|
DEBUG_PRINT (1,"=============== NVRAM LITTLE-ENDIAN DISPLAY ===============\n") ;
|
|
DEBUG_PRINT (1," Size: %dK, Version %d.%d CRC1=0x%04X CRC2=0x%04X Endian: '%c'\n",
|
|
(int)hp->Size,
|
|
(int)hp->Version, (int)hp->Revision,
|
|
(int)hp->Crc1,
|
|
(int)hp->Crc2,
|
|
hp->Endian
|
|
) ;
|
|
|
|
// Show the serial number
|
|
for ( i=0 ;
|
|
i < sizeof(hp->Security.Serial)
|
|
&& i < (sizeof(buf)-2)
|
|
&& (tmp=hp->Security.Serial[i]) ;
|
|
i++
|
|
)
|
|
buf[i] = tmp ;
|
|
buf[i] = '\0' ; // terminate the string
|
|
DEBUG_PRINT (1," Serial: '%s'\n",buf) ;
|
|
|
|
DEBUG_PRINT (1," ---- GEAddress: 0x%08lx GELength: 0x%08lx\n",
|
|
hp->GEAddress, hp->GELength) ;
|
|
cp = (PUCHAR)((ULONG)hp + (ULONG)hp->GEAddress) ;
|
|
max = (PUCHAR)((ULONG)cp + hp->GELength) ;
|
|
while ((*cp) && (cp < max))
|
|
{
|
|
DEBUG_PRINT (1," '%s'\n", cp) ;
|
|
cp += (strlen(cp) + 1) ;
|
|
}
|
|
|
|
DEBUG_PRINT (1," ---- OSAreaAddress: 0x%08lx OSAreaLength: 0x%08lx\n",
|
|
hp->OSAreaAddress, hp->OSAreaLength) ;
|
|
cp = (PUCHAR)((ULONG)hp + (ULONG)hp->OSAreaAddress) ;
|
|
max = (PUCHAR)((ULONG)cp + hp->OSAreaLength) ;
|
|
while ((*cp) && (cp < max))
|
|
{
|
|
DEBUG_PRINT (1," '%s'\n", cp) ;
|
|
cp += (strlen(cp) + 1) ;
|
|
}
|
|
|
|
DEBUG_PRINT (1," ---- ConfigAddress: 0x%08lx ConfigLength: 0x%08lx Count: 0x%08lx\n",
|
|
hp->ConfigAddress, hp->ConfigLength, hp->ConfigCount) ;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// NOT YET USED; other finds will be written in terms of this one ASAP
|
|
|
|
// ==
|
|
STATUS_TYPE
|
|
nvr_find_variable (
|
|
PUCHAR VarName, // name of variable to find
|
|
PUCHAR ArrayAddr, // address of variable array
|
|
ULONG ArraySize, // max size of variable array
|
|
PULONG ni,
|
|
PULONG vi
|
|
)
|
|
{
|
|
PUCHAR lvar ;
|
|
PUCHAR cp ;
|
|
ULONG i ;
|
|
|
|
if ( !VarName || !(*VarName) || !ArrayAddr || !ArraySize )
|
|
return stat_error ; // bad input
|
|
|
|
i = 0 ;
|
|
while ( TRUE )
|
|
{
|
|
lvar = VarName ;
|
|
*ni = i ; // RETURN Name Index
|
|
cp = ArrayAddr ;
|
|
|
|
// does the variable we want start at this index?
|
|
while ( i < ArraySize )
|
|
{
|
|
/* break if mismatch */
|
|
if (_toupr_(cp[i]) != _toupr_(*lvar))
|
|
break ; // mismatch
|
|
lvar++, i++ ;
|
|
}
|
|
|
|
// if var name matches
|
|
if ( *lvar == 0 && cp[i] == '=' )
|
|
{
|
|
*vi = ++i ; // RETURN Value Index
|
|
return stat_ok ; // indicate FOUND
|
|
}
|
|
|
|
// no match - set index to start of the next variable
|
|
if ( i >= ArraySize )
|
|
return stat_error ;
|
|
while ( cp[i++] != 0 )
|
|
{
|
|
if ( i >= ArraySize )
|
|
return stat_error ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ==
|
|
STATUS_TYPE
|
|
nvr_set_variable (
|
|
PUCHAR VarName, // name of variable to add/change
|
|
PUCHAR VarValue, // value to be set into variable
|
|
PUCHAR ArrayAddr, // address of variable array
|
|
ULONG ArraySize // max size of variable array
|
|
)
|
|
{
|
|
PUCHAR lvar ;
|
|
PUCHAR cp ;
|
|
ULONG i ;
|
|
ULONG ni ;
|
|
ULONG vi ;
|
|
ULONG eos ;
|
|
PUCHAR str ;
|
|
ULONG count ;
|
|
CHAR c ;
|
|
|
|
if ( !VarName || !(*VarName) || !ArrayAddr || !ArraySize )
|
|
return stat_error ; // bad input
|
|
|
|
// MORE; NOT QUITE READY FOR PRIME TIME
|
|
// Convert to use pointers throughout instead of indexes (including
|
|
// calling convention). At some future time this function will be one
|
|
// of the basic blocks for dealing with NVRAM directly (no buffers),
|
|
// IF the hardware folk say it's OK.
|
|
|
|
// find the end of the used space by looking for
|
|
// the first non-null character from the top
|
|
eos = ArraySize - 1 ;
|
|
while ( ArrayAddr[--eos] == 0 )
|
|
{
|
|
if ( eos == 0 )
|
|
break ;
|
|
}
|
|
|
|
// position eos to the first new character, unless
|
|
// environment space is empty
|
|
if ( eos != 0 )
|
|
eos += 2 ;
|
|
|
|
count = ArraySize - eos ;
|
|
|
|
// find out if the variable already has a value
|
|
if ( nvr_find_variable(VarName,ArrayAddr,ArraySize,&ni,&vi) == stat_ok )
|
|
{
|
|
// The VarName already exists. See if there is room to
|
|
// substitute it with the new one.
|
|
|
|
// count free space
|
|
// start with the free area at the top and add
|
|
// the old ni value
|
|
for ( str = &(ArrayAddr[vi]) ; *str != 0 ; str++ )
|
|
count++ ;
|
|
|
|
// if free area is not large enough to handle new value,
|
|
// return an error
|
|
for ( str = VarValue ; *str != 0 ; str++ )
|
|
{
|
|
if ( count-- == 0 )
|
|
return stat_error ;
|
|
}
|
|
|
|
// pack strings
|
|
// first move vi to the end of the value
|
|
while ( ArrayAddr[vi++] != 0 )
|
|
;
|
|
|
|
// now move everything to where the variable starts
|
|
// covering up the old name/value pair
|
|
while ( vi < eos )
|
|
{
|
|
c = ArrayAddr[vi++] ;
|
|
ArrayAddr[ni++] = c ;
|
|
}
|
|
|
|
// adjust new top of environment
|
|
eos = ni ;
|
|
|
|
// zero to the end of OS area
|
|
while ( ni < ArraySize )
|
|
ArrayAddr[ni++] = 0 ;
|
|
}
|
|
else
|
|
{
|
|
// variable is new
|
|
// if free area is not large enough to handle new value return error
|
|
for ( str = VarValue ; *str != 0 ; str++ )
|
|
{
|
|
if ( count-- == 0 )
|
|
return stat_error ;
|
|
}
|
|
}
|
|
|
|
// At this point any existing variable by the name specified has been
|
|
// removed. If there is no new value to be added, we're done
|
|
|
|
if ( *VarValue )
|
|
{
|
|
// insert new name, converting to upper case.
|
|
while ( *VarName )
|
|
{
|
|
ArrayAddr[eos++] = *VarName++ ;
|
|
}
|
|
ArrayAddr[eos++] = '=' ;
|
|
|
|
// insert new value, leaving case alone
|
|
while ( *VarValue )
|
|
ArrayAddr[eos++] = *VarValue++ ;
|
|
}
|
|
return stat_ok;
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ==
|
|
STATUS_TYPE
|
|
nvr_find_OS_variable (
|
|
PUCHAR var,
|
|
PULONG ni,
|
|
PULONG vi
|
|
)
|
|
{
|
|
PUCHAR cp ;
|
|
HEADER * lhp ;
|
|
|
|
if ( !pnvrobj || !var || !(*var) )
|
|
return stat_error ;
|
|
|
|
lhp = (HEADER*)pnvrobj->lhead ;
|
|
cp = (PUCHAR)((ULONG)lhp + (ULONG)(lhp->OSAreaAddress)) ;
|
|
|
|
return ( nvr_find_variable(var,cp,lhp->OSAreaLength,ni,vi) ) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
STATUS_TYPE
|
|
nvr_find_GE_variable (
|
|
PUCHAR var,
|
|
PULONG ni,
|
|
PULONG vi
|
|
)
|
|
{
|
|
PUCHAR cp ;
|
|
HEADER * lhp ;
|
|
|
|
if ( !pnvrobj || !var || !(*var) )
|
|
return stat_error ;
|
|
|
|
lhp = (HEADER*)pnvrobj->lhead ;
|
|
cp = (PUCHAR)((ULONG)lhp + (ULONG)(lhp->GEAddress)) ;
|
|
|
|
return ( nvr_find_variable(var,cp,lhp->GELength,ni,vi) ) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
PUCHAR
|
|
nvr_get_OS_variable (
|
|
PUCHAR vname
|
|
)
|
|
{
|
|
ULONG ni ;
|
|
ULONG vi ;
|
|
ULONG i ;
|
|
PNVRAM_MAP lep ;
|
|
PUCHAR array ;
|
|
|
|
if ( !pnvrobj || !vname || !(*vname) )
|
|
return NULL ;
|
|
|
|
if (nvr_find_OS_variable(vname, &ni, &vi) != stat_ok)
|
|
return NULL ;
|
|
|
|
lep = (PNVRAM_MAP)pnvrobj->lend ;
|
|
array = (PUCHAR)((ULONG)lep + (ULONG)(lep->Header.OSAreaAddress)) ;
|
|
|
|
for ( i = 0 ; i < MAXIMUM_ENVIRONMENT_VALUE - 1 ; i++ )
|
|
{
|
|
if ( array[vi] == 0 )
|
|
break ;
|
|
_currentstring[i] = array[vi++] ;
|
|
}
|
|
_currentstring[i] = 0 ;
|
|
|
|
return ( _currentstring ) ;
|
|
}
|
|
|
|
|
|
// USED_BY_HAL: also SFENVIR.C
|
|
|
|
// ==
|
|
PUCHAR
|
|
nvr_get_GE_variable (
|
|
PUCHAR vname
|
|
)
|
|
{
|
|
ULONG ni ;
|
|
ULONG vi ;
|
|
ULONG i ;
|
|
PUCHAR cp ;
|
|
HEADER* lhp ;
|
|
|
|
if ( !pnvrobj || !vname || !(*vname) )
|
|
return NULL ;
|
|
|
|
if (nvr_find_GE_variable(vname, &ni, &vi) != stat_ok)
|
|
return NULL ;
|
|
|
|
lhp = (HEADER*)pnvrobj->lhead ;
|
|
cp = (PUCHAR)((ULONG)lhp + (ULONG)lhp->GEAddress) ;
|
|
|
|
for (i = 0 ; i < MAXIMUM_ENVIRONMENT_VALUE - 1 ; i++)
|
|
{
|
|
if (cp[vi] == 0)
|
|
{
|
|
break ;
|
|
}
|
|
_currentstring[i] = cp[vi++] ;
|
|
}
|
|
_currentstring[i] = 0 ;
|
|
|
|
// DEBUG_PRINT (1,"get_GE vname: '%s' value: '%s'\n", vname, _currentstring);
|
|
|
|
return (_currentstring) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
STATUS_TYPE
|
|
nvr_set_OS_variable (
|
|
PUCHAR vname,
|
|
PUCHAR value
|
|
)
|
|
{
|
|
ULONG nameindex ;
|
|
ULONG valueindex ;
|
|
ULONG eos ;
|
|
PUCHAR str ;
|
|
ULONG count ;
|
|
CHAR c ;
|
|
PUCHAR aptr ;
|
|
HEADER* lhp ;
|
|
|
|
if ( !pnvrobj || !vname || !value || !(*vname) )
|
|
return stat_error ;
|
|
|
|
lhp = (HEADER*)pnvrobj->lhead ;
|
|
|
|
// DEBUG_PRINT (1,"OS vname: '%s' value: '%s'\n", vname, value);
|
|
|
|
/* initialize pointer to OS area */
|
|
aptr = (PUCHAR)((ULONG)lhp + (ULONG)lhp->OSAreaAddress) ;
|
|
|
|
// find the end of the used OS space by looking for
|
|
// the first non-null character from the top
|
|
eos = lhp->OSAreaLength - 1 ;
|
|
while (aptr[--eos] == 0)
|
|
{
|
|
if (eos == 0)
|
|
break ;
|
|
}
|
|
|
|
// position eos to the first new character, unless
|
|
// environment space is empty
|
|
if (eos != 0)
|
|
eos += 2 ;
|
|
|
|
// find out if the variable already has a value
|
|
count = lhp->OSAreaLength - eos ;
|
|
if (nvr_find_OS_variable(vname, &nameindex, &valueindex) == stat_ok)
|
|
{
|
|
// count free space
|
|
// start with the free area at the top and add
|
|
// the old nameindex value
|
|
for (str = &(aptr[valueindex]) ; *str != 0 ; str++)
|
|
count++ ;
|
|
|
|
// if free area is not large enough to handle new value return error
|
|
for (str = value ; *str != 0 ; str++)
|
|
{
|
|
if ( count-- == 0 )
|
|
return stat_error ;
|
|
}
|
|
|
|
// pack strings
|
|
// first move valueindex to the end of the value
|
|
while (aptr[valueindex++] != 0)
|
|
;
|
|
|
|
// now move everything to where the variable starts
|
|
// covering up the old name/value pair
|
|
while (valueindex < eos)
|
|
{
|
|
c = aptr[valueindex++] ;
|
|
aptr[nameindex++] = c ;
|
|
}
|
|
|
|
// adjust new top of environment
|
|
eos = nameindex ;
|
|
|
|
// zero to the end of OS area
|
|
while (nameindex < lhp->OSAreaLength)
|
|
aptr[nameindex++] = 0 ;
|
|
}
|
|
else
|
|
{
|
|
// variable is new
|
|
// if free area is not large enough to handle new value return error
|
|
for (str = value ; *str != 0 ; str++)
|
|
{
|
|
if (count-- == 0)
|
|
return stat_error ;
|
|
}
|
|
}
|
|
|
|
/* if value is null, we have removed the variable */
|
|
if (*value)
|
|
{
|
|
// insert new name, converting to upper case.
|
|
while ( *vname )
|
|
{
|
|
aptr[eos++] = *vname++ ;
|
|
}
|
|
aptr[eos++] = '=' ;
|
|
|
|
// insert new value
|
|
while ( *value )
|
|
{
|
|
aptr[eos++] = *value ;
|
|
value++ ;
|
|
}
|
|
}
|
|
|
|
nvr_write_OSArea(pnvrobj) ;
|
|
|
|
return stat_ok ;
|
|
}
|
|
|
|
|
|
// USED_BY_HAL:
|
|
|
|
// ==
|
|
STATUS_TYPE
|
|
nvr_set_GE_variable (
|
|
PUCHAR vname,
|
|
PUCHAR value
|
|
)
|
|
{
|
|
ULONG nameindex ;
|
|
ULONG valueindex ;
|
|
ULONG toe ;
|
|
PUCHAR str ;
|
|
ULONG count ;
|
|
CHAR c ;
|
|
PUCHAR aptr ;
|
|
HEADER* lhp ;
|
|
|
|
if ( !pnvrobj || !vname || !(*vname) )
|
|
return stat_error ; // invalid input
|
|
|
|
lhp = (HEADER*)pnvrobj->lhead ;
|
|
|
|
DEBUG_PRINT (3,"set_GE vname: '%s' value: '%s'\n", vname, value) ;
|
|
|
|
/* initialize pointer to GE area */
|
|
aptr = (PUCHAR)((ULONG)lhp + (ULONG)lhp->GEAddress) ;
|
|
|
|
/* find the top of the used environment space by looking for */
|
|
/* the first non-null character from the top */
|
|
toe = lhp->GELength - 1 ;
|
|
aptr = (PUCHAR)((ULONG)lhp + (ULONG)lhp->GEAddress) ;
|
|
while (aptr[--toe] == 0)
|
|
{
|
|
if (toe == 0)
|
|
break ;
|
|
}
|
|
|
|
/* adjust toe to the first new character, unless */
|
|
/* environment space is empty */
|
|
if (toe != 0)
|
|
toe += 2 ;
|
|
|
|
/* find out if the variable already has a value */
|
|
count = lhp->GELength - toe ;
|
|
|
|
if (nvr_find_GE_variable(vname, &nameindex, &valueindex) == stat_ok)
|
|
{
|
|
/* count free space */
|
|
/* start with the free area at the top and add */
|
|
/* the old nameindex value */
|
|
for (str = &(aptr[valueindex]) ; *str != 0 ; str++)
|
|
count++ ;
|
|
|
|
/* if free area is not large enough to handle new value return error */
|
|
if (value)
|
|
{
|
|
for (str = value ; *str != 0 ; str++)
|
|
{
|
|
if (count-- == 0)
|
|
return stat_error ;
|
|
}
|
|
}
|
|
|
|
/* pack strings */
|
|
/* first move valueindex to the end of the value */
|
|
while (aptr[valueindex++] != 0)
|
|
;
|
|
|
|
/* now move everything to where the variable starts */
|
|
/* covering up the old name/value pair */
|
|
while (valueindex < toe)
|
|
{
|
|
c = aptr[valueindex++] ;
|
|
aptr[nameindex++] = c ;
|
|
}
|
|
|
|
/* adjust new top of environment */
|
|
toe = nameindex ;
|
|
|
|
/* zero to the end of GE area */
|
|
while (nameindex < lhp->GELength)
|
|
aptr[nameindex++] = 0 ;
|
|
}
|
|
else
|
|
{
|
|
/* variable is new */
|
|
/* if free area is not large enough to handle new value return error */
|
|
if (value)
|
|
{
|
|
for (str = value ; *str != 0 ; str++)
|
|
{
|
|
if (count-- == 0)
|
|
return stat_error ;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if value is null or is a pointer to a 0 */
|
|
/* the variable has been removed */
|
|
|
|
if ( value && *value )
|
|
{
|
|
/* insert new name, converting to upper case */
|
|
while ( *vname )
|
|
{
|
|
aptr[toe] = *vname++ ;
|
|
toe++ ;
|
|
}
|
|
aptr[toe++] = '=' ;
|
|
|
|
/* insert new value */
|
|
while ( *value )
|
|
{
|
|
aptr[toe] = *value ;
|
|
value++ ;
|
|
toe++ ;
|
|
}
|
|
}
|
|
|
|
nvr_write_GEArea(pnvrobj) ;
|
|
|
|
return stat_ok ;
|
|
}
|
|
|
|
|
|
// ==
|
|
PUCHAR
|
|
nvr_fetch_GE (
|
|
VOID
|
|
)
|
|
{
|
|
ULONG i ;
|
|
ULONG toe ;
|
|
PUCHAR aptr ;
|
|
HEADER* lhp ;
|
|
PNVRAM_MAP lep ;
|
|
|
|
if (!pnvrobj)
|
|
return NULL ;
|
|
|
|
lep = (PNVRAM_MAP) pnvrobj->lend ;
|
|
|
|
NvrCopyFill (pnvrobj->lend + (ULONG)lep->Header.GEAddress,
|
|
lep->Header.GELength) ;
|
|
|
|
return (_currentfetch) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
ULONG
|
|
nvr_stat_GE (
|
|
PULONG size
|
|
)
|
|
{
|
|
ULONG i ;
|
|
ULONG toe ;
|
|
PUCHAR aptr ;
|
|
HEADER* lhp ;
|
|
ULONG free ;
|
|
|
|
if ( !pnvrobj )
|
|
return 0 ;
|
|
|
|
/* initialize pointers to GE area */
|
|
lhp = (HEADER*) pnvrobj->lhead ;
|
|
aptr = (PUCHAR) ((ULONG)lhp + (ULONG)lhp->GEAddress) ;
|
|
|
|
/* return original size to caller */
|
|
if (size)
|
|
*size = lhp->GELength ;
|
|
|
|
/* find the top of the used environment space by looking for */
|
|
/* the first non-null character from the top */
|
|
toe = lhp->GELength - 1 ;
|
|
free = 0 ;
|
|
while ((aptr[--toe]) == 0)
|
|
{
|
|
free++ ;
|
|
if (toe == 0)
|
|
break ;
|
|
}
|
|
|
|
return ( free ) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
PUCHAR
|
|
nvr_fetch_OS (
|
|
VOID
|
|
)
|
|
{
|
|
ULONG i ;
|
|
ULONG toe ;
|
|
PNVRAM_MAP lep ;
|
|
|
|
if ( !pnvrobj )
|
|
return NULL ;
|
|
|
|
lep = (PNVRAM_MAP) pnvrobj->lend ;
|
|
|
|
NvrCopyFill (pnvrobj->lend + (ULONG)lep->Header.OSAreaAddress,
|
|
lep->Header.OSAreaLength) ;
|
|
|
|
return ( _currentfetch ) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
PUCHAR
|
|
nvr_fetch_CF (
|
|
VOID
|
|
)
|
|
{
|
|
ULONG i ;
|
|
PNVRAM_MAP lep ; // LE ptr to NVRAM volatile image
|
|
|
|
if ( !pnvrobj )
|
|
return NULL ;
|
|
|
|
lep = (PNVRAM_MAP) pnvrobj->lend ;
|
|
|
|
NvrCopyFill (pnvrobj->lend + (ULONG)lep->Header.ConfigAddress,
|
|
lep->Header.ConfigLength) ;
|
|
|
|
return ( _currentfetch ) ;
|
|
}
|
|
|
|
|
|
// ==
|
|
VOID
|
|
NvrCopyFill (
|
|
PVOID src,
|
|
ULONG srclen
|
|
)
|
|
// Fill the _currentfetch area from the source described, then fill the
|
|
// remainder of the buffer with zeros. The same buffer is used to pass
|
|
// several areas, and it is the callers responsibility to copy each one
|
|
// if required before fetching another area.
|
|
{
|
|
PUCHAR srcp = (PUCHAR)src ;
|
|
PUCHAR dstp = _currentfetch ;
|
|
ULONG dstlen = MAXNVRFETCH ;
|
|
|
|
while ( dstlen-- )
|
|
{
|
|
if ( srclen )
|
|
*dstp++ = *srcp++, srclen-- ;
|
|
else
|
|
*dstp++ = 0 ;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef _HALNVR_
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Resolve references to debug functions provided by ARC that are not part
|
|
// of the HAL environment. Currently these merely disable the debugging
|
|
// features when used in the HAL, but could be expanded later to provide
|
|
// the same features available in ARC.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
DEBUG_PRINT (
|
|
LONG DebugLevelReqd,
|
|
PCHAR DebugMessage,
|
|
...
|
|
)
|
|
{
|
|
}
|
|
|
|
VOID
|
|
DEBUG_BREAK (
|
|
LONG DebugLevelReqd
|
|
)
|
|
{
|
|
}
|
|
|
|
LONG
|
|
DEBUG_GETLEVEL ()
|
|
{
|
|
return 0 ;
|
|
}
|
|
|
|
LONG
|
|
DEBUG_GETREGION ()
|
|
{
|
|
return 0 ;
|
|
}
|
|
|
|
#endif
|
|
|