910 lines
20 KiB
C++
910 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 "recovpch.h"
|
||
|
#include <pci.h>
|
||
|
|
||
|
|
||
|
//
|
||
|
// Manufacturer and chip identifiers
|
||
|
//
|
||
|
|
||
|
#define SST_ID 0xBF
|
||
|
#define SST_49LF040 0x53
|
||
|
|
||
|
#define AMD_ID 0x01
|
||
|
#define FUJITSU_ID 0x04
|
||
|
#define HYUNDAI_ID 0xAD
|
||
|
#define GENERIC_29F080 0xD5
|
||
|
|
||
|
#define ST_ID 0x20
|
||
|
#define M29F080A 0xF1
|
||
|
|
||
|
typedef enum {
|
||
|
FlashUnknownDevice = 0,
|
||
|
FlashSST49LF040,
|
||
|
FlashGeneric29F080
|
||
|
} FlashDeviceID;
|
||
|
|
||
|
typedef enum {
|
||
|
FlashStatusReady,
|
||
|
FlashStatusBusy,
|
||
|
FlashStatusEraseSuspended,
|
||
|
FlashStatusTimeout,
|
||
|
FlashStatusError
|
||
|
} FlashStatus;
|
||
|
|
||
|
//
|
||
|
// 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
|
||
|
};
|
||
|
|
||
|
// 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;
|
||
|
BOOL FirstTime = TRUE;
|
||
|
PCI_SLOT_NUMBER PCISlotNumber;
|
||
|
PCI_COMMON_CONFIG Configuration;
|
||
|
|
||
|
detect:
|
||
|
|
||
|
FlashWriteByte( 0xFFFF5555, 0xAA );
|
||
|
FlashWriteByte( 0xFFFF2AAA, 0x55 );
|
||
|
FlashWriteByte( 0xFFFF5555, 0x90 );
|
||
|
|
||
|
KeStallExecutionProcessor( 1 );
|
||
|
|
||
|
id1 = FlashReadByte( 0xFFFF0000 );
|
||
|
id2 = FlashReadByte( 0xFFFF0001 );
|
||
|
|
||
|
FlashResetDevice();
|
||
|
|
||
|
if ( id1 == SST_ID && id2 == SST_49LF040 ) {
|
||
|
return FlashSST49LF040;
|
||
|
}
|
||
|
|
||
|
if ( (id1 == AMD_ID || id1 == HYUNDAI_ID || id1 == FUJITSU_ID) && \
|
||
|
id2 == GENERIC_29F080 ) {
|
||
|
return FlashGeneric29F080;
|
||
|
}
|
||
|
|
||
|
if ( id1 == ST_ID && id2 == M29F080A ) {
|
||
|
return FlashGeneric29F080;
|
||
|
}
|
||
|
|
||
|
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
|
||
|
)
|
||
|
{
|
||
|
#ifdef FLASH_TIME
|
||
|
UINT64 ClockTick;
|
||
|
#endif
|
||
|
|
||
|
FlashDeviceID ID;
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
#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;
|
||
|
}
|
||
|
|
||
|
__asm cli
|
||
|
|
||
|
XDBGWRN("RECOVERY", "FLASH: interrupts are now disabled" );
|
||
|
|
||
|
//
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
XDBGWRN("RECOVERY", "FLASH: erasing and blank checking..." );
|
||
|
|
||
|
if ( !FlashEraseChip(ID) ) {
|
||
|
_snprintf( szResp, cchResp, "Failed to erase flash chip" );
|
||
|
hr = E_FAIL;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
XDBGWRN("RECOVERY", "FLASH: programming..." );
|
||
|
|
||
|
if ( !FlashProgramImage(ID, ImageBuffer) ) {
|
||
|
_snprintf( szResp, cchResp, "Failed to program kernel image (verify failed)" );
|
||
|
hr = E_FAIL;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
XDBGWRN("RECOVERY", "FLASH: done" );
|
||
|
|
||
|
if ( SUCCEEDED(hr) ) {
|
||
|
_snprintf( szResp, cchResp, "Done, new image flashed" );
|
||
|
}
|
||
|
|
||
|
hr = S_OK;
|
||
|
|
||
|
cleanup:
|
||
|
|
||
|
__asm sti
|
||
|
|
||
|
XDBGWRN("RECOVERY", "FLASH: interrupts are now enabled" );
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
|