1451 lines
32 KiB
C
1451 lines
32 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
Copyright (c) 1993 Digital Equipment Corporation
|
||
|
||
Module Name:
|
||
|
||
jnupdate.c
|
||
|
||
Abstract:
|
||
|
||
The main module for the JNUPDATE.EXE Jensen firwmare update program.
|
||
|
||
Author:
|
||
|
||
John DeRosa 14-October-1992
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "fwp.h"
|
||
#include "machdef.h"
|
||
//#include "jnsnrtc.h"
|
||
#include "string.h"
|
||
#include "jnfs.h"
|
||
#include "jnvendor.h"
|
||
#include "iodevice.h"
|
||
#include "rom.h"
|
||
#include "fwupstr.h"
|
||
|
||
|
||
// Number of times we will try to update a block before telling the user.
|
||
#define ROM_BLOCK_RETRY_COUNT 4
|
||
|
||
|
||
#define MAXIMUM_IDENTIFIER_LENGTH 400
|
||
|
||
#define MAXIMUM_NUMBER_ROM_BLOCKS 16
|
||
|
||
#define MINIMUM_UPDATE_FILE_SIZE ( 5 + \
|
||
(SIXTY_FOUR_KB * 1) + \
|
||
4 )
|
||
#define MAXIMUM_UPDATE_FILE_SIZE ( MAXIMUM_IDENTIFIER_LENGTH + \
|
||
(SIXTY_FOUR_KB * 16 ) + \
|
||
4 )
|
||
|
||
//
|
||
// The type of ROM in this machine, and the array that that describes
|
||
// how to talk to different kinds of ROMs.
|
||
//
|
||
|
||
extern ROM_TYPE MachineROMType;
|
||
extern ROM_VALUES RomValues[InvalidROM];
|
||
|
||
//
|
||
// The indicator of a bad Firmware stack for _RtlCheckStack
|
||
//
|
||
ULONG FwRtlStackPanic;
|
||
|
||
extern PCHAR FirmwareVersion;
|
||
|
||
//
|
||
// Function prototypes
|
||
//
|
||
|
||
ARC_STATUS
|
||
FwpFindCDROM (
|
||
OUT PCHAR PathName
|
||
);
|
||
|
||
#ifdef MORGAN
|
||
|
||
VOID
|
||
MorganReadFlashRomId(
|
||
ULONG MorganFlashRomChipSelect,
|
||
PULONG MfgCode,
|
||
PULONG DeviceCode
|
||
);
|
||
|
||
ULONG
|
||
MorganBlastFlash(
|
||
ULONG MorganFlashRomChipSelect,
|
||
PUCHAR FirmwareStart,
|
||
ULONG FirmwareBufferLength
|
||
);
|
||
|
||
ARC_STATUS
|
||
MorganFsStoreIntoROM(
|
||
IN ULONG MorganFlashRomChipSelect,
|
||
IN PUCHAR FirmwareStart,
|
||
IN ULONG FirmwareBufferLength
|
||
);
|
||
|
||
|
||
#endif // ifdef MORGAN
|
||
|
||
|
||
VOID
|
||
main (
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This calls other functions to communicate with the user, get the
|
||
firmware update file, verify it, and do the update.
|
||
|
||
Success and error messages are printed out by this function
|
||
and/or functions below this one.
|
||
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ARC_STATUS Status;
|
||
LONG Index;
|
||
ULONG CurrentLine;
|
||
ULONG FirmwareBufferAddress;
|
||
ULONG FirmwareBufferLength;
|
||
ULONG FirmwareStart;
|
||
ULONG HighROMBlockToBeWritten;
|
||
ULONG LowROMBlockToBeWritten;
|
||
BOOLEAN VariableFound;
|
||
PCONFIGURATION_COMPONENT Controller;
|
||
PCHAR Colon;
|
||
PCHAR EnvironmentValue;
|
||
CHAR PathName[128];
|
||
PCHAR TempArgs;
|
||
CHAR UserSpecifiedPath[128];
|
||
GETSTRING_ACTION Action;
|
||
PCONFIGURATION_COMPONENT Cdrom;
|
||
|
||
|
||
FwRtlStackPanic = 0;
|
||
|
||
VenClearScreen();
|
||
|
||
VenSetPosition(1,0);
|
||
|
||
VenPrint1(FWUP_INTRO1_MSG, FirmwareVersion);
|
||
VenPrint (FWUP_INTRO2_MSG);
|
||
VenPrint (FWUP_INTRO3_MSG);
|
||
|
||
if (!JnFsProceedWithUpdate()) {
|
||
return;
|
||
}
|
||
|
||
VenClearScreen();
|
||
|
||
VenSetPosition(1,0);
|
||
VenPrint(FWUP_SELECT_LOCATION_MSG);
|
||
VenPrint(FWUP_USE_ARROW_KEYS_MSG);
|
||
VenPrint(FWUP_HIT_ESC_TO_ABORT_MSG);
|
||
|
||
Index = JzDisplayMenu(UpdateLocationChoices,
|
||
NUMBER_OF_UPDATELOCATIONCHOICES,
|
||
0,
|
||
7,
|
||
0,
|
||
FALSE);
|
||
|
||
CurrentLine = 12;
|
||
|
||
switch (Index) {
|
||
|
||
//
|
||
// Floppy drive
|
||
//
|
||
case 0:
|
||
|
||
strcpy(PathName, FWUP_DEFAULT_FLOPPY_LOCATION);
|
||
break;
|
||
|
||
//
|
||
// CD-ROM
|
||
//
|
||
case 1:
|
||
|
||
FwpFindCDROM(PathName);
|
||
strcat(PathName, FWUP_DEFAULT_CDROM_FILENAME);
|
||
break;
|
||
|
||
//
|
||
// Some other location
|
||
//
|
||
case 2:
|
||
|
||
VenSetPosition(12,0);
|
||
VenPrint(FWUP_LOCATION_OF_UPDATE_FILE_MSG);
|
||
do {
|
||
Action = JzGetString(UserSpecifiedPath,
|
||
sizeof(UserSpecifiedPath),
|
||
NULL,
|
||
12,
|
||
strlen(FWUP_LOCATION_OF_UPDATE_FILE_MSG),
|
||
FALSE
|
||
);
|
||
|
||
} while ((Action != GetStringEscape) && (Action != GetStringSuccess));
|
||
|
||
if (Action == GetStringEscape) {
|
||
return;
|
||
}
|
||
|
||
CurrentLine += 2;
|
||
|
||
|
||
//
|
||
// Strip off any arguments.
|
||
//
|
||
|
||
if ((TempArgs = strchr(UserSpecifiedPath, ' ')) != NULL) {
|
||
*TempArgs++ = 0;
|
||
}
|
||
|
||
//
|
||
// If the name does not contain a "(", then assume it is not a full
|
||
// pathname.
|
||
//
|
||
|
||
if (strchr( UserSpecifiedPath, '(') == NULL) {
|
||
|
||
//
|
||
// If the name contains a semicolon, look for an environment
|
||
// variable that defines the path.
|
||
//
|
||
|
||
if ((Colon = strchr( UserSpecifiedPath, ':')) != NULL) {
|
||
|
||
for (Index = 0; UserSpecifiedPath[Index] != ':' ; Index++ ) {
|
||
PathName[Index] = tolower(UserSpecifiedPath[Index]);
|
||
}
|
||
|
||
PathName[Index++] = ':';
|
||
PathName[Index++] = 0;
|
||
EnvironmentValue = ArcGetEnvironmentVariable(PathName);
|
||
VariableFound = FALSE;
|
||
|
||
if (EnvironmentValue != NULL) {
|
||
strcpy( PathName, EnvironmentValue);
|
||
VariableFound = TRUE;
|
||
} else if (!strcmp(PathName, "cd:")) {
|
||
for ( Index = 0 ; Index < 8 ; Index++ ) {
|
||
sprintf(PathName, "scsi(0)cdrom(%d)fdisk(0)", Index);
|
||
Controller = ArcGetComponent(PathName);
|
||
if ((Controller != NULL) && (Controller->Type == FloppyDiskPeripheral)) {
|
||
VariableFound = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!VariableFound) {
|
||
VenSetPosition( 17, 0);
|
||
VenSetScreenColor(ArcColorRed, ArcColorWhite);
|
||
VenPrint(FWUP_UNDEFINED_PATHNAME_MSG);
|
||
FwWaitForKeypress(FALSE);
|
||
VenSetScreenColor(ArcColorWhite, ArcColorBlue);
|
||
return;
|
||
} else {
|
||
strcat( PathName, Colon + 1);
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// The filespec does not contain a '(' or a :.
|
||
// FWSEARCHPATH is not supported in this tool.
|
||
// Therefore, declare an error.
|
||
//
|
||
|
||
VenSetPosition( 17, 0);
|
||
VenSetScreenColor(ArcColorRed, ArcColorWhite);
|
||
VenPrint1(FWUP_BAD_PATHNAME_MSG, UserSpecifiedPath);
|
||
FwWaitForKeypress(FALSE);
|
||
VenSetScreenColor(ArcColorWhite, ArcColorBlue);
|
||
return;
|
||
}
|
||
|
||
} else {
|
||
strcpy( PathName, UserSpecifiedPath);
|
||
}
|
||
break;
|
||
|
||
|
||
//
|
||
// Exit, or internal error.
|
||
//
|
||
case 3:
|
||
default:
|
||
return;
|
||
|
||
}
|
||
|
||
VenSetPosition(CurrentLine, 0);
|
||
VenPrint(FWUP_LOCATING_THE_FILE_MSG);
|
||
|
||
Status = ReadAndVerifyUpdateFile(PathName, &FirmwareBufferAddress,
|
||
&FirmwareStart,
|
||
&FirmwareBufferLength,
|
||
&LowROMBlockToBeWritten,
|
||
&HighROMBlockToBeWritten);
|
||
|
||
if (Status != ESUCCESS) {
|
||
JnFsDecodeBadStatus(Status);
|
||
FwWaitForKeypress(FALSE);
|
||
return;
|
||
}
|
||
|
||
VenClearScreen();
|
||
|
||
VenSetPosition(1,0);
|
||
VenPrint(FWUP_UPDATE_FILE_IS_GOOD_MSG);
|
||
|
||
VenPrint ((PUCHAR)FirmwareBufferAddress);
|
||
|
||
//
|
||
// If manufacturing followed the rules, we should be at or above row #14.
|
||
//
|
||
|
||
VenPrint("\r\n\n");
|
||
if (!JnFsProceedWithUpdate()) {
|
||
return;
|
||
}
|
||
|
||
VenPrint(FWUP_ARE_YOU_REALLY_SURE_MSG);
|
||
|
||
if (!JnFsProceedWithUpdate()) {
|
||
return;
|
||
}
|
||
|
||
#ifdef JENSEN
|
||
Status = JnFsStoreIntoROM((PUCHAR)FirmwareStart, LowROMBlockToBeWritten,
|
||
HighROMBlockToBeWritten);
|
||
#endif // JENSEN
|
||
|
||
#ifdef MORGAN
|
||
VenPrint1(FWUP_ABOUT_TO_WRITE_ROM_MSG, LowROMBlockToBeWritten);
|
||
FwWaitForKeypress();
|
||
Status = MorganFsStoreIntoROM( LowROMBlockToBeWritten, (PUCHAR)FirmwareStart,
|
||
FirmwareBufferLength);
|
||
#endif // MORGAN
|
||
|
||
if (Status != ESUCCESS) {
|
||
JnFsDecodeBadStatus(Status);
|
||
VenPrint(FWUP_FAILED_UPDATE_MSG);
|
||
} else {
|
||
VenPrint(FWUP_SUCCESSFUL_UPDATE_MSG);
|
||
}
|
||
|
||
FwWaitForKeypress(FALSE);
|
||
return;
|
||
|
||
}
|
||
|
||
BOOLEAN
|
||
HackGetYesNo (
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This asks the user to type a Y or N for a debug clause located later
|
||
in this module. This is only needed while I am trying to understand the
|
||
FlashFile ROM update failures, and should be removed when the
|
||
problem is resolved.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the user hits the Y key.
|
||
FALSE otherwise.
|
||
|
||
--*/
|
||
{
|
||
CHAR Character;
|
||
ULONG Count;
|
||
|
||
VenPrint(FWUP_YORN_MSG);
|
||
|
||
while (ArcGetReadStatus(ARC_CONSOLE_INPUT) != ESUCCESS) {
|
||
}
|
||
|
||
ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
|
||
VenPrint1("%c\r\n", Character);
|
||
|
||
if ((Character == FWUP_LOWER_Y) || (Character == FWUP_UPPER_Y)) {
|
||
return TRUE;
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
#ifdef JENSEN
|
||
|
||
ARC_STATUS
|
||
JnFsStoreIntoROM(
|
||
IN PUCHAR FirmwareStart,
|
||
IN ULONG LowROMBlock,
|
||
IN ULONG HighROMBlock
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The firmware update has been read into memory and verified to
|
||
be correct, and the user has told us to go ahead with the update.
|
||
|
||
Operation:
|
||
|
||
- Clear the LowROMBlock so that if we are updating the VMS Console,
|
||
a reboot will bring up the FailSafe Booter.
|
||
|
||
- Update the ROM in reverse order, high block -> low block.
|
||
|
||
- Verify the ROM against the information in the update buffer.
|
||
|
||
- Tells the user to power-cycle the machine if everything is fine.
|
||
|
||
- Retries failing blocks, and when retry count is exceeded,
|
||
asks the user if we should try again.
|
||
|
||
|
||
Arguments:
|
||
|
||
FirmwareStart A pointer to the beginning of the ROM
|
||
binary information. This is byte 0 of
|
||
the low block.
|
||
|
||
LowROMBlock The number of the first ROM block to be
|
||
updated.
|
||
|
||
HighROMBlock The number of the last ROM block to be
|
||
updated.
|
||
|
||
HighROMBlock is guaranteed by the caller
|
||
to be >= LowROMBlock.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS if update was successful.
|
||
Otherwise, an error code.
|
||
|
||
--*/
|
||
{
|
||
ULONG Count;
|
||
UCHAR Character;
|
||
ARC_STATUS Status;
|
||
BOOLEAN BlockErased[MAXIMUM_NUMBER_ROM_BLOCKS];
|
||
BOOLEAN BlockStored[MAXIMUM_NUMBER_ROM_BLOCKS];
|
||
ULONG TempX;
|
||
ULONG TempY;
|
||
PUCHAR PromBlockAddress;
|
||
PUCHAR LocalPromAddress;
|
||
PCHAR BufferData;
|
||
PCHAR LocalBufferData;
|
||
ULONG RetryIndex;
|
||
ULONG BadCount = 0; // Needed while debugging --- remove later..
|
||
|
||
VenClearScreen();
|
||
|
||
//
|
||
// Verify the block arguments
|
||
//
|
||
|
||
if ((LowROMBlock > HighROMBlock) ||
|
||
(HighROMBlock > (MAXIMUM_NUMBER_ROM_BLOCKS-1))) {
|
||
return ENODEV;
|
||
}
|
||
|
||
//
|
||
// Initialize the ROM block status arrays to "not done".
|
||
//
|
||
|
||
for (TempX = LowROMBlock; TempX <= HighROMBlock; TempX++) {
|
||
BlockErased[TempX] = FALSE;
|
||
BlockStored[TempX] = FALSE;
|
||
}
|
||
//
|
||
// Determine the type of ROM in the machine.
|
||
//
|
||
|
||
if (FwROMDetermineMachineROMType() != ESUCCESS) {
|
||
VenPrint(FWUP_UNKNOWN_ROM_MSG);
|
||
return ENODEV;
|
||
}
|
||
|
||
VenPrint1(FWUP_ROM_TYPE_IS_MSG, MachineROMType);
|
||
|
||
//
|
||
// Erase the low block.
|
||
//
|
||
|
||
VenPrint(FWUP_CLEARING_LOW_PROM_BLOCK_MSG);
|
||
|
||
RetryIndex = 0;
|
||
|
||
do {
|
||
|
||
PromBlockAddress = (PUCHAR)(PROM_VIRTUAL_BASE +
|
||
(LowROMBlock * SIXTY_FOUR_KB));
|
||
|
||
if (!BlockErased[LowROMBlock]) {
|
||
if (FwROMErase64KB(PromBlockAddress) == ESUCCESS) {
|
||
BlockErased[LowROMBlock] = TRUE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now verify that the block has been cleared.
|
||
//
|
||
|
||
for (TempY = 0; TempY < SIXTY_FOUR_KB; TempY++) {
|
||
if (READ_PORT_UCHAR(PromBlockAddress++) != 0xff) {
|
||
BlockErased[LowROMBlock] = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// If the block has not been cleared after ROM_BLOCK_RETRY_COUNT
|
||
// attempts, ask the user if we should continue trying.
|
||
//
|
||
|
||
RetryIndex++;
|
||
|
||
if (!BlockErased[LowROMBlock] &&
|
||
((RetryIndex % ROM_BLOCK_RETRY_COUNT) == 0)) {
|
||
|
||
VenPrint2(FWUP_BLOCK_CANNOT_BE_ERASED_MSG,
|
||
LowROMBlock,
|
||
RetryIndex);
|
||
VenPrint(FWUP_KEEP_TRYING_MSG);
|
||
if (!JnFsProceedWithUpdate()) {
|
||
return EIO;
|
||
}
|
||
|
||
}
|
||
|
||
} while (!BlockErased[LowROMBlock]);
|
||
|
||
//
|
||
// Now we write the update into the PROM starting at the highest block.
|
||
// Reverse writing is used because the serial ROM transfers control to
|
||
// the VMS console if the checksum of the console is good *and* the
|
||
// first block is not all 1s. So, if this update includes the VMS console,
|
||
// we want to write the lowest block last. For other updates (e.g.,
|
||
// updates to the NT firmware only) it does not matter.
|
||
//
|
||
|
||
|
||
//
|
||
// For writes of at least two blocks, start at the high block and
|
||
// repeatedly try to update every block except the low block.
|
||
//
|
||
|
||
if (HighROMBlock > LowROMBlock) {
|
||
|
||
VenPrint(FWUP_CLEARING_AND_WRITING_HIGHER_BLOCKS_MSG);
|
||
|
||
RetryIndex = 0;
|
||
|
||
do {
|
||
|
||
//
|
||
// Start at the base of the highest block to be written
|
||
//
|
||
|
||
PromBlockAddress = (PUCHAR)(PROM_VIRTUAL_BASE +
|
||
(HighROMBlock * SIXTY_FOUR_KB));
|
||
BufferData = FirmwareStart + (HighROMBlock * SIXTY_FOUR_KB) -
|
||
(LowROMBlock * SIXTY_FOUR_KB);
|
||
|
||
|
||
|
||
//
|
||
// TempX > LowROMBlock is intentional, so low block is not updated.
|
||
//
|
||
|
||
for (TempX = HighROMBlock; TempX > LowROMBlock; --TempX) {
|
||
|
||
VenPrint(".");
|
||
|
||
|
||
//
|
||
// Have we cleared and written this block? If not, do so.
|
||
//
|
||
|
||
if (!BlockStored[TempX]) {
|
||
|
||
|
||
//
|
||
// First erase the block.
|
||
//
|
||
|
||
BlockErased[TempX] = FALSE;
|
||
if (FwROMErase64KB(PromBlockAddress) == ESUCCESS) {
|
||
BlockErased[TempX] = TRUE;
|
||
}
|
||
|
||
//
|
||
// Verify that the block has been erased properly.
|
||
//
|
||
|
||
LocalPromAddress = PromBlockAddress;
|
||
for (TempY = 0; TempY < SIXTY_FOUR_KB; TempY++) {
|
||
if (READ_PORT_UCHAR(LocalPromAddress++) != 0xff) {
|
||
BlockErased[TempX] = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Write the block if the erase succeeded.
|
||
//
|
||
|
||
if (BlockErased[TempX]) {
|
||
|
||
BlockStored[TempX] = TRUE;
|
||
LocalPromAddress = PromBlockAddress;
|
||
LocalBufferData = BufferData;
|
||
|
||
for (TempY = 0; TempY < SIXTY_FOUR_KB; TempY++) {
|
||
if (FwROMByteWrite(LocalPromAddress++, *LocalBufferData++)
|
||
!= ESUCCESS) {
|
||
BlockStored[TempX] = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (BlockStored[TempX]) {
|
||
|
||
//
|
||
// Verify that the writes have succeeded.
|
||
//
|
||
|
||
//
|
||
// First, set the device(s) to read-mode. To
|
||
// support devices with a block size smaller than
|
||
// 64KB, we issues set read-mode commands to every
|
||
// block within this virtual 64KB block. This is
|
||
// overkill, but it is easy and quick.
|
||
//
|
||
|
||
LocalPromAddress = PromBlockAddress;
|
||
for (TempY = 0;
|
||
TempY < (SIXTY_FOUR_KB / RomValues[MachineROMType].BytesPerBlock);
|
||
TempY++) {
|
||
FwROMSetReadMode(LocalPromAddress);
|
||
LocalPromAddress += RomValues[MachineROMType].BytesPerBlock;
|
||
}
|
||
|
||
LocalPromAddress = PromBlockAddress;
|
||
LocalBufferData = BufferData;
|
||
|
||
for (TempY = 0; TempY < SIXTY_FOUR_KB; TempY++) {
|
||
if (READ_PORT_UCHAR(LocalPromAddress++) !=
|
||
*LocalBufferData++) {
|
||
BlockStored[TempX] = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
} // if (BlockErased[TempX])
|
||
|
||
} // if...
|
||
|
||
// Decrement pointers to the next block
|
||
PromBlockAddress -= SIXTY_FOUR_KB;
|
||
BufferData -= SIXTY_FOUR_KB;
|
||
|
||
} // for...
|
||
|
||
|
||
//
|
||
// BlockErased[TempX] is TRUE iff the block was erased.
|
||
// BlockStored[TempX] is TRUE iff the block was erased and stored.
|
||
//
|
||
|
||
RetryIndex++;
|
||
|
||
if (AllBlocksNotDone(BlockStored, LowROMBlock+1, HighROMBlock) &&
|
||
((RetryIndex % ROM_BLOCK_RETRY_COUNT) == 0)) {
|
||
|
||
VenPrint1(FWUP_SOME_BLOCKS_CANNOT_BE_ERASED_MSG,
|
||
RetryIndex);
|
||
|
||
VenPrint(FWUP_ERASE_FAILURES_MSG);
|
||
|
||
//
|
||
// TempX = LowROMBlock+1 is intentional, to not check the
|
||
// lowest block.
|
||
//
|
||
|
||
for (TempX = LowROMBlock+1; TempX <= HighROMBlock; TempX++) {
|
||
if (!BlockErased[TempX]) {
|
||
VenPrint1("%d. ", TempX);
|
||
}
|
||
}
|
||
if (!AllBlocksNotDone(BlockErased, LowROMBlock+1, HighROMBlock)) {
|
||
VenPrint(FWUP_NONE_MSG);
|
||
}
|
||
|
||
|
||
VenPrint(FWUP_WRITE_FAILURES_MSG);
|
||
|
||
//
|
||
// TempX = LowROMBlock+1 is intentional, to not check the
|
||
// lowest block.
|
||
//
|
||
|
||
for (TempX = LowROMBlock+1; TempX <= HighROMBlock; TempX++) {
|
||
if (!BlockStored[TempX]) {
|
||
VenPrint1("%d. ", TempX);
|
||
}
|
||
}
|
||
if (!AllBlocksNotDone(BlockStored, LowROMBlock+1, HighROMBlock)) {
|
||
VenPrint(FWUP_INTERNAL_ERROR_MSG);
|
||
}
|
||
|
||
VenPrint(FWUP_DO_YOU_WISH_TO_KEEP_TRYING_MSG);
|
||
|
||
if (!JnFsProceedWithUpdate()) {
|
||
return EIO;
|
||
}
|
||
}
|
||
|
||
} while (AllBlocksNotDone(BlockStored, LowROMBlock+1, HighROMBlock));
|
||
}
|
||
|
||
//
|
||
// Now write the lowest/only block.
|
||
//
|
||
|
||
if (HighROMBlock == LowROMBlock) {
|
||
VenPrint(FWUP_WRITING_THE_BLOCK_MSG);
|
||
} else {
|
||
VenPrint(FWUP_WRITING_THE_LOW_BLOCK_MSG);
|
||
}
|
||
|
||
BlockStored[LowROMBlock] = FALSE;
|
||
RetryIndex = 0;
|
||
|
||
do {
|
||
|
||
PromBlockAddress = (PUCHAR)(PROM_VIRTUAL_BASE +
|
||
(LowROMBlock * SIXTY_FOUR_KB));
|
||
BufferData = FirmwareStart;
|
||
|
||
|
||
//
|
||
// First erase the block.
|
||
//
|
||
|
||
BlockErased[LowROMBlock] = FALSE;
|
||
|
||
if (FwROMErase64KB(PromBlockAddress) == ESUCCESS) {
|
||
BlockErased[LowROMBlock] = TRUE;
|
||
} else {
|
||
VenPrint(FWUP_BLOCK_CANNOT_BE_ERASED_AFTER_10_MSG);
|
||
}
|
||
|
||
|
||
//
|
||
// Verify that the block has been erased.
|
||
//
|
||
|
||
LocalPromAddress = PromBlockAddress;
|
||
|
||
for (TempY = 0; TempY < SIXTY_FOUR_KB; TempY++) {
|
||
if (READ_PORT_UCHAR(LocalPromAddress++) != 0xff) {
|
||
BlockErased[LowROMBlock] = FALSE;
|
||
VenPrint(FWUP_ERASURE_VERIFICATION_FAILED_MSG);
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Write the block if the erase succeeded.
|
||
//
|
||
|
||
if (BlockErased[LowROMBlock]) {
|
||
|
||
BlockStored[LowROMBlock] = TRUE;
|
||
|
||
LocalPromAddress = PromBlockAddress;
|
||
LocalBufferData = BufferData;
|
||
|
||
for (TempY = 0; TempY < SIXTY_FOUR_KB; TempY++) {
|
||
if (FwROMByteWrite(LocalPromAddress++, *LocalBufferData++) != ESUCCESS) {
|
||
BlockStored[LowROMBlock] = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
if (BlockStored[LowROMBlock]) {
|
||
|
||
//
|
||
// Verify that the writes have succeeded
|
||
//
|
||
|
||
//
|
||
// First, set the device(s) to read-mode. To
|
||
// support devices with a block size smaller than
|
||
// 64KB, we issues set read-mode commands to every
|
||
// block within this virtual 64KB block. This is
|
||
// overkill, but it is easy and quick.
|
||
//
|
||
|
||
LocalPromAddress = PromBlockAddress;
|
||
for (TempY = 0;
|
||
TempY < (SIXTY_FOUR_KB / RomValues[MachineROMType].BytesPerBlock);
|
||
TempY++) {
|
||
FwROMSetReadMode(LocalPromAddress);
|
||
LocalPromAddress += RomValues[MachineROMType].BytesPerBlock;
|
||
}
|
||
|
||
LocalPromAddress = PromBlockAddress;
|
||
LocalBufferData = BufferData;
|
||
|
||
|
||
for (TempY = 0; TempY < SIXTY_FOUR_KB; TempY++) {
|
||
|
||
if (READ_PORT_UCHAR(LocalPromAddress++) !=
|
||
*LocalBufferData++) {
|
||
|
||
#if 1
|
||
//
|
||
// This is temporary debugging assistance for
|
||
// the ROM update failures. The #if should be
|
||
// turned off once the problem has been
|
||
// understood and fixed.
|
||
//
|
||
|
||
PUCHAR TempPromAddress;
|
||
PCHAR TempBufferData;
|
||
|
||
TempPromAddress = LocalPromAddress - 1;
|
||
TempBufferData = LocalBufferData - 1;
|
||
|
||
VenPrint2(FWUP_BAD_DATA_MSG,
|
||
TempPromAddress,
|
||
READ_PORT_UCHAR(TempPromAddress)
|
||
);
|
||
VenPrint2(FWUP_BUFFER_MSG,
|
||
TempBufferData,
|
||
*TempBufferData);
|
||
BadCount++;
|
||
|
||
BlockStored[LowROMBlock] = FALSE;
|
||
|
||
if ((BadCount % 5) == 0) {
|
||
if (!HackGetYesNo()) {
|
||
break;
|
||
}
|
||
}
|
||
#else
|
||
BlockStored[LowROMBlock] = FALSE;
|
||
break;
|
||
#endif
|
||
|
||
} // if
|
||
|
||
} // for
|
||
|
||
} // if
|
||
|
||
} // if (BlockErased[LowROMBlock])
|
||
|
||
|
||
//
|
||
// BlockErased[LowROMBlock] is TRUE iff the block was erased.
|
||
// BlockStored[LowROMBlock] is TRUE iff the block was erased and stored.
|
||
//
|
||
|
||
VenPrint(".");
|
||
RetryIndex++;
|
||
|
||
if (!BlockStored[LowROMBlock] &&
|
||
((RetryIndex % ROM_BLOCK_RETRY_COUNT) == 0)) {
|
||
|
||
VenPrint1(FWUP_LOW_BLOCK_CANNOT_BE_ERASED_MSG, RetryIndex);
|
||
|
||
VenPrint(FWUP_ERASE_FAILURES_MSG);
|
||
|
||
if (!BlockErased[LowROMBlock]) {
|
||
VenPrint1("%d", LowROMBlock);
|
||
} else {
|
||
VenPrint(FWUP_NONE_MSG);
|
||
}
|
||
|
||
VenPrint(FWUP_WRITE_FAILURES_MSG);
|
||
if (!BlockStored[LowROMBlock]) {
|
||
VenPrint1("%d.", LowROMBlock);
|
||
} else {
|
||
VenPrint(FWUP_NONE_MSG);
|
||
}
|
||
|
||
VenPrint(FWUP_DO_YOU_WISH_TO_KEEP_TRYING_MSG);
|
||
|
||
if (!JnFsProceedWithUpdate()) {
|
||
return EIO;
|
||
}
|
||
}
|
||
|
||
} while (!BlockStored[LowROMBlock]);
|
||
|
||
|
||
//
|
||
// All done!!
|
||
//
|
||
|
||
return;
|
||
}
|
||
|
||
BOOLEAN
|
||
AllBlocksNotDone (
|
||
IN PBOOLEAN StatusArray,
|
||
IN ULONG StartIndex,
|
||
IN ULONG EndIndex
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns TRUE if any block has not been "done", where "done"
|
||
depends on what status array is passed in.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ULONG X;
|
||
|
||
for (X = StartIndex; X <= EndIndex; X++) {
|
||
if (StatusArray[X] == FALSE) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
#endif // ifdef JENSEN
|
||
|
||
#ifdef MORGAN
|
||
|
||
ARC_STATUS
|
||
MorganFsStoreIntoROM(
|
||
IN ULONG MorganFlashRomChipSelect,
|
||
IN PUCHAR FirmwareStart,
|
||
IN ULONG FirmwareBufferLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The firmware update has been read into memory and verified to
|
||
be correct, and the user has told us to go ahead with the update.
|
||
|
||
Operation:
|
||
|
||
Morgan strategy differs from Jensen in that the POST and fail-safe
|
||
loader code resides in a separate jumper-protected FLASH ROM, and
|
||
that the FLASH ROM containing the Morgan compressed firmware is a bulk
|
||
erase part with different erase and program methods than the Jensen
|
||
FLASH ROM parts.
|
||
|
||
Arguments:
|
||
|
||
FirmwareStart A pointer to the beginning of the ROM
|
||
binary information. This is byte 0 of
|
||
the Morgan firmware image.
|
||
|
||
MorganFlashRomChipSelect Selects which Morgan FLASH ROM the NT
|
||
will be firmware written into.
|
||
|
||
FirmwareBufferLength Length of the Morgan NT firmware image in
|
||
bytes.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS if update was successful.
|
||
Otherwise, an error code.
|
||
|
||
--*/
|
||
{
|
||
ARC_STATUS Status;
|
||
|
||
VenClearScreen();
|
||
|
||
//
|
||
// Verify the Morgan FLASH ROM chip select value
|
||
//
|
||
|
||
|
||
if ((MorganFlashRomChipSelect < 1) || (MorganFlashRomChipSelect > 2)) {
|
||
VenPrint1(FWUP_ROM_CHIP_SELECT_MSG, MorganFlashRomChipSelect);
|
||
FwWaitForKeypress();
|
||
return ENODEV;
|
||
}
|
||
|
||
if (MorganBlastFlash( MorganFlashRomChipSelect, FirmwareStart,
|
||
FirmwareBufferLength) == TRUE) {
|
||
VenPrint(FWUP_ROM_UPDATE_SUCCEEDED_MSG);
|
||
FwWaitForKeypress();
|
||
return ESUCCESS;
|
||
} else {
|
||
VenPrint(FWUP_ROM_UPDATE_FAILED_MSG);
|
||
FwWaitForKeypress();
|
||
return ENODEV;
|
||
}
|
||
|
||
} // MorganFsStoreIntoROM()
|
||
|
||
#endif // ifdef MORGAN
|
||
|
||
|
||
ARC_STATUS
|
||
ReadAndVerifyUpdateFile(
|
||
IN PCHAR PathName,
|
||
OUT PULONG BufferAddress,
|
||
OUT PULONG FirmwareStart,
|
||
OUT PULONG BufferLength,
|
||
OUT PULONG LowROMBlock,
|
||
OUT PULONG HighROMBlock
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This attempts to load and verify the firmware update file.
|
||
|
||
Arguments:
|
||
|
||
PathName A pointer to string descriptor for the name of
|
||
the file to load.
|
||
|
||
BufferAddress A pointer to a variable that receives the
|
||
address of the image base.
|
||
|
||
FirmwareStart A pointer to a variable that receives the address
|
||
of the start of the firmware. This is the first
|
||
byte after the null byte that terminates the
|
||
identifier string.
|
||
|
||
BufferLength A pointer to a variable that receives the length of
|
||
the image.
|
||
|
||
LowROMBlock A pointer to a variable that receives the low ROM
|
||
block to be updated.
|
||
|
||
HighROMBlock A pointer to a variable that receives the low ROM
|
||
block to be updated.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS is returned if the image file is loaded and verified.
|
||
|
||
Otherwise, an unsuccessful status is returned that describes the
|
||
reason for failure. Additionally, some detailed error messages
|
||
may be printed out by this function.
|
||
|
||
With any return, the file will have already been closed.
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONG ActualBase;
|
||
ULONG Count;
|
||
ULONG FileId;
|
||
ULONG Index;
|
||
ULONG PageCount;
|
||
ARC_STATUS Status;
|
||
LARGE_INTEGER SeekPosition;
|
||
FILE_INFORMATION FileInfo;
|
||
ULONG FileSize;
|
||
CHAR ChecksumAdjustment[4];
|
||
ULONG AccumulatedSum;
|
||
ULONG AmountOfBinaryData;
|
||
|
||
|
||
//
|
||
// Attempt to open the file.
|
||
//
|
||
|
||
Status = ArcOpen(PathName, ArcOpenReadOnly, &FileId);
|
||
if (Status != ESUCCESS) {
|
||
VenPrint(FWUP_READ_CANT_OPEN_MSG);
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Get the file information to figure out how big the file is.
|
||
//
|
||
|
||
Status = ArcGetFileInformation(FileId, &FileInfo);
|
||
|
||
if (Status != ESUCCESS) {
|
||
VenPrint(FWUP_READ_CANT_GET_FILE_INFO_MSG);
|
||
ArcClose(FileId);
|
||
return Status;
|
||
}
|
||
|
||
FileSize = FileInfo.EndingAddress.LowPart - FileInfo.StartingAddress.LowPart;
|
||
|
||
if ((FileSize < MINIMUM_UPDATE_FILE_SIZE) || (FileSize > MAXIMUM_UPDATE_FILE_SIZE)) {
|
||
VenPrint(FWUP_READ_BAD_SIZE_MSG);
|
||
ArcClose(FileId);
|
||
return EINVAL;
|
||
}
|
||
|
||
|
||
//
|
||
// Compute number of pages in the file and read it in.
|
||
//
|
||
|
||
PageCount = (FileSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||
|
||
Status = JnFsAllocateDescriptor(MemoryFree, PageCount, &ActualBase);
|
||
|
||
if (Status != ESUCCESS) {
|
||
VenPrint1(FWUP_READ_NOT_ENOUGH_MEMORY, PageCount);
|
||
ArcClose(FileId);
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Compute the byte address of the update file buffer
|
||
//
|
||
*BufferAddress = KSEG0_BASE | (ActualBase << PAGE_SHIFT);
|
||
VenPrint(FWUP_READ_READING_MSG);
|
||
Status = ArcRead(FileId, (PUCHAR)*BufferAddress, FileSize, &Count);
|
||
ArcClose(FileId);
|
||
|
||
if (Count != FileSize) {
|
||
VenPrint2(FWUP_READ_BAD_READ_COUNT_MSG, FileSize, Count);
|
||
if (Status != ESUCCESS) {
|
||
return Status;
|
||
} else {
|
||
return EIO;
|
||
}
|
||
}
|
||
if (Status != ESUCCESS) {
|
||
return Status;
|
||
}
|
||
|
||
|
||
//
|
||
// Verify the file's checksum.
|
||
//
|
||
|
||
VenPrint(FWUP_READ_VERIFYING_CHECKSUM_MSG);
|
||
AccumulatedSum = 0;
|
||
Index = 0;
|
||
do {
|
||
ChecksumAdjustment[0] = ChecksumAdjustment[1];
|
||
ChecksumAdjustment[1] = ChecksumAdjustment[2];
|
||
ChecksumAdjustment[2] = ChecksumAdjustment[3];
|
||
ChecksumAdjustment[3] = *(((PUCHAR)*BufferAddress)+Index);
|
||
AccumulatedSum += *(((PUCHAR)*BufferAddress)+Index);
|
||
Index++;
|
||
} while (Index < FileSize); // Filesize is 1-based, Index is 0-based
|
||
|
||
// The last four bytes were really a 32-bit additive-zero checksum,
|
||
// order of {low byte -- high byte }
|
||
AccumulatedSum = AccumulatedSum -
|
||
ChecksumAdjustment[3] -
|
||
ChecksumAdjustment[2] -
|
||
ChecksumAdjustment[1] -
|
||
ChecksumAdjustment[0];
|
||
AccumulatedSum = AccumulatedSum +
|
||
((ChecksumAdjustment[3] << 24) |
|
||
(ChecksumAdjustment[2] << 16) |
|
||
(ChecksumAdjustment[1] << 8) |
|
||
(ChecksumAdjustment[0]));
|
||
|
||
if (AccumulatedSum != 0) {
|
||
VenPrint1 (FWUP_READ_BAD_CHECKSUM_MSG, AccumulatedSum);
|
||
return ENOEXEC;
|
||
}
|
||
|
||
|
||
//
|
||
// The checksum is good. Find the start of the firmware data.
|
||
//
|
||
|
||
Index = 0;
|
||
while ((Index < MAXIMUM_IDENTIFIER_LENGTH) &&
|
||
(*(((PUCHAR)*BufferAddress)+Index) != 0)) {
|
||
Index++;
|
||
}
|
||
|
||
if (Index == MAXIMUM_IDENTIFIER_LENGTH) {
|
||
VenPrint(FWUP_READ_IDENTIFIER_TOO_LONG_MSG);
|
||
return ENOEXEC;
|
||
}
|
||
|
||
//
|
||
// Skip over the starting block byte
|
||
//
|
||
|
||
*FirmwareStart = (ULONG)(((PUCHAR)*BufferAddress) + Index + 2);
|
||
|
||
|
||
//
|
||
// Now verify legality of the starting block number, and verify that
|
||
// we have at least that much data in the binary section of the file.
|
||
//
|
||
|
||
*LowROMBlock = *(((PUCHAR)*BufferAddress) + Index + 1);
|
||
|
||
if (*LowROMBlock > 0xf) {
|
||
VenPrint1(FWUP_READ_BAD_START_BLOCK_MSG, *LowROMBlock);
|
||
return ENOEXEC;
|
||
}
|
||
|
||
AmountOfBinaryData = FileSize -
|
||
(ULONG)((PUCHAR)*FirmwareStart -
|
||
(PUCHAR)*BufferAddress) -
|
||
4;
|
||
|
||
*BufferLength = AmountOfBinaryData;
|
||
|
||
if ((AmountOfBinaryData % SIXTY_FOUR_KB) != 0) {
|
||
VenPrint(FWUP_READ_BAD_BINARY_DATA_MSG);
|
||
return EBADF;
|
||
}
|
||
|
||
*HighROMBlock = *LowROMBlock + (AmountOfBinaryData / SIXTY_FOUR_KB) - 1;
|
||
|
||
if ((*HighROMBlock < *LowROMBlock) || (*HighROMBlock > 0xf)) {
|
||
VenPrint2(FWUP_READ_TOO_MUCH_DATA_MSG, *LowROMBlock, *HighROMBlock);
|
||
return E2BIG;
|
||
}
|
||
|
||
|
||
return ESUCCESS;
|
||
}
|
||
|
||
ARC_STATUS
|
||
JnFsAllocateDescriptor(
|
||
IN ULONG MemoryType,
|
||
IN ULONG PageCount,
|
||
OUT PULONG ActualBase
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
This attempts to find a free section of memory of the requested size
|
||
and type. It does *not* update the memory descriptor list to reflect a
|
||
successful allocation.
|
||
|
||
Arguments:
|
||
|
||
MemoryType The type of memory requested.
|
||
|
||
PageCount The number of pages requested.
|
||
|
||
ActualBase A pointer to a variable that receives the base
|
||
page number of the found section.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS is returned if the memory descriptor is found.
|
||
ENOMEM if not.
|
||
--*/
|
||
|
||
{
|
||
|
||
PMEMORY_DESCRIPTOR MemoryDescriptor;
|
||
ULONG MemoryBase;
|
||
ARC_STATUS ReturnStatus = ENOMEM;
|
||
|
||
//
|
||
// Find a memory descriptor of the right size
|
||
//
|
||
|
||
MemoryDescriptor = ArcGetMemoryDescriptor(NULL);
|
||
|
||
while (MemoryDescriptor != NULL) {
|
||
if ((MemoryDescriptor->MemoryType == MemoryType) &&
|
||
(MemoryDescriptor->PageCount >= PageCount)) {
|
||
MemoryBase = MemoryDescriptor->BasePage;
|
||
ReturnStatus = ESUCCESS;
|
||
break;
|
||
}
|
||
MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor);
|
||
}
|
||
|
||
*ActualBase = MemoryBase;
|
||
|
||
return ReturnStatus;
|
||
}
|
||
|
||
BOOLEAN
|
||
JnFsProceedWithUpdate (
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function asks the user if she wants to proceed.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Returns TRUE if the user typed a Y on the keyboard.
|
||
|
||
FALSE if some other key is typed.
|
||
|
||
--*/
|
||
|
||
{
|
||
CHAR Character;
|
||
ULONG Count;
|
||
ARC_STATUS Status = EAGAIN;
|
||
|
||
VenPrint(FWUP_PRESS_Y_TO_CONTINUE_MSG);
|
||
|
||
while (Status != ESUCCESS) {
|
||
Status = ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
|
||
}
|
||
|
||
if ((Character == FWUP_LOWER_Y) || (Character == FWUP_UPPER_Y)) {
|
||
return TRUE;
|
||
} else {
|
||
VenPrint(FWUP_UPDATE_ABORTED_MSG);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
JnFsDecodeBadStatus (
|
||
IN ARC_STATUS Status
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This prints out error messages of type ARC_STATUS. ESUCCESS
|
||
codes cause nothing to be done.
|
||
|
||
Arguments:
|
||
|
||
Status The error code to be decoded.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
--*/
|
||
|
||
{
|
||
|
||
if (Status != ESUCCESS) {
|
||
|
||
if (Status <= EROFS) {
|
||
VenPrint(FWUP_ERROR_MSG[Status - 1]);
|
||
} else {
|
||
VenPrint1(FWUP_ERROR_CODE_MSG, Status);
|
||
}
|
||
|
||
VenPrint(FWUP_UPDATE_ABORTED_MSG);
|
||
}
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
FwpFindCDROM (
|
||
OUT PCHAR PathName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function finds the first CD-ROM in the machine, and returns
|
||
an ARC pathstring to it.
|
||
|
||
Arguments:
|
||
|
||
PathName A pointer to a buffer area that can receive
|
||
the CDROM pathname string.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS if the PathName was loaded.
|
||
|
||
Otherwise, an error code. On an error return, PathName is loaded
|
||
with "scsi(0)cdrom(4)fdisk(0)".
|
||
|
||
--*/
|
||
{
|
||
PCONFIGURATION_COMPONENT Controller;
|
||
BOOLEAN VariableFound = FALSE;
|
||
ULONG Index;
|
||
|
||
for ( Index = 0 ; Index < 8 ; Index++ ) {
|
||
sprintf(PathName, "scsi(0)cdrom(%d)fdisk(0)", Index);
|
||
Controller = ArcGetComponent(PathName);
|
||
if ((Controller != NULL) &&
|
||
(Controller->Type == FloppyDiskPeripheral)) {
|
||
VariableFound = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (VariableFound) {
|
||
return (ESUCCESS);
|
||
} else {
|
||
sprintf(PathName, "scsi0)cdrom(4)fdisk(0)");
|
||
return (EIO);
|
||
}
|
||
}
|