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.
1745 lines
47 KiB
1745 lines
47 KiB
/*
|
|
***********************************************************************
|
|
** NVRAM
|
|
***********************************************************************
|
|
*/
|
|
#define _NOT_HALNVR_
|
|
|
|
#ifdef _HALNVR_
|
|
#include "halp.h"
|
|
#else
|
|
#include "fwp.h"
|
|
#endif /* _HALNVR_ */
|
|
|
|
#include "prepnvr.h"
|
|
#include "fwstatus.h"
|
|
#include "fwnvr.h"
|
|
|
|
/*
|
|
***********************************************************************
|
|
** internal type definitions
|
|
***********************************************************************
|
|
*/
|
|
typedef struct _nvrregs {
|
|
UCHAR reserved_0[0x74];
|
|
UCHAR addl; /* low half of address register */
|
|
UCHAR addh; /* high half of address register */
|
|
UCHAR polodata; /* NVRAM Data Port on Polo */
|
|
UCHAR sfdata; /* NVRAM Data Port on Sandalfoot */
|
|
UCHAR reserved_1[0x800-0x78];
|
|
UCHAR bb_data; /* NVRAM Data Port on BigBend (0x800) */
|
|
UCHAR reserved_2[0x400-1];
|
|
UCHAR bb_addl; /* NVRAM Lo Index Port on BigBend (0xC00) */
|
|
UCHAR bb_addh; /* NVRAM Hi Index Port on BigBend (0xC01) */
|
|
|
|
} NVRREGS, *PNVRREGS;
|
|
|
|
typedef struct _nvr_object {
|
|
struct _nvr_object *self;
|
|
NVR_SYSTEM_TYPE systype;
|
|
HEADER* bhead;
|
|
HEADER* lhead;
|
|
UCHAR bend[NVSIZE*2];
|
|
UCHAR lend[NVSIZE*2];
|
|
} NVR_OBJECT, *PNVR_OBJECT;
|
|
|
|
typedef NVRAM_MAP *PNVRAM_MAP;
|
|
|
|
/*
|
|
***********************************************************************
|
|
** private macros, defines, and externs
|
|
***********************************************************************
|
|
*/
|
|
extern PVOID HalpIoControlBase;
|
|
#define NVRAM_VIRTUAL_BASE ((PUCHAR)HalpIoControlBase)
|
|
|
|
#define _ppc_shortswap(_x) (((_x<<8)&0xff00)|((_x>>8)&0x00ff))
|
|
|
|
#define _ppc_longswap(_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 MAXNVRFETCH NVSIZE*2
|
|
|
|
/*
|
|
***********************************************************************
|
|
** prototypes of private methods
|
|
** (prototypes of public methods are defined in fwnvr.h)
|
|
***********************************************************************
|
|
*/
|
|
|
|
VOID nvr_clear_nvram(PNVR_OBJECT);
|
|
UCHAR nvr_read(NVR_SYSTEM_TYPE, ULONG);
|
|
VOID nvr_write(NVR_SYSTEM_TYPE, ULONG,UCHAR);
|
|
PNVR_OBJECT nvr_create_object(NVR_SYSTEM_TYPE);
|
|
PNVR_OBJECT nvr_alloc(ULONG);
|
|
VOID nvr_free(PVOID);
|
|
VOID nvr_default_nvram(PNVR_OBJECT);
|
|
VOID nvr_read_nvram(PNVR_OBJECT);
|
|
VOID nvr_write_Header(PNVR_OBJECT);
|
|
VOID nvr_swap_Header(HEADER*, HEADER*);
|
|
VOID nvr_headb2l(PNVR_OBJECT);
|
|
VOID nvr_headl2b(PNVR_OBJECT);
|
|
ULONG nvr_computecrc(ULONG, UCHAR);
|
|
USHORT nvr_calc1crc(PNVR_OBJECT);
|
|
USHORT nvr_calc2crc(PNVR_OBJECT);
|
|
VOID nvr_read_GEArea(PNVR_OBJECT);
|
|
VOID nvr_read_OSArea(PNVR_OBJECT);
|
|
VOID nvr_read_CFArea(PNVR_OBJECT);
|
|
VOID nvr_write_GEArea(PNVR_OBJECT);
|
|
VOID nvr_write_OSArea(PNVR_OBJECT);
|
|
VOID nvr_write_CFArea(PNVR_OBJECT);
|
|
|
|
/*
|
|
***********************************************************************
|
|
** prototypes of private debug methods are defined below
|
|
***********************************************************************
|
|
*/
|
|
//#undef KDB
|
|
#ifdef KDB
|
|
VOID nvr_display_object(PNVR_OBJECT);
|
|
VOID nvr_display_lemap(PNVR_OBJECT);
|
|
VOID nvr_display_bemap(PNVR_OBJECT);
|
|
VOID nvr_test_setvar(VOID);
|
|
#endif /* KDB */
|
|
|
|
/*
|
|
***********************************************************************
|
|
** private data items - not visible to public clients
|
|
***********************************************************************
|
|
*/
|
|
|
|
UCHAR _currentstring[MAXIMUM_ENVIRONMENT_VALUE];
|
|
UCHAR _currentfetch[MAXNVRFETCH];
|
|
|
|
#ifndef _HALNVR_
|
|
NVR_OBJECT nvrobj;
|
|
#endif /* _HALNVR_ */
|
|
|
|
PNVR_OBJECT pnvrobj = 0;
|
|
|
|
/*
|
|
***********************************************************************
|
|
** methods
|
|
***********************************************************************
|
|
*/
|
|
|
|
/***********************************************************************/
|
|
PNVR_OBJECT nvr_alloc(ULONG size)
|
|
{
|
|
PNVR_OBJECT p;
|
|
|
|
p = (PNVR_OBJECT)0;
|
|
|
|
#ifdef _HALNVR_
|
|
/* use HAL memory allocation here */
|
|
p = ExAllocatePool(NonPagedPool, size);
|
|
return(p);
|
|
#else
|
|
/* use ARC FW memory allocation here */
|
|
p = &nvrobj;
|
|
return(p);
|
|
#endif /* _HALNVR_ */
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_free(PVOID p)
|
|
{
|
|
if (p == (PVOID)NULL)
|
|
return;
|
|
|
|
#ifdef _HALNVR_
|
|
/* use HAL memory deallocation here */
|
|
ExFreePool(p);
|
|
#endif /* _HALNVR_ */
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
UCHAR nvr_read(NVR_SYSTEM_TYPE st, ULONG addr)
|
|
{
|
|
UCHAR uc;
|
|
UCHAR hi_index, lo_index;
|
|
PNVRREGS nvp = (PNVRREGS)NVRAM_VIRTUAL_BASE;
|
|
lo_index = (UCHAR)(addr & 0xff);
|
|
hi_index = (UCHAR)((addr >> 8) & 0x1f);
|
|
switch (st) {
|
|
case nvr_systype_bigbend:
|
|
WRITE_REGISTER_UCHAR(&nvp->bb_addl, lo_index);
|
|
WRITE_REGISTER_UCHAR(&nvp->bb_addh, hi_index);
|
|
break;
|
|
default:
|
|
WRITE_REGISTER_UCHAR(&nvp->addl, lo_index);
|
|
WRITE_REGISTER_UCHAR(&nvp->addh, hi_index);
|
|
break;
|
|
}
|
|
#ifndef _HALNVR_
|
|
Eieio();
|
|
#endif /* _HALNVR_ */
|
|
|
|
switch (st) {
|
|
case nvr_systype_powerstack:
|
|
case nvr_systype_sandalfoot:
|
|
uc = READ_REGISTER_UCHAR(&nvp->sfdata);
|
|
break;
|
|
case nvr_systype_bigbend:
|
|
uc = READ_REGISTER_UCHAR(&nvp->bb_data);
|
|
break;
|
|
case nvr_systype_polo:
|
|
case nvr_systype_woodfield:
|
|
uc = READ_REGISTER_UCHAR(&nvp->polodata);
|
|
break;
|
|
default:
|
|
uc = 0;
|
|
break;
|
|
}
|
|
|
|
return(uc);
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_write(NVR_SYSTEM_TYPE st, ULONG addr, UCHAR data)
|
|
{
|
|
UCHAR hi_index, lo_index;
|
|
PNVRREGS nvp = (PNVRREGS)NVRAM_VIRTUAL_BASE;
|
|
|
|
lo_index = (UCHAR)(addr & 0xff);
|
|
hi_index = (UCHAR)((addr >> 8) & 0x1f);
|
|
switch (st) {
|
|
case nvr_systype_bigbend:
|
|
WRITE_REGISTER_UCHAR(&nvp->bb_addl, lo_index);
|
|
WRITE_REGISTER_UCHAR(&nvp->bb_addh, hi_index);
|
|
break;
|
|
default:
|
|
WRITE_REGISTER_UCHAR(&nvp->addl, lo_index);
|
|
WRITE_REGISTER_UCHAR(&nvp->addh, hi_index);
|
|
break;
|
|
}
|
|
#ifndef _HALNVR_
|
|
Eieio();
|
|
#endif /* _HALNVR_ */
|
|
|
|
switch (st) {
|
|
case nvr_systype_powerstack:
|
|
case nvr_systype_sandalfoot:
|
|
WRITE_REGISTER_UCHAR(&nvp->sfdata, data);
|
|
break;
|
|
case nvr_systype_bigbend:
|
|
WRITE_REGISTER_UCHAR(&nvp->bb_data, data);
|
|
break;
|
|
case nvr_systype_polo:
|
|
case nvr_systype_woodfield:
|
|
WRITE_REGISTER_UCHAR(&nvp->polodata, data);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#ifndef _HALNVR_
|
|
Eieio();
|
|
#endif /* _HALNVR_ */
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_swap_Header(HEADER* dest, HEADER* src)
|
|
{
|
|
ULONG i;
|
|
PUCHAR cp;
|
|
|
|
/* validate pointers */
|
|
if ((dest == NULL) || (src == NULL))
|
|
return;
|
|
|
|
dest->Size = _ppc_shortswap(src->Size);
|
|
dest->Version = src->Version;
|
|
dest->Revision = src->Revision;
|
|
dest->Crc1 = _ppc_shortswap(src->Crc1);
|
|
dest->Crc2 = _ppc_shortswap(src->Crc2);
|
|
dest->LastOS = src->LastOS;
|
|
dest->Endian = src->Endian;
|
|
dest->OSAreaUsage = src->OSAreaUsage;
|
|
dest->PMMode = src->PMMode;
|
|
|
|
/* convert NVRRESTART_BLOCK structure of Header */
|
|
dest->ResumeBlock.CheckSum = _ppc_longswap(src->ResumeBlock.CheckSum);
|
|
dest->ResumeBlock.BootStatus = _ppc_longswap(src->ResumeBlock.BootStatus);
|
|
dest->ResumeBlock.ResumeAddr =
|
|
(VOID *) _ppc_longswap((ULONG)src->ResumeBlock.ResumeAddr);
|
|
dest->ResumeBlock.SaveAreaAddr =
|
|
(VOID *) _ppc_longswap((ULONG)src->ResumeBlock.SaveAreaAddr);
|
|
dest->ResumeBlock.SaveAreaLength =
|
|
_ppc_longswap((ULONG)src->ResumeBlock.SaveAreaLength);
|
|
dest->ResumeBlock.HibResumeImageRBA =
|
|
_ppc_longswap((ULONG)src->ResumeBlock.HibResumeImageRBA);
|
|
dest->ResumeBlock.HibResumeImageRBACount =
|
|
_ppc_longswap((ULONG)src->ResumeBlock.HibResumeImageRBACount);
|
|
dest->ResumeBlock.Reserved =
|
|
_ppc_longswap((ULONG)src->ResumeBlock.Reserved);
|
|
|
|
/* convert SECURITY structure */
|
|
dest->Security.BootErrCnt =
|
|
_ppc_longswap(src->Security.BootErrCnt);
|
|
dest->Security.ConfigErrCnt =
|
|
_ppc_longswap(src->Security.ConfigErrCnt);
|
|
dest->Security.BootErrorDT[0] =
|
|
_ppc_longswap(src->Security.BootErrorDT[0]);
|
|
dest->Security.BootErrorDT[1] =
|
|
_ppc_longswap(src->Security.BootErrorDT[1]);
|
|
dest->Security.ConfigErrorDT[0] =
|
|
_ppc_longswap(src->Security.ConfigErrorDT[0]);
|
|
dest->Security.ConfigErrorDT[1] =
|
|
_ppc_longswap(src->Security.ConfigErrorDT[1]);
|
|
dest->Security.BootCorrectDT[0] =
|
|
_ppc_longswap(src->Security.BootCorrectDT[0]);
|
|
dest->Security.BootCorrectDT[1] =
|
|
_ppc_longswap(src->Security.BootCorrectDT[1]);
|
|
dest->Security.ConfigCorrectDT[0] =
|
|
_ppc_longswap(src->Security.ConfigCorrectDT[0]);
|
|
dest->Security.ConfigCorrectDT[1] =
|
|
_ppc_longswap(src->Security.ConfigCorrectDT[1]);
|
|
dest->Security.BootSetDT[0] =
|
|
_ppc_longswap(src->Security.BootSetDT[0]);
|
|
dest->Security.BootSetDT[1] =
|
|
_ppc_longswap(src->Security.BootSetDT[1]);
|
|
dest->Security.ConfigSetDT[0] =
|
|
_ppc_longswap(src->Security.ConfigSetDT[0]);
|
|
dest->Security.ConfigSetDT[1] =
|
|
_ppc_longswap(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 */
|
|
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 = (VOID *) _ppc_longswap((ULONG)src->GEAddress);
|
|
dest->GELength = _ppc_longswap(src->GELength);
|
|
dest->GELastWriteDT[0] = _ppc_longswap(src->GELastWriteDT[0]);
|
|
dest->GELastWriteDT[1] = _ppc_longswap(src->GELastWriteDT[1]);
|
|
|
|
dest->ConfigAddress =
|
|
(VOID *)_ppc_longswap((ULONG)src->ConfigAddress);
|
|
dest->ConfigLength = _ppc_longswap(src->ConfigLength);
|
|
dest->ConfigLastWriteDT[0] =
|
|
_ppc_longswap(src->ConfigLastWriteDT[0]);
|
|
dest->ConfigLastWriteDT[1] =
|
|
_ppc_longswap(src->ConfigLastWriteDT[1]);
|
|
dest->ConfigCount = _ppc_longswap(src->ConfigCount);
|
|
|
|
dest->OSAreaAddress =
|
|
(VOID *)_ppc_longswap((ULONG)src->OSAreaAddress);
|
|
dest->OSAreaLength = _ppc_longswap(src->OSAreaLength);
|
|
dest->OSAreaLastWriteDT[0] =
|
|
_ppc_longswap(src->OSAreaLastWriteDT[0]);
|
|
dest->OSAreaLastWriteDT[1] =
|
|
_ppc_longswap(src->OSAreaLastWriteDT[1]);
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_headb2l(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
PUCHAR cp;
|
|
HEADER *dest;
|
|
HEADER *src;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
dest = (HEADER*)p->lend;
|
|
src = (HEADER*)p->bend;
|
|
|
|
nvr_swap_Header(dest, src);
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_headl2b(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
PUCHAR cp;
|
|
HEADER *dest;
|
|
HEADER *src;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
dest = (HEADER*)p->bend;
|
|
src = (HEADER*)p->lend;
|
|
|
|
nvr_swap_Header(dest, src);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
***********************************************************************
|
|
** the following attempts to protect operation from faulty
|
|
** intitialization of NVRAM by early versions of the machine FW
|
|
***********************************************************************
|
|
*/
|
|
#define GEASIZE (NVSIZE-CONFSIZE-OSAREASIZE-sizeof(HEADER))
|
|
VOID nvr_default_nvram(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
PUCHAR cp;
|
|
HEADER* bethp;
|
|
|
|
#ifdef KDB
|
|
DbgPrint("************** nvr_default_nvram: entry\n");
|
|
#endif /* KDB */
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
/* clear the chip memory */
|
|
nvr_clear_nvram(p);
|
|
|
|
cp = (PUCHAR)p->bend;
|
|
bethp = (HEADER *) cp;
|
|
/* clear internal header */
|
|
for (i = 0; i < sizeof(HEADER); i++)
|
|
*cp++ = 0;
|
|
|
|
/* clear internal data areas */
|
|
for (i = 0; i < (NVSIZE*2); i++)
|
|
p->bend[i] = p->lend[i] = 0;
|
|
|
|
/* initialize size according to what we know about type */
|
|
if (p->systype == nvr_systype_polo)
|
|
bethp->Size = _ppc_shortswap((USHORT)8);
|
|
else if (p->systype == nvr_systype_woodfield)
|
|
bethp->Size = _ppc_shortswap((USHORT)8);
|
|
else
|
|
bethp->Size = _ppc_shortswap((USHORT)4);
|
|
bethp->Endian = 'B';
|
|
|
|
/* init the header to default values */
|
|
if (_ppc_shortswap((USHORT)bethp->Size) == 8) {
|
|
/* size of NVRAM is 8k */
|
|
if (_ppc_longswap((ULONG)bethp->GEAddress) == 0) {
|
|
bethp->GEAddress = (VOID *)_ppc_longswap((ULONG)sizeof(HEADER));
|
|
bethp->GELength = _ppc_longswap((ULONG)GEASIZE+NVSIZE);
|
|
}
|
|
if (_ppc_longswap((ULONG)bethp->OSAreaAddress) == 0) {
|
|
bethp->OSAreaAddress =
|
|
(VOID *)_ppc_longswap((ULONG)((NVSIZE*2)-(CONFSIZE+OSAREASIZE)));
|
|
bethp->OSAreaLength =
|
|
_ppc_longswap((ULONG)OSAREASIZE);
|
|
}
|
|
if (_ppc_longswap((ULONG)bethp->ConfigAddress) == 0) {
|
|
bethp->ConfigAddress = (VOID *)_ppc_longswap((ULONG)(NVSIZE*2));
|
|
bethp->ConfigLength = _ppc_longswap((ULONG)0);
|
|
}
|
|
}
|
|
else {
|
|
/* size is assumed to be 4k */
|
|
if (_ppc_longswap((ULONG)bethp->GEAddress) == 0) {
|
|
bethp->GEAddress = (VOID *)_ppc_longswap((ULONG)sizeof(HEADER));
|
|
bethp->GELength = _ppc_longswap((ULONG)GEASIZE);
|
|
}
|
|
if (_ppc_longswap((ULONG)bethp->OSAreaAddress) == 0) {
|
|
bethp->OSAreaAddress =
|
|
(VOID *)_ppc_longswap((ULONG)(NVSIZE-(CONFSIZE+OSAREASIZE)));
|
|
bethp->OSAreaLength =
|
|
_ppc_longswap((ULONG)OSAREASIZE);
|
|
}
|
|
if (_ppc_longswap((ULONG)bethp->ConfigAddress) == 0) {
|
|
bethp->ConfigAddress = (VOID *)_ppc_longswap((ULONG)NVSIZE);
|
|
bethp->ConfigLength = _ppc_longswap((ULONG)0);
|
|
}
|
|
}
|
|
|
|
/* transfer data to little endian (internal) side */
|
|
nvr_headb2l(p);
|
|
|
|
/* write the default header to chip memory */
|
|
nvr_write_Header(p);
|
|
|
|
#ifdef KDB
|
|
DbgPrint("************** nvr_default_nvram: exit\n");
|
|
#endif /* KDB */
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_read_nvram(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
PUCHAR cp;
|
|
HEADER* hp;
|
|
USHORT us;
|
|
USHORT tmp;
|
|
|
|
#ifdef KDB
|
|
DbgPrint("enter nvr_read_nvram\n");
|
|
#endif /* KDB */
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
/* read data from the NVRAM chip */
|
|
hp = p->bhead;
|
|
cp = (PUCHAR)p->bend;
|
|
for (i = 0; i < sizeof(HEADER); i++)
|
|
*cp++ = nvr_read(p->systype,i);
|
|
|
|
#ifdef KDB
|
|
DbgPrint("IMMEDIATELY AFTER READ HEADER - NO DATA AREAS READ\n");
|
|
nvr_display_bemap(p);
|
|
#endif /* KDB */
|
|
|
|
if ((hp->Endian != 'B') && (hp->Endian != 'L')) {
|
|
#ifdef KDB
|
|
DbgPrint("BAD ENDIAN\n");
|
|
#endif /* KDB */
|
|
nvr_default_nvram(p);
|
|
return;
|
|
}
|
|
|
|
/* convert big endian to little endian */
|
|
nvr_headb2l(p);
|
|
|
|
/* read in data areas */
|
|
nvr_read_GEArea(p);
|
|
nvr_read_OSArea(p);
|
|
nvr_read_CFArea(p);
|
|
|
|
#ifdef KDB
|
|
DbgPrint("After Areas\n");
|
|
#endif /* KDB */
|
|
|
|
/* check valid checksum 1 */
|
|
us = _ppc_shortswap(hp->Crc1);
|
|
tmp = nvr_calc1crc(p);
|
|
if (tmp != us) {
|
|
#ifdef KDB
|
|
DbgPrint("BADCRC1 nvr_read_nvram: orgcrc1: 0x%08x calccrc1: 0x%08x\n",
|
|
(int)us, (int)tmp);
|
|
#endif /* KDB */
|
|
nvr_default_nvram(p);
|
|
return;
|
|
}
|
|
|
|
#ifdef KDB
|
|
DbgPrint("After CRC1\n");
|
|
#endif /* KDB */
|
|
|
|
#if 0 // Don't let a bad CRC #2 bother us
|
|
/* check valid checksum 2 */
|
|
us = _ppc_shortswap(hp->Crc2);
|
|
tmp = nvr_calc2crc(p);
|
|
if (tmp != us) {
|
|
#ifdef KDB
|
|
DbgPrint("BADCRC2 nvr_read_nvram: orgcrc2: 0x%08x calccrc2: 0x%08x\n",
|
|
(int)us, (int)tmp);
|
|
#endif /* KDB */
|
|
nvr_default_nvram(p);
|
|
return;
|
|
}
|
|
|
|
#ifdef KDB
|
|
DbgPrint("After CRC2\n");
|
|
#endif /* KDB */
|
|
#endif
|
|
|
|
#ifdef KDB
|
|
DbgPrint("exit nvr_read_nvram: SUCCESS\n");
|
|
#endif /* KDB */
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_write_Header(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
PUCHAR cp;
|
|
USHORT us;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
/* convert little endian to big endian */
|
|
nvr_headl2b(p);
|
|
|
|
us = nvr_calc1crc(p);
|
|
p->bhead->Crc1 = _ppc_shortswap(us);
|
|
us = nvr_calc2crc(p);
|
|
p->bhead->Crc2 = _ppc_shortswap(us);
|
|
|
|
/* spit out data */
|
|
cp = (PUCHAR)p->bend;
|
|
for (i = 0; i < sizeof(HEADER); i++)
|
|
nvr_write(p->systype, i, *cp++);
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_read_GEArea(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
PUCHAR lp;
|
|
PUCHAR bp;
|
|
ULONG offset;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
/* suck up global environment data */
|
|
/* and place it in both little and big endian sides */
|
|
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(p->systype, offset + i);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_read_OSArea(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
PUCHAR lp;
|
|
PUCHAR bp;
|
|
ULONG offset;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
/* suck up OS specific data */
|
|
/* and place it in both little and big endian sides */
|
|
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(p->systype, offset + i);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_read_CFArea(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
PUCHAR lp;
|
|
PUCHAR bp;
|
|
ULONG offset;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
/* suck up configuration data */
|
|
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(p->systype, (offset + i));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_write_GEArea(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
PUCHAR dest;
|
|
PUCHAR src;
|
|
ULONG offset;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
/* 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(p->systype, (i + offset), *src);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_write_OSArea(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
ULONG offset;
|
|
PUCHAR src;
|
|
PUCHAR dest;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
/* 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(p->systype, (i + offset), *src);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_write_CFArea(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
PUCHAR dest;
|
|
PUCHAR src;
|
|
ULONG offset;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
/* 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(p->systype, (i + offset), *src);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
PNVR_OBJECT nvr_create_object(NVR_SYSTEM_TYPE systemtype)
|
|
{
|
|
ULONG i;
|
|
PUCHAR cp;
|
|
UCHAR pid;
|
|
|
|
pnvrobj = nvr_alloc(sizeof(NVR_OBJECT));
|
|
|
|
if (pnvrobj) {
|
|
/* success */
|
|
/* zero out input area */
|
|
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;
|
|
|
|
switch (systemtype) {
|
|
case nvr_systype_powerstack:
|
|
case nvr_systype_sandalfoot:
|
|
pnvrobj->systype = nvr_systype_sandalfoot;
|
|
break;
|
|
case nvr_systype_bigbend:
|
|
pnvrobj->systype = nvr_systype_bigbend;
|
|
break;
|
|
case nvr_systype_polo:
|
|
pnvrobj->systype = nvr_systype_polo;
|
|
break;
|
|
case nvr_systype_woodfield:
|
|
pnvrobj->systype = nvr_systype_woodfield;
|
|
break;
|
|
default:
|
|
pnvrobj->systype = nvr_systype_unknown;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(pnvrobj);
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_delete_object()
|
|
{
|
|
PNVR_OBJECT p = pnvrobj;
|
|
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
p->self = (PNVR_OBJECT)0;
|
|
|
|
(void)nvr_free(p);
|
|
|
|
pnvrobj = (PNVR_OBJECT)0;
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
STATUS_TYPE nvr_initialize_object(NVR_SYSTEM_TYPE systemtype)
|
|
{
|
|
HEADER* hp;
|
|
|
|
#ifdef KDB
|
|
DbgPrint("enter nvr_initialize_object\n");
|
|
#endif /* KDB */
|
|
|
|
if (pnvrobj)
|
|
return(stat_exist);
|
|
|
|
/* create object or get static address */
|
|
if (!(pnvrobj = nvr_create_object(systemtype)))
|
|
return(stat_error);
|
|
|
|
/* read the header from NVRAM and convert to little endian */
|
|
nvr_read_nvram(pnvrobj);
|
|
|
|
return(stat_ok);
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_clear_nvram(PNVR_OBJECT p)
|
|
{
|
|
ULONG i;
|
|
ULONG len;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
len = NVSIZE;
|
|
switch (p->systype) {
|
|
case nvr_systype_polo:
|
|
case nvr_systype_woodfield:
|
|
len *= 2;
|
|
break;
|
|
case nvr_systype_powerstack:
|
|
case nvr_systype_sandalfoot:
|
|
break;
|
|
case nvr_systype_delmar:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < len; i++) {
|
|
nvr_write(p->systype,i,0);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/***********************************************************************/
|
|
VOID nvr_destroy()
|
|
{
|
|
NVR_SYSTEM_TYPE st;
|
|
|
|
/* validate pointer */
|
|
if ((pnvrobj == NULL) || (pnvrobj != pnvrobj->self))
|
|
return;
|
|
|
|
st = pnvrobj->systype;
|
|
|
|
nvr_delete_object();
|
|
nvr_initialize_object(st);
|
|
nvr_clear_nvram(pnvrobj);
|
|
nvr_delete_object();
|
|
|
|
nvr_initialize_object(st);
|
|
|
|
#ifdef KDB
|
|
nvr_display_object(pnvrobj);
|
|
nvr_display_lemap(pnvrobj);
|
|
nvr_display_bemap(pnvrobj);
|
|
#endif /* KDB */
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
***********************************************************************
|
|
** Computation of CRCs must be done consistent with the approach
|
|
** taken by the Firmware (Dakota or Open FW). The algorithm for the
|
|
** following CRC routines (i.e., nvr_computecrc, nvr_calc1crc,
|
|
** nvr_calc2crc were obtained from the ESW group that develops
|
|
** Dakota FW
|
|
**
|
|
** If Dakota changes, then these routines may have to change also.
|
|
**
|
|
** 07.21.94
|
|
***********************************************************************
|
|
*/
|
|
|
|
#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;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return(0);
|
|
|
|
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]);
|
|
|
|
// advance to calculate the area after Crc1, Crc2, and LastOS
|
|
// to include the region up to the OSArea
|
|
i += (sizeof(p->bhead->Crc1) + sizeof(p->bhead->Crc2)) + 1;
|
|
for (i = i; i < len2; i++)
|
|
ul = nvr_computecrc(ul, cp[i]);
|
|
|
|
us = (USHORT)(ul & 0x0ffff);
|
|
|
|
return(us);
|
|
}
|
|
|
|
USHORT nvr_calc2crc(PNVR_OBJECT p)
|
|
{
|
|
ULONG ul;
|
|
PUCHAR cp;
|
|
PUCHAR end;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return 0;
|
|
|
|
ul = 0x0ffff;
|
|
|
|
cp = (PUCHAR)((ULONG)p->bhead + (ULONG)p->lhead->ConfigAddress);
|
|
end = (PUCHAR)((ULONG)p->bhead +
|
|
(ULONG)(((ULONG)p->lhead->Size << 10) - 1));
|
|
for (; cp < end; cp++)
|
|
ul = nvr_computecrc(ul, *cp);
|
|
|
|
return((USHORT)(ul & 0x0ffff));
|
|
}
|
|
|
|
/*
|
|
***********************************************************************
|
|
** Computation of CRCs must be done consistent with the approach
|
|
** taken by the Firmware (Dakota or Open FW). The algorithm for the
|
|
** above CRC routines (i.e., nvr_computecrc, nvr_calc1crc,
|
|
** nvr_calc2crc were obtained from the ESW group that develops
|
|
** Dakota FW
|
|
**
|
|
** 07.21.94
|
|
***********************************************************************
|
|
*/
|
|
|
|
/*
|
|
***********************************************************************
|
|
** ----------- Methods Public to the higher layers of SW -------------
|
|
** The methods 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
|
|
** downloaded back to NVRAM.
|
|
***********************************************************************
|
|
*/
|
|
|
|
VOID nvr_print_object()
|
|
{
|
|
#ifdef KDB
|
|
nvr_display_object(pnvrobj);
|
|
nvr_display_lemap(pnvrobj);
|
|
nvr_display_bemap(pnvrobj);
|
|
#endif /* KDB */
|
|
return;
|
|
}
|
|
|
|
STATUS_TYPE nvr_find_OS_variable(PUCHAR var, PULONG ni, PULONG vi)
|
|
{
|
|
PUCHAR lvar;
|
|
PUCHAR cp;
|
|
ULONG i;
|
|
PNVRAM_MAP little_nvrmap;
|
|
|
|
if (*var == 0)
|
|
return(stat_error);
|
|
|
|
if (!pnvrobj)
|
|
return(stat_error);
|
|
|
|
little_nvrmap = (PNVRAM_MAP)pnvrobj->lend;
|
|
|
|
i = 0;
|
|
while (TRUE) {
|
|
lvar = var;
|
|
*ni = i;
|
|
cp = (PUCHAR)((ULONG)little_nvrmap +
|
|
(ULONG)(little_nvrmap->Header.OSAreaAddress));
|
|
|
|
/* does the variable we want start at this index? */
|
|
while (i < little_nvrmap->Header.OSAreaLength) {
|
|
/* break if mismatch */
|
|
if (_toupr_(cp[i]) != _toupr_(*lvar))
|
|
break;
|
|
lvar++;
|
|
i++;
|
|
}
|
|
|
|
/* if we're at the end of OSArea and var has a match */
|
|
if ((*lvar == 0) && (cp[i] == '=')) {
|
|
*vi = ++i;
|
|
return(stat_ok);
|
|
}
|
|
|
|
/* no match - set index to start of the next variable */
|
|
if (i >= little_nvrmap->Header.OSAreaLength)
|
|
return(stat_error);
|
|
while (cp[i++] != 0) {
|
|
if (i >= little_nvrmap->Header.OSAreaLength)
|
|
return(stat_error);
|
|
}
|
|
}
|
|
}
|
|
|
|
STATUS_TYPE nvr_find_GE_variable(PUCHAR var, PULONG ni, PULONG vi)
|
|
{
|
|
PUCHAR lvar;
|
|
PUCHAR cp;
|
|
ULONG i;
|
|
HEADER* lhp;
|
|
|
|
if (*var == 0)
|
|
return(stat_error);
|
|
|
|
if (!pnvrobj)
|
|
return(stat_error);
|
|
|
|
lhp = (HEADER*)pnvrobj->lhead;
|
|
|
|
i = 0;
|
|
while (TRUE) {
|
|
lvar = var;
|
|
*ni = i;
|
|
cp = (PUCHAR)((ULONG)lhp + (ULONG)(lhp->GEAddress));
|
|
|
|
/* does the variable we want start at this index? */
|
|
while (i < lhp->GELength) {
|
|
/* break if mismatch */
|
|
if (_toupr_(cp[i]) != _toupr_(*lvar))
|
|
break;
|
|
lvar++;
|
|
i++;
|
|
}
|
|
|
|
/* if we're at the end of GEArea and var has a match */
|
|
if ((*lvar == 0) && (cp[i] == '=')) {
|
|
*vi = ++i;
|
|
return(stat_ok);
|
|
}
|
|
|
|
/* no match - set index to start of the next variable */
|
|
if (i >= lhp->GELength)
|
|
return(stat_error);
|
|
while (cp[i++] != 0) {
|
|
if (i >= lhp->GELength)
|
|
return(stat_error);
|
|
}
|
|
}
|
|
}
|
|
|
|
PUCHAR nvr_get_OS_variable(PUCHAR vname)
|
|
{
|
|
ULONG ni;
|
|
ULONG vi;
|
|
ULONG i;
|
|
PNVRAM_MAP little_nvrmap;
|
|
|
|
if (!pnvrobj)
|
|
return((PUCHAR)NULL);
|
|
|
|
if (nvr_find_OS_variable(vname, &ni, &vi) != stat_ok)
|
|
return((PUCHAR)NULL);
|
|
|
|
little_nvrmap = (PNVRAM_MAP)pnvrobj->lend;
|
|
|
|
for (i = 0; i < MAXIMUM_ENVIRONMENT_VALUE - 1; i++) {
|
|
if (little_nvrmap->OSArea[vi] == 0)
|
|
break;
|
|
_currentstring[i] = little_nvrmap->OSArea[vi++];
|
|
}
|
|
_currentstring[i] = 0;
|
|
|
|
return(_currentstring);
|
|
}
|
|
|
|
PUCHAR nvr_get_GE_variable(PUCHAR vname)
|
|
{
|
|
ULONG ni;
|
|
ULONG vi;
|
|
ULONG i;
|
|
PUCHAR cp;
|
|
HEADER* lhp;
|
|
|
|
if (!pnvrobj)
|
|
return((PUCHAR)NULL);
|
|
|
|
if (nvr_find_GE_variable(vname, &ni, &vi) != stat_ok)
|
|
return((PUCHAR)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;
|
|
|
|
#ifdef KDB
|
|
DbgPrint("get_GE vname: '%s' value: '%s'\n", vname, _currentstring);
|
|
#endif /* KDB */
|
|
|
|
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 ((vname == 0) || (value == 0))
|
|
return(stat_error);
|
|
|
|
if (*vname == 0)
|
|
return(stat_error);
|
|
|
|
if (!pnvrobj)
|
|
return(stat_error);
|
|
|
|
lhp = (HEADER*)pnvrobj->lhead;
|
|
|
|
#ifdef KDB
|
|
DbgPrint("OS vname: '%s' value: '%s'\n", vname, value);
|
|
#endif /* KDB */
|
|
|
|
/* 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 != 0) {
|
|
aptr[eos++] = _toupr_(*vname);
|
|
vname++;
|
|
}
|
|
aptr[eos++] = '=';
|
|
|
|
// insert new value
|
|
while (*value != 0) {
|
|
aptr[eos++] = *value;
|
|
value++;
|
|
}
|
|
}
|
|
|
|
nvr_write_OSArea(pnvrobj);
|
|
|
|
return(stat_ok);
|
|
}
|
|
|
|
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 (vname == 0)
|
|
return(stat_error);
|
|
|
|
if (*vname == 0)
|
|
return(stat_error);
|
|
|
|
if (!pnvrobj)
|
|
return(stat_error);
|
|
|
|
lhp = (HEADER*)pnvrobj->lhead;
|
|
|
|
#ifdef KDB
|
|
DbgPrint("set_GE vname: '%s' value: '%s'\n", vname, value);
|
|
#endif /* KDB */
|
|
|
|
/* initialize pointer to OS 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 != 0) {
|
|
aptr[toe] = _toupr_(*vname);
|
|
vname++;
|
|
toe++;
|
|
}
|
|
aptr[toe++] = '=';
|
|
|
|
/* insert new value */
|
|
while (*value != 0) {
|
|
aptr[toe] = *value;
|
|
value++;
|
|
toe++;
|
|
}
|
|
}
|
|
|
|
nvr_write_GEArea(pnvrobj);
|
|
|
|
return(stat_ok);
|
|
}
|
|
|
|
PUCHAR nvr_fetch_GE()
|
|
{
|
|
ULONG i;
|
|
ULONG toe;
|
|
PNVRAM_MAP little_nvrmap;
|
|
|
|
if (!pnvrobj)
|
|
return NULL;
|
|
|
|
little_nvrmap = (NVRAM_MAP *)pnvrobj->lend;
|
|
|
|
// initialize hold buffer to zeros
|
|
for (i = 0; i < little_nvrmap->Header.GELength; i++)
|
|
_currentfetch[i] = 0;
|
|
|
|
// find the top of the used environment space by looking for
|
|
// the first non-null character from the top
|
|
toe = little_nvrmap->Header.GELength - 1;
|
|
while ((little_nvrmap->GEArea[--toe]) == 0) {
|
|
if (toe == 0)
|
|
break;
|
|
}
|
|
|
|
// toe contains last index of GE
|
|
if (toe == 0)
|
|
return(_currentfetch);
|
|
|
|
// copy from GE to hold buffer
|
|
for (i = 0; ((i <= toe) && (i < MAXNVRFETCH)); i++)
|
|
_currentfetch[i] = little_nvrmap->GEArea[i];
|
|
|
|
return(_currentfetch);
|
|
}
|
|
|
|
PUCHAR nvr_fetch_OS()
|
|
{
|
|
ULONG i;
|
|
ULONG toe;
|
|
PNVRAM_MAP little_nvrmap;
|
|
|
|
if (!pnvrobj)
|
|
return NULL;
|
|
|
|
little_nvrmap = (NVRAM_MAP *)pnvrobj->lend;
|
|
|
|
// initialize the hold buffer to zeros
|
|
for (i = 0; i < little_nvrmap->Header.OSAreaLength; i++)
|
|
_currentfetch[i] = 0;
|
|
|
|
// find the top of the used environment space by looking for
|
|
// the first non-null character from the top
|
|
toe = little_nvrmap->Header.OSAreaLength - 1;
|
|
while ((little_nvrmap->OSArea[--toe]) == 0) {
|
|
if (toe == 0)
|
|
break;
|
|
}
|
|
|
|
// toe contains last index of OS
|
|
if (toe == 0)
|
|
return(_currentfetch);
|
|
|
|
// copy from OS to hold buffer
|
|
for (i = 0; ((i <= toe) && (i < MAXNVRFETCH)); i++)
|
|
_currentfetch[i] = little_nvrmap->OSArea[i];
|
|
|
|
return(_currentfetch);
|
|
}
|
|
|
|
PUCHAR nvr_fetch_CF()
|
|
{
|
|
ULONG i;
|
|
PNVRAM_MAP little_nvrmap;
|
|
|
|
if (!pnvrobj)
|
|
return NULL;
|
|
|
|
little_nvrmap = (NVRAM_MAP *)pnvrobj->lend;
|
|
|
|
/* initialize the hold buffer to zeros */
|
|
for (i = 0; i < MAXNVRFETCH; i++)
|
|
_currentfetch[i] = 0;
|
|
|
|
/* copy from Config to hold buffer */
|
|
for (i = 0; i < little_nvrmap->Header.ConfigLength; i++)
|
|
_currentfetch[i] = little_nvrmap->ConfigArea[i];
|
|
|
|
return(_currentfetch);
|
|
}
|
|
|
|
/*
|
|
***********************************************************************
|
|
** ----------- Methods Public to the higher layers of SW -------------
|
|
** The methods above 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
|
|
** downloaded back to NVRAM.
|
|
***********************************************************************
|
|
*/
|
|
|
|
#ifdef KDB
|
|
/*
|
|
***********************************************************************
|
|
** The methods below are used in development and debug.
|
|
***********************************************************************
|
|
*/
|
|
|
|
VOID nvr_display_object(PNVR_OBJECT p)
|
|
{
|
|
PUCHAR cp;
|
|
int len;
|
|
UCHAR tmp;
|
|
PNVRAM_MAP mp;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
DbgPrint(" ---- ---- INTERNAL DISPLAY ---- ----\n\r");
|
|
DbgPrint(" Object Addr: 0x%08lx\n\r",(ULONG)p->self);
|
|
switch (p->systype) {
|
|
case nvr_systype_powerstack:
|
|
DbgPrint(" System Type: PowerStack\n\r");
|
|
break;
|
|
case nvr_systype_sandalfoot:
|
|
DbgPrint(" System Type: Sandalfoot\n\r");
|
|
break;
|
|
case nvr_systype_polo:
|
|
DbgPrint(" System Type: Polo\n\r");
|
|
break;
|
|
case nvr_systype_woodfield:
|
|
DbgPrint(" System Type: Woodfield\n\r");
|
|
break;
|
|
case nvr_systype_delmar:
|
|
DbgPrint(" System Type: Delmar\n\r");
|
|
break;
|
|
default:
|
|
DbgPrint(" System Type: Unknown\n\r");
|
|
break;
|
|
}
|
|
DbgPrint(" BE Header addr: 0x%08lx\n\r",(ULONG)p->bhead);
|
|
DbgPrint(" BE Map addr: 0x%08lx\n\r",(ULONG)p->bend);
|
|
DbgPrint(" LE Header addr: 0x%08lx\n\r",(ULONG)p->lhead);
|
|
DbgPrint(" LE Map addr: 0x%08lx\n\r",(ULONG)p->lend);
|
|
DbgPrint(" ---- ---- INTERNAL DISPLAY ---- ----\n\r");
|
|
|
|
return;
|
|
}
|
|
|
|
VOID nvr_display_lemap(PNVR_OBJECT p)
|
|
{
|
|
PUCHAR cp;
|
|
PUCHAR max;
|
|
UCHAR tmp;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
DbgPrint(" -------- ---- ---- ---- ---- LITTLE DISPLAY\n\r");
|
|
DbgPrint(" NVR Size: 0x%04xK (%dK)", (int)p->lhead->Size,
|
|
(int)p->lhead->Size);
|
|
DbgPrint(" Version: 0x%02x Revision: 0x%02x\n\r",
|
|
(int)p->lhead->Version, (int)p->lhead->Revision);
|
|
DbgPrint(" Crc1: 0x%04x Crc2: 0x%04x\n\r",
|
|
(int)p->lhead->Crc1, (int)p->lhead->Crc2);
|
|
DbgPrint(" NVR Endian: '%c'\n\r",p->lhead->Endian);
|
|
|
|
tmp = p->lhead->Security.Serial[15];
|
|
p->lhead->Security.Serial[15] = 0;
|
|
DbgPrint(" NVR Serial: '%s'\n\r",p->lhead->Security.Serial);
|
|
p->lhead->Security.Serial[15] = tmp;
|
|
|
|
DbgPrint(" GEAddress: 0x%08lx GELength: 0x%08lx\n\r",
|
|
(ULONG)p->lhead->GEAddress, (ULONG)p->lhead->GELength);
|
|
cp = (PUCHAR)((ULONG)p->lhead + (ULONG)p->lhead->GEAddress);
|
|
max = (PUCHAR)((ULONG)p->lhead + (ULONG)p->lhead->GEAddress +
|
|
(ULONG)p->lhead->GELength);
|
|
while ((*cp) && (cp < max)) {
|
|
DbgPrint(" '%s'\n\r", cp);
|
|
cp += (strlen(cp) + 1);
|
|
}
|
|
|
|
DbgPrint(" OSAreaAddress: 0x%08lx OSAreaLength: 0x%08lx\n\r",
|
|
(ULONG)p->lhead->OSAreaAddress, (ULONG)p->lhead->OSAreaLength);
|
|
cp = (PUCHAR)((ULONG)p->lhead + (ULONG)p->lhead->OSAreaAddress);
|
|
max = (PUCHAR)((ULONG)p->lhead + (ULONG)p->lhead->OSAreaAddress +
|
|
(ULONG)p->lhead->OSAreaLength);
|
|
while ((*cp) && (cp < max)) {
|
|
DbgPrint(" '%s'\n\r", cp);
|
|
cp += (strlen(cp) + 1);
|
|
}
|
|
|
|
DbgPrint(" ConfigAddress: 0x%08lx ConfigLength: 0x%08lx Count: 0x%08lx\n\r",
|
|
(ULONG)p->lhead->ConfigAddress, (ULONG)p->lhead->ConfigLength,
|
|
(ULONG)p->lhead->ConfigCount);
|
|
DbgPrint(" -------- ---- ---- ---- ---- LITTLE DISPLAY\n\r");
|
|
|
|
return;
|
|
}
|
|
|
|
VOID nvr_display_bemap(PNVR_OBJECT p)
|
|
{
|
|
PUCHAR cp;
|
|
PUCHAR max;
|
|
UCHAR tmp;
|
|
PNVRAM_MAP mp;
|
|
HEADER* hp;
|
|
|
|
/* validate pointer */
|
|
if ((p == NULL) || (p != p->self))
|
|
return;
|
|
|
|
mp = p->bend;
|
|
hp = p->bhead;
|
|
|
|
DbgPrint(" ---- ---- BIG DISPLAY ---- ----\n\r");
|
|
DbgPrint(" NVR Size: 0x%04xK (%dK)", (int)mp->Header.Size,
|
|
(int)mp->Header.Size);
|
|
DbgPrint(" Version: 0x%02x Revision: 0x%02x\n\r",
|
|
(int)mp->Header.Version, (int)mp->Header.Revision);
|
|
DbgPrint(" Crc1: 0x%04x Crc2: 0x%04x\n\r",
|
|
(int)mp->Header.Crc1, (int)mp->Header.Crc2);
|
|
DbgPrint(" NVR Endian: '%c'\n\r",mp->Header.Endian);
|
|
|
|
tmp = mp->Header.Security.Serial[15];
|
|
mp->Header.Security.Serial[15] = 0;
|
|
DbgPrint(" NVR Serial: '%s'\n\r",mp->Header.Security.Serial);
|
|
mp->Header.Security.Serial[15] = tmp;
|
|
|
|
DbgPrint(" GEAddress: 0x%08lx GELength: 0x%08lx\n\r",
|
|
(ULONG)hp->GEAddress, (ULONG)hp->GELength);
|
|
cp = (PUCHAR)((ULONG)hp + _ppc_longswap((ULONG)hp->GEAddress));
|
|
max = (PUCHAR)((ULONG)cp + _ppc_longswap((ULONG)hp->GELength));
|
|
while ((*cp) && (cp < max)) {
|
|
DbgPrint(" '%s'\n\r", cp);
|
|
cp += (strlen(cp) + 1);
|
|
}
|
|
|
|
DbgPrint(" OSAreaAddress: 0x%08lx OSAreaLength: 0x%08lx\n\r",
|
|
(ULONG)hp->OSAreaAddress, (ULONG)hp->OSAreaLength);
|
|
cp = (PUCHAR)((ULONG)hp + _ppc_longswap((ULONG)hp->OSAreaAddress));
|
|
max = (PUCHAR)((ULONG)cp + _ppc_longswap((ULONG)hp->OSAreaLength));
|
|
while ((*cp) && (cp < max)) {
|
|
DbgPrint(" '%s'\n\r", cp);
|
|
cp += (strlen(cp) + 1);
|
|
}
|
|
|
|
DbgPrint(" ConfigAddress: 0x%08lx ConfigLength: 0x%08lx Count: 0x%08lx\n\r",
|
|
(ULONG)hp->ConfigAddress, (ULONG)hp->ConfigLength,
|
|
(ULONG)hp->ConfigCount);
|
|
DbgPrint(" ---- ---- BIG DISPLAY ---- ----\n\r");
|
|
|
|
return;
|
|
}
|
|
|
|
VOID nvr_test_setvar(VOID)
|
|
{
|
|
DbgPrint("\n\r");
|
|
DbgPrint("--------- VARIABLE SET TEST\n\r");
|
|
nvr_display_lemap(pnvrobj);
|
|
DbgPrint("---------\n\r");
|
|
|
|
(VOID)nvr_set_GE_variable("GESLUG0","this is it");
|
|
(VOID)nvr_set_GE_variable("GESLUG1","NO: this is it");
|
|
(VOID)nvr_set_GE_variable("GESLUG2","I beg your pardon! This is it");
|
|
|
|
(VOID)nvr_set_OS_variable("OSSLUG0","multi(0)scsi(0)");
|
|
(VOID)nvr_set_OS_variable("OSSLUG1","multi(0)scsi(1)");
|
|
(VOID)nvr_set_OS_variable("OSSLUG2",
|
|
"multi(0)scsi(0)disk(6)rdisk(0)partition(1)");
|
|
nvr_display_lemap(pnvrobj);
|
|
|
|
DbgPrint("--------- VARIABLE SET TEST\n\r");
|
|
|
|
return;
|
|
}
|
|
|
|
VOID nvr_test_object(NVR_SYSTEM_TYPE systemtype)
|
|
{
|
|
PUCHAR cp;
|
|
|
|
nvr_initialize_object(systemtype);
|
|
|
|
nvr_display_object(pnvrobj);
|
|
nvr_display_lemap(pnvrobj);
|
|
nvr_display_bemap(pnvrobj);
|
|
|
|
/***************************
|
|
cp = nvr_get_GE_variable("SYSTEMPARTITION");
|
|
if (cp) {
|
|
if (*cp == 0)
|
|
DbgPrint("nvr_test_object: SYSTEMPARTITION=-value zero-\n",cp);
|
|
else
|
|
DbgPrint("nvr_test_object: SYSTEMPARTITION='%s'\n",cp);
|
|
}
|
|
else
|
|
DbgPrint("nvr_test_object: SYSTEMPARTITION=-pointer NULL-\n");
|
|
|
|
cp = nvr_get_GE_variable("DOG000111");
|
|
if (cp) {
|
|
if (*cp == 0)
|
|
DbgPrint("nvr_test_object: DOG000111=-value zero-\n",cp);
|
|
else
|
|
DbgPrint("nvr_test_object: DOG000111='%s'\n",cp);
|
|
}
|
|
else
|
|
DbgPrint("nvr_test_object: DOG000111=-pointer NULL-\n");
|
|
|
|
DbgBreakPoint();
|
|
nvr_test_setvar();
|
|
DbgBreakPoint();
|
|
***************************/
|
|
|
|
/***************************
|
|
DbgPrint("--------- CLEARING NVRAM\n");
|
|
if (!(pnvrobj = nvr_create_object(systemtype)))
|
|
return;
|
|
nvr_clear_nvram(pnvrobj);
|
|
nvr_delete_object();
|
|
DbgPrint("--------- CLEARED NVRAM\n");
|
|
DbgBreakPoint();
|
|
***************************/
|
|
|
|
/***************************
|
|
DbgPrint("--------- REREAD NVRAM \n\r");
|
|
DbgPrint("---------\n");
|
|
DbgPrint("---------\n");
|
|
nvr_initialize_object(systemtype);
|
|
DbgPrint("nvr_calc1crc: 0x%08x\n",(int)nvr_calc1crc(pnvrobj));
|
|
DbgPrint("nvr_calc2crc: 0x%08x\n",(int)nvr_calc2crc(pnvrobj));
|
|
nvr_display_lemap(pnvrobj);
|
|
nvr_display_bemap(pnvrobj);
|
|
DbgPrint("--- SETTING VARS\n");
|
|
(VOID)nvr_set_GE_variable("GESLUG0","this is it");
|
|
(VOID)nvr_set_GE_variable("GESLUG1"," -------- this is it --------");
|
|
(VOID)nvr_set_OS_variable("OSSLUG0","multi(0)scsi(0)");
|
|
(VOID)nvr_set_OS_variable("OSSLUG1","multi(1)scsi(1)");
|
|
nvr_display_lemap(pnvrobj);
|
|
nvr_display_bemap(pnvrobj);
|
|
(VOID)nvr_set_GE_variable("GESLUG0","");
|
|
nvr_display_lemap(pnvrobj);
|
|
|
|
DbgPrint("---------\n");
|
|
DbgPrint("---------\n");
|
|
DbgPrint("--------- REREAD NVRAM \n\r");
|
|
DbgBreakPoint();
|
|
|
|
***************************/
|
|
|
|
return;
|
|
}
|
|
#endif /* KDB */
|