930 lines
20 KiB
C
930 lines
20 KiB
C
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
flash.c
|
|
|
|
Abstract:
|
|
|
|
This module implements function used to program kernel image to flash
|
|
ROM on EVT and DVT machine.
|
|
|
|
--*/
|
|
|
|
#include "dmp.h"
|
|
#include <pci.h>
|
|
|
|
#define ROM_VERSION_BYTE_OFFSET 0x78
|
|
|
|
typedef enum {
|
|
FlashUnknownDevice = 0,
|
|
FlashSST49LF040,
|
|
FlashGeneric29F080,
|
|
FlashGeneric29F040,
|
|
FlashGeneric29F020,
|
|
} FlashDeviceID;
|
|
|
|
typedef struct {
|
|
FlashDeviceID DeviceID;
|
|
WCHAR* DeviceCodes;
|
|
} FlashDeviceClass;
|
|
|
|
typedef enum {
|
|
FlashStatusReady,
|
|
FlashStatusBusy,
|
|
FlashStatusEraseSuspended,
|
|
FlashStatusTimeout,
|
|
FlashStatusError
|
|
} FlashStatus;
|
|
|
|
//
|
|
// Table of known flash devices list
|
|
//
|
|
|
|
FlashDeviceClass _FlashDeviceClass[] = {
|
|
{ FlashSST49LF040, L"\xBF53" },
|
|
{ FlashGeneric29F080, L"\x01D5\x04D5\xADD5" },
|
|
{ FlashGeneric29F040, L"\x1F13\x20E2\xC2A4\xADA4" },
|
|
{ FlashGeneric29F020, L"\x1F07\x1F08\x1F0B\x2034\x20B0\xC234\xC2B0\xDA8C" },
|
|
};
|
|
|
|
//
|
|
// Mapped virtual address of ROM region
|
|
//
|
|
|
|
PVOID KernelRomBase;
|
|
|
|
// SIZE_T
|
|
// FlashSize(
|
|
// IN FlashDeviceID ID
|
|
// )
|
|
// ++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro returns size of flash ROM specified by device identifier id
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ID - Device identifier returned by FlashDetectDevice
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Size of flash ROM for specified device
|
|
//
|
|
// --
|
|
|
|
#define FlashSize(ID) FlashSizeMap[(ID)]
|
|
|
|
SIZE_T FlashSizeMap[] = {
|
|
0,
|
|
512 * 1024, // SST 49LF040 Firmware Hub
|
|
1024 * 1024, // Generic 29F080
|
|
512 * 1024, // Generic 29F040
|
|
256 * 1024, // Generic 29F020
|
|
};
|
|
|
|
// ULONG_PTR
|
|
// FlashBaseAddress(
|
|
// IN FlashDeviceID ID
|
|
// )
|
|
// ++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro calculates the base address of flash ROM specified by ID,
|
|
// based on the size of the chip
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ID - Device identifier returned by FlashDetectDevice
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Base address of flash ROM from top 4GB
|
|
//
|
|
// --
|
|
|
|
#define FlashBaseAddress(ID) ((ULONG_PTR)(0xFFFFFFFF-FlashSize(ID)+1))
|
|
|
|
//
|
|
// Lowest possible base address of flash ROM and region size
|
|
//
|
|
|
|
#define FLASH_BASE_ADDRESS 0xFFF00000
|
|
#define FLASH_REGION_SIZE (0xFFFFFFFF-FLASH_BASE_ADDRESS-1)
|
|
|
|
// BYTE
|
|
// FlashReadByte(
|
|
// IN ULONG_PTR Physical
|
|
// )
|
|
// ++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro maps specified physical address of flash ROM into mapped
|
|
// virtual address and reads one byte from mapped address.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Physical - Physical address of flash ROM to be read
|
|
//
|
|
// Return Value:
|
|
//
|
|
// A read byte from specified address
|
|
//
|
|
// --
|
|
|
|
#define FlashReadByte(a) \
|
|
(*(PBYTE)((ULONG_PTR)KernelRomBase+(ULONG_PTR)(a)-FLASH_BASE_ADDRESS))
|
|
|
|
// VOID
|
|
// FlashWriteByte(
|
|
// IN ULONG_PTR Physical,
|
|
// IN BYTE Byte
|
|
// )
|
|
// ++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro maps specified physical address of flash ROM into mapped
|
|
// virtual address and writes one byte to mapped address.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Physical - Physical address of flash ROM to be read
|
|
//
|
|
// Byte - Data to be written to
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None
|
|
//
|
|
// --
|
|
|
|
#define FlashWriteByte(a, d) \
|
|
(*(PBYTE)((ULONG_PTR)KernelRomBase+(ULONG_PTR)(a)-FLASH_BASE_ADDRESS) = d)
|
|
|
|
// WORD
|
|
// FlashReadWord(
|
|
// IN ULONG_PTR Physical
|
|
// )
|
|
// ++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro maps specified physical address of flash ROM into mapped
|
|
// virtual address and reads two bytes from mapped address.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Physical - Physical address of flash ROM to be read
|
|
//
|
|
// Return Value:
|
|
//
|
|
// Two byte from specified address
|
|
//
|
|
// --
|
|
|
|
#define FlashReadWord(a) \
|
|
(*(PWORD)((ULONG_PTR)KernelRomBase+(ULONG_PTR)(a)-FLASH_BASE_ADDRESS))
|
|
|
|
// VOID
|
|
// FlashWriteWord(
|
|
// IN ULONG_PTR Physical,
|
|
// IN WORD Word
|
|
// )
|
|
// ++
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This macro maps specified physical address of flash ROM into mapped
|
|
// virtual address and writes two bytes to mapped address.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Physical - Physical address of flash ROM to be read
|
|
//
|
|
// Word - Data to be written to
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None
|
|
//
|
|
// --
|
|
|
|
#define FlashWriteWord(a, d) \
|
|
(*(PWORD)((ULONG_PTR)KernelRomBase+(ULONG_PTR)(a)-FLASH_BASE_ADDRESS) = d)
|
|
|
|
FlashStatus
|
|
FlashGetStatus(
|
|
IN FlashDeviceID ID,
|
|
IN ULONG_PTR Address OPTIONAL,
|
|
IN BYTE Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks status of flash chip using data# polling method.
|
|
The data# polling bit, DQ7, indicates whether the Embeded Algorithm
|
|
is in progress or completed.
|
|
|
|
Arguments:
|
|
|
|
ID - Device identifier returned by FlashDetectDevice
|
|
|
|
Address - Physical address of flash ROM to be checked
|
|
|
|
Data - Expected data at specified address
|
|
|
|
Return Value:
|
|
|
|
Status of flash chip, see the definition of FlashStatus above.
|
|
|
|
--*/
|
|
{
|
|
UCHAR retry=1, d, t;
|
|
|
|
if (!ARGUMENT_PRESENT(Address)) {
|
|
Address = FlashBaseAddress(ID);
|
|
}
|
|
|
|
if (ID == FlashSST49LF040) {
|
|
|
|
//
|
|
// SST doesn't support Exceeded Timing Limits, DQ5
|
|
//
|
|
|
|
d = FlashReadByte(Address) & 0x80;
|
|
t = Data & 0x80;
|
|
|
|
if (t == d) {
|
|
return FlashStatusReady;
|
|
} else {
|
|
return FlashStatusBusy;
|
|
}
|
|
|
|
} else {
|
|
|
|
again:
|
|
d = FlashReadByte(Address) & 0x80;
|
|
t = Data & 0x80;
|
|
|
|
if (t == d) {
|
|
return FlashStatusReady; // data matches
|
|
} else if (d & 0x20) { // Timeout?
|
|
d = FlashReadByte(Address) & 0x80;
|
|
if (t == d) {
|
|
return FlashStatusReady; // data matches
|
|
}
|
|
if (retry--) {
|
|
goto again; // may have been write completion
|
|
}
|
|
return FlashStatusTimeout;
|
|
}
|
|
|
|
if (retry--) {
|
|
goto again; // may have been write completion
|
|
} else {
|
|
return FlashStatusError;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FlashResetDevice(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine resets flash ROM back to read mode if device is in ID command
|
|
mode or during a program or erase operation
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
FlashWriteByte(0xFFFF5555, 0xAA);
|
|
FlashWriteByte(0xFFFF2AAA, 0x55);
|
|
FlashWriteByte(0xFFFF5555, 0xF0);
|
|
KeStallExecutionProcessor(150000);
|
|
}
|
|
|
|
FlashDeviceID
|
|
FlashDetectDevice(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine detects the device and manufacturer id of flash device on
|
|
the system. The device on Xbus will be detected first and if no device
|
|
detected, LPC bus will be next.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Type of flash id installed in the system or FlashUnknownDevice
|
|
|
|
--*/
|
|
{
|
|
BYTE byte;
|
|
BYTE id1=0, id2=0;
|
|
WORD DeviceID;
|
|
BOOL FirstTime = TRUE;
|
|
PCI_SLOT_NUMBER PCISlotNumber;
|
|
PCI_COMMON_CONFIG Configuration;
|
|
SIZE_T loop;
|
|
|
|
detect:
|
|
|
|
FlashWriteByte(0xFFFF5555, 0xAA);
|
|
FlashWriteByte(0xFFFF2AAA, 0x55);
|
|
FlashWriteByte(0xFFFF5555, 0x90);
|
|
|
|
KeStallExecutionProcessor(1);
|
|
|
|
id1 = FlashReadByte(0xFFFF0000);
|
|
id2 = FlashReadByte(0xFFFF0001);
|
|
DeviceID = id1 << 8 | id2;
|
|
|
|
FlashResetDevice();
|
|
|
|
for (loop=0; loop<sizeof(_FlashDeviceClass)/sizeof(_FlashDeviceClass[0]); loop++) {
|
|
if (wcschr(_FlashDeviceClass[loop].DeviceCodes, DeviceID)) {
|
|
return _FlashDeviceClass[loop].DeviceID;
|
|
}
|
|
}
|
|
|
|
if (FirstTime == TRUE) {
|
|
|
|
//
|
|
// We are here because we couldn't find any flash ROM on Xbus.
|
|
// Next thing is to see if this is a EVT board and enable ROM
|
|
// write bus cycle to LPC interface. By default the write cycle
|
|
// to ROM will drop.
|
|
//
|
|
|
|
FirstTime = FALSE;
|
|
|
|
//
|
|
// Looking for PCI-to-LPC bridge
|
|
//
|
|
|
|
for (byte=0x00; byte<=0xff; byte++) {
|
|
PCISlotNumber.u.AsULONG = byte;
|
|
HalReadPCISpace(0, PCISlotNumber.u.AsULONG, 0, &Configuration, sizeof(Configuration));
|
|
if (Configuration.BaseClass == 6 && Configuration.SubClass == 1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it is Nvidia PCI-to-LPC bridge, enable LPC ROM write
|
|
//
|
|
|
|
if (Configuration.VendorID == 0x10DE && Configuration.DeviceID == 0x01B2) {
|
|
byte = 0x01;
|
|
HalWritePCISpace(0, PCISlotNumber.u.AsULONG, 0x45, &byte, sizeof(byte));
|
|
goto detect;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// If we still couldn't find any flash ROM on LPC bus, disable LPC
|
|
// ROM write
|
|
//
|
|
|
|
byte = 0x00;
|
|
HalWritePCISpace(0, PCISlotNumber.u.AsULONG, 0x45, &byte, sizeof(byte));
|
|
}
|
|
|
|
return FlashUnknownDevice;
|
|
}
|
|
|
|
BOOL
|
|
FlashEraseChip(
|
|
FlashDeviceID ID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine erase the content of entire flash ROM to 0xFF.
|
|
|
|
Arguments:
|
|
|
|
ID - Device identifier returned by FlashDetectDevice
|
|
|
|
Return Value:
|
|
|
|
TRUE if operation success, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
ULONG_PTR FlashPtr;
|
|
BOOL fBlank = FALSE;
|
|
SIZE_T Count, Retries=5;
|
|
|
|
while (Retries--) {
|
|
|
|
FlashWriteByte(0xFFFF5555, 0xAA);
|
|
FlashWriteByte(0xFFFF2AAA, 0x55);
|
|
FlashWriteByte(0xFFFF5555, 0x80);
|
|
FlashWriteByte(0xFFFF5555, 0xAA);
|
|
FlashWriteByte(0xFFFF2AAA, 0x55);
|
|
FlashWriteByte(0xFFFF5555, 0x10);
|
|
|
|
FlashPtr = ~0L;
|
|
|
|
//
|
|
// Wait until flash chip is ready and completely erased.
|
|
//
|
|
|
|
Count = 0x100000;
|
|
while (FlashGetStatus(ID, FlashPtr, 0xFF) != FlashStatusReady && Count) {
|
|
Count--;
|
|
}
|
|
|
|
//
|
|
// For some reasons in the FIB DVT, even the flash status is
|
|
// ready but the actual data is not written to the chip.
|
|
// We just have to poll the actual data and spin for a while
|
|
// if it didn't get through.
|
|
//
|
|
|
|
Count = 0x100000;
|
|
while (FlashReadByte(FlashPtr) != 0xFF && Count) {
|
|
KeStallExecutionProcessor(150000);
|
|
Count--;
|
|
}
|
|
|
|
//
|
|
// Perform a blank check by compare all the content with 0xFF
|
|
//
|
|
|
|
Count = FlashSize(ID);
|
|
FlashResetDevice();
|
|
FlashPtr = FlashBaseAddress(ID);
|
|
|
|
ASSERTMSG("Size of flash ROM must be power of two", (Count & (Count-1)) == 0);
|
|
|
|
while (Count) {
|
|
if (FlashReadWord(FlashPtr) != 0xFFFF) {
|
|
DbgPrint("FLASH: blank check failed (retries=%d)\n", Retries);
|
|
break;
|
|
}
|
|
|
|
Count -= sizeof(WORD);
|
|
FlashPtr += sizeof(WORD);
|
|
}
|
|
|
|
if (Count == 0) {
|
|
fBlank = TRUE;
|
|
break;
|
|
}
|
|
|
|
FlashResetDevice();
|
|
}
|
|
|
|
return fBlank;
|
|
}
|
|
|
|
BOOL
|
|
FlashProgramImage(
|
|
IN FlashDeviceID ID,
|
|
IN PVOID ImageBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine programs the content of flash ROM with new image. The flash
|
|
ROM has to be blank first before programming.
|
|
|
|
Arguments:
|
|
|
|
ID - Device identifier returned by FlashDetectDevice
|
|
|
|
ImageBuffer - Buffer contains the content to be programmed
|
|
|
|
Return Value:
|
|
|
|
TRUE if operation success, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
BYTE b;
|
|
PBYTE pb;
|
|
PWORD pw;
|
|
ULONG TimeOut;
|
|
ULONG_PTR FlashPtr;
|
|
BYTE TrueData, CurrData;
|
|
BOOL Loop, fSuccess = FALSE;
|
|
SIZE_T Count, Retries = 5;
|
|
SIZE_T Again;
|
|
|
|
while (Retries--) {
|
|
|
|
Count = FlashSize(ID);
|
|
pb = (PBYTE)ImageBuffer;
|
|
FlashPtr = FlashBaseAddress(ID);
|
|
|
|
while (Count--) {
|
|
|
|
b = *pb++;
|
|
|
|
if (b != 0xFF) {
|
|
FlashWriteByte(0xFFFF5555, 0xAA);
|
|
FlashWriteByte(0xFFFF2AAA, 0x55);
|
|
FlashWriteByte(0xFFFF5555, 0xA0);
|
|
FlashWriteByte(FlashPtr, b);
|
|
|
|
//
|
|
// Wait until flash chip is ready for next command
|
|
//
|
|
|
|
Again = 0x100000;
|
|
while (FlashGetStatus(ID, FlashPtr, b) != FlashStatusReady && Again) {
|
|
Again--;
|
|
}
|
|
|
|
//
|
|
// For some reasons in the FIB DVT, even the flash status is
|
|
// ready but the actual data is not written to the chip.
|
|
// We just have to poll the actual data and spin for a while
|
|
// if it didn't get through.
|
|
//
|
|
|
|
Again = 0x100000;
|
|
while (FlashReadByte(FlashPtr) != b && Again) {
|
|
Again--;
|
|
}
|
|
}
|
|
|
|
FlashPtr++;
|
|
}
|
|
|
|
//
|
|
// Verify the content that just has been programmed
|
|
//
|
|
|
|
Count = FlashSize(ID);
|
|
pw = (PWORD)ImageBuffer;
|
|
FlashPtr = FlashBaseAddress(ID);
|
|
FlashResetDevice();
|
|
|
|
while (Count) {
|
|
if (FlashReadWord(FlashPtr) != *pw++) {
|
|
DbgPrint("FLASH: verification failed (retries=%d)\n", Retries);
|
|
break;
|
|
}
|
|
|
|
Count -= sizeof(WORD);
|
|
FlashPtr += sizeof(WORD);
|
|
}
|
|
|
|
if (Count == 0) {
|
|
fSuccess = TRUE;
|
|
break;
|
|
}
|
|
|
|
FlashResetDevice();
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
UINT64
|
|
FASTCALL
|
|
FlashReadMSR(
|
|
IN ULONG Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads Pentium III Model-Specific Register (MSR) specified
|
|
by Address
|
|
|
|
Arguments:
|
|
|
|
Address - Register address to read
|
|
|
|
Return Value:
|
|
|
|
64-bit value of specified MSR
|
|
|
|
--*/
|
|
{
|
|
__asm {
|
|
rdmsr
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FASTCALL
|
|
FlashWriteMSR(
|
|
IN ULONG Address,
|
|
IN UINT64 Value
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine writes Pentium III Model-Specific Register (MSR) specified
|
|
by Address
|
|
|
|
Arguments:
|
|
|
|
Address - Register address to read
|
|
|
|
Value - 64-bit value to be written
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
__asm {
|
|
mov eax, DWORD PTR [Value]
|
|
mov edx, DWORD PTR [Value+4]
|
|
wrmsr
|
|
}
|
|
}
|
|
|
|
#ifdef FLASH_TIME
|
|
|
|
UINT64
|
|
FlashReadTSC(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads processor's time-stamp counter. The time-stamp counter
|
|
is contained in a 64-bit MSR. The high-order of 32 bits MSR are loaded
|
|
into the EDX register, and the low-order 32 bits are loaded into the EAX
|
|
register. The processor increments the time-stamp counter MSR every
|
|
clock cycle and resets it to 0 whenever the processor reset.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
64-bit MSR of time-stamp counter
|
|
|
|
--*/
|
|
{
|
|
__asm {
|
|
rdtsc
|
|
}
|
|
}
|
|
|
|
#endif // FLASH_TIME
|
|
|
|
VOID
|
|
FlashChangeRomCaching(
|
|
BOOL EnableCache
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine searches for ROM cache setting in MTRR and disable it. It is
|
|
necessary to disable and flash cache before changing MTRR. The following
|
|
steps are recommended by Intel in order to change MTRR settings. Save CR4,
|
|
disable and flush processor cache, flush TLB, disable MTRR, change MTRR
|
|
settings, flush cache and TLB, enable MTRR and restore CR4
|
|
|
|
Arguments:
|
|
|
|
EnableCache - TRUE to enable caching, FALSE to disable
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ULONG MTRR;
|
|
UINT64 v, MTRRdeftype;
|
|
ULONG Base, Type;
|
|
|
|
|
|
__asm {
|
|
push ecx
|
|
push edx
|
|
|
|
_emit 0fh ; mov eax, cr4
|
|
_emit 20h
|
|
_emit 0e0h
|
|
|
|
push eax ; save content of cr4
|
|
|
|
mov eax, cr0 ; disable and flush cache
|
|
push eax ; save content of cr0
|
|
or eax, 060000000H
|
|
mov cr0, eax
|
|
wbinvd
|
|
|
|
mov eax, cr3 ; flush TLB
|
|
mov cr3, eax
|
|
}
|
|
|
|
//
|
|
// Save the content of MTRR deftype and disable MTRR
|
|
//
|
|
|
|
MTRRdeftype = FlashReadMSR(0x2FF);
|
|
FlashWriteMSR(0x2FF, 0);
|
|
|
|
for (MTRR=0x200; MTRR<0x20F; MTRR+=2) {
|
|
v = FlashReadMSR(MTRR);
|
|
Base = (ULONG)((v >> 12) & 0xFFFFFF);
|
|
Type = (BYTE)v;
|
|
|
|
//
|
|
// Set or reset valid bit according to cache enable flag
|
|
//
|
|
|
|
if (Base >= (FLASH_BASE_ADDRESS >> 12) && Type != 0) {
|
|
v = FlashReadMSR(MTRR+1);
|
|
v = EnableCache ? (v | 0x800) : (v & (~0x800));
|
|
FlashWriteMSR(MTRR+1, v);
|
|
}
|
|
}
|
|
|
|
__asm {
|
|
wbinvd ; flush cache
|
|
mov eax, cr3 ; flush TLB
|
|
mov cr3, eax
|
|
}
|
|
|
|
//
|
|
// Restore content of MTRR deftype, MTRR should be re-enabled
|
|
//
|
|
|
|
FlashWriteMSR(0x2FF, MTRRdeftype);
|
|
|
|
__asm {
|
|
pop eax ; restore cr0
|
|
mov cr0, eax
|
|
|
|
pop eax ; restore cr4
|
|
|
|
_emit 0fh ; mov cr4, eax
|
|
_emit 22h
|
|
_emit 0e0h
|
|
|
|
pop edx
|
|
pop ecx
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
FlashKernelImage(
|
|
IN PVOID ImageBuffer,
|
|
IN SIZE_T ImageSize,
|
|
OUT LPSTR szResp,
|
|
IN DWORD cchResp,
|
|
IN BOOL IgnoreVersionChecking
|
|
)
|
|
{
|
|
#ifdef FLASH_TIME
|
|
UINT64 ClockTick;
|
|
#endif
|
|
|
|
FlashDeviceID ID;
|
|
HRESULT hr = XBDM_NOERR;
|
|
BYTE RomVersion, ImageVersion;
|
|
|
|
#ifdef FLASH_TIME
|
|
ClockTick = FlashReadTSC();
|
|
#endif
|
|
|
|
if (IsBadReadPtr(ImageBuffer, ImageSize) || \
|
|
IsBadWritePtr(szResp, cchResp)) {
|
|
return HRESULT_FROM_WIN32(ERROR_NOACCESS);
|
|
}
|
|
|
|
//
|
|
// Map top 1MB of physical memory of ROM region (FFF00000-FFFFFFFF)
|
|
//
|
|
|
|
KernelRomBase = MmMapIoSpace(FLASH_BASE_ADDRESS, FLASH_REGION_SIZE,
|
|
PAGE_READWRITE | PAGE_NOCACHE);
|
|
|
|
if (!KernelRomBase) {
|
|
_snprintf(szResp, cchResp, "unable to map i/o space");
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Before disable all interrupts, sleep 300 msec so that the TCP/IP stack
|
|
// get a chance a respond ACK to the other end
|
|
//
|
|
|
|
Sleep(300);
|
|
|
|
__asm cli
|
|
|
|
DbgPrint("FLASH: interrupts are now disabled\n");
|
|
|
|
//
|
|
// Disable ROM caching
|
|
//
|
|
|
|
FlashChangeRomCaching(FALSE);
|
|
|
|
ID = FlashDetectDevice();
|
|
|
|
if (ID == FlashUnknownDevice) {
|
|
_snprintf(szResp, cchResp, "Unknown flash device id");
|
|
hr = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (FlashSize(ID) != ImageSize) {
|
|
_snprintf(szResp, cchResp, "Invalid image size");
|
|
hr = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
RomVersion = FlashReadByte(FLASH_BASE_ADDRESS + ROM_VERSION_BYTE_OFFSET);
|
|
ImageVersion = ((PBYTE)ImageBuffer)[ROM_VERSION_BYTE_OFFSET];
|
|
|
|
if (!IgnoreVersionChecking && RomVersion != ImageVersion) {
|
|
_snprintf(szResp, cchResp, "Mismatch ROM version (rom=%x, image=%x)",
|
|
RomVersion, ImageVersion);
|
|
hr = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
DbgPrint("FLASH: erasing and blank checking...\n");
|
|
|
|
if ( !FlashEraseChip(ID) ) {
|
|
_snprintf(szResp, cchResp, "Failed to erase flash chip");
|
|
hr = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
DbgPrint("FLASH: programming...\n");
|
|
|
|
if (!FlashProgramImage(ID, ImageBuffer)) {
|
|
_snprintf(szResp, cchResp, "Failed to program kernel image (verify failed)");
|
|
hr = E_FAIL;
|
|
goto cleanup;
|
|
}
|
|
|
|
DbgPrint("FLASH: done...\n");
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
_snprintf(szResp, cchResp, "Done, new image flashed");
|
|
}
|
|
|
|
hr = XBDM_NOERR;
|
|
|
|
cleanup:
|
|
|
|
__asm sti
|
|
|
|
DbgPrint("FLASH: interrupts are now enabled\n");
|
|
|
|
MmUnmapIoSpace(KernelRomBase, FLASH_REGION_SIZE);
|
|
|
|
//
|
|
// Re-enable ROM caching as needed
|
|
//
|
|
|
|
FlashChangeRomCaching(TRUE);
|
|
|
|
#ifdef FLASH_TIME
|
|
ClockTick = FlashReadTSC() - ClockTick;
|
|
DbgPrint("FLASH: elapsed time %I64u seconds\n", ClockTick / 733000000UI64);
|
|
#endif
|
|
|
|
return hr;
|
|
}
|
|
|