1011 lines
25 KiB
C
1011 lines
25 KiB
C
/*++
|
||
|
||
Copyright (c) 1990, 1991 Microsoft Corporation
|
||
|
||
|
||
Module Name:
|
||
|
||
hwheap.c
|
||
|
||
Abstract:
|
||
|
||
This module goes through ROM area and tries to pick up all the ROM
|
||
blocks.
|
||
|
||
Author:
|
||
|
||
Shie-Lin Tzong (shielint) 21-Jan-92
|
||
|
||
|
||
Environment:
|
||
|
||
Real mode.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "hwdetect.h"
|
||
#include "hwvbios.h"
|
||
#if defined(_GAMBIT_)
|
||
#include "ssc.h"
|
||
#endif
|
||
|
||
#if !defined(_GAMBIT_)
|
||
FPTEMPORARY_ROM_BLOCK BlockHead;
|
||
FPTEMPORARY_ROM_BLOCK BlockPointer;
|
||
|
||
BOOLEAN
|
||
AddRomBlock (
|
||
ULONG RomAddress,
|
||
ULONG RomSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine adds a ROM/RAM block to our ROM list.
|
||
|
||
Arguments:
|
||
|
||
RomAddress - the starting address of the ROM/RAM block to be added.
|
||
|
||
RomSize - the size of the ROM/RAM block (in byte).
|
||
|
||
Return Value:
|
||
|
||
A value of TRUE is returned if success. Otherwise, a value of
|
||
FALSE is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG AddSize;
|
||
ULONG AddAddress;
|
||
FPTEMPORARY_ROM_BLOCK pCurrentBlock, pNextBlock;
|
||
ULONG CurrentBlock, NextBlock, AddBlock;
|
||
ULONG EndAddBlock, EndCurrentBlock, EndNextBlock;
|
||
BOOLEAN fOverlap=FALSE;
|
||
|
||
pCurrentBlock = NULL;
|
||
pNextBlock = NULL;
|
||
AddSize = RomSize;
|
||
AddAddress = RomAddress;
|
||
AddBlock = RomAddress;
|
||
|
||
//
|
||
// If there are other blocks, make sure there is no overlap with them
|
||
//
|
||
|
||
if (BlockHead) {
|
||
|
||
pCurrentBlock = BlockHead;
|
||
pNextBlock = pCurrentBlock->Next;
|
||
CurrentBlock = pCurrentBlock->RomBlock.Address;
|
||
EndCurrentBlock = CurrentBlock + pCurrentBlock->RomBlock.Size;
|
||
EndAddBlock = RomAddress + RomSize;
|
||
|
||
while (pCurrentBlock!=NULL) {
|
||
|
||
//
|
||
// calculate location of next block (if it's there)
|
||
//
|
||
|
||
if(pNextBlock) {
|
||
NextBlock = pNextBlock->RomBlock.Address;
|
||
EndNextBlock = NextBlock + pNextBlock->RomBlock.Size;
|
||
}
|
||
|
||
//
|
||
// if overlapping with current block, then stop and
|
||
// resolve overlap
|
||
//
|
||
|
||
if((RomAddress < EndCurrentBlock)&& (RomAddress >= CurrentBlock)){
|
||
fOverlap = TRUE;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// if add block is lower than the current one,
|
||
// or there is not a next block, then no need to search further
|
||
//
|
||
|
||
if((EndAddBlock <= CurrentBlock) || (pNextBlock == NULL)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// if block is lower than next one, but greater than current
|
||
// one, we have found the right area
|
||
//
|
||
|
||
if ((EndAddBlock <= NextBlock) && (AddBlock >= EndCurrentBlock)) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// if conflicting with next block, stop searching and
|
||
// resolve conflict after this loop
|
||
//
|
||
|
||
if((EndAddBlock > NextBlock) && (EndAddBlock <= EndNextBlock)) {
|
||
fOverlap = TRUE;
|
||
break;
|
||
}
|
||
|
||
pCurrentBlock = pNextBlock;
|
||
pNextBlock = pCurrentBlock->Next;
|
||
CurrentBlock = NextBlock;
|
||
EndCurrentBlock = EndNextBlock;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if we have reached this point, there may be a conflict
|
||
// with the current block.
|
||
//
|
||
|
||
if(fOverlap) {
|
||
if(AddBlock < EndCurrentBlock) {
|
||
AddAddress = EndCurrentBlock;
|
||
AddSize = EndAddBlock - EndCurrentBlock;
|
||
if(AddSize <= 0) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
if((pNextBlock != NULL) && (EndAddBlock > NextBlock)) {
|
||
AddSize = NextBlock - AddBlock;
|
||
if(AddSize <= 0) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
BlockPointer->RomBlock.Address = AddAddress;
|
||
BlockPointer->RomBlock.Size = AddSize;
|
||
|
||
//
|
||
// Put it on the list.
|
||
// if it belongs on top, put it there
|
||
//
|
||
|
||
if ((pCurrentBlock == NULL)||
|
||
((pCurrentBlock == BlockHead) && (CurrentBlock > AddBlock))) {
|
||
BlockPointer->Next = pCurrentBlock;
|
||
BlockHead = BlockPointer;
|
||
} else {
|
||
|
||
//
|
||
// else add to middle or bottom depending on NextBlock
|
||
//
|
||
|
||
BlockPointer->Next = pNextBlock;
|
||
pCurrentBlock->Next = BlockPointer;
|
||
}
|
||
BlockPointer++; // Note that this works because
|
||
// we know the offset part of
|
||
// the addr is always < 64k.
|
||
return TRUE;
|
||
}
|
||
VOID
|
||
AddPs2CardRomRam (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine adds ROM/RAM block to our ROM list for missed MCA Adapters.
|
||
|
||
Notes: This function was constructed to recognize
|
||
PS/2 cards that normally are missed. Without
|
||
this code, VBIOS will not recognize certain adapters
|
||
since they have no ROM header, or use RAM.
|
||
|
||
POS ID Adapter Name ROM RAM
|
||
------- ------------ --- ---
|
||
E000 Token Ring x x
|
||
E001 Token Ring x x
|
||
E04F 3119 Scanner x
|
||
E1FF 3270 Ver B x
|
||
E7FF 3270 Ver A x
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i;
|
||
USHORT CardID;
|
||
ULONG ROMAddr,RAMAddr;
|
||
ULONG RAMSize, ROMSize;
|
||
FPMCA_POS_DATA PosData;
|
||
|
||
//
|
||
// for every adapter slot, we search if the card is IBM Token Ring.
|
||
// if yes, we will calculate RAM and ROM address from POS information
|
||
// and add these blocks to our ROM BLOCK list.
|
||
//
|
||
|
||
for (i = 0L; i < POS_MAX_SLOT; i++) {
|
||
|
||
ROMAddr = 0L;
|
||
RAMAddr = 0L;
|
||
RAMSize = 0L;
|
||
ROMSize = 0L;
|
||
|
||
//
|
||
// get the POS ID of the card
|
||
//
|
||
|
||
PosData = HwMcaPosData + i;
|
||
CardID = PosData->AdapterId;
|
||
switch(CardID) {
|
||
|
||
//
|
||
// 4Mhz Token ring (0xE000) or 16/4Mhz Token ring (0xE001)
|
||
//
|
||
|
||
case 0xE000:
|
||
case 0xE001:
|
||
|
||
//
|
||
// get ROM and RAM addresses of adapter
|
||
//
|
||
|
||
ROMAddr = ((ULONG)PosData->PosData3 & 0xfe)<<12;
|
||
RAMAddr = ((ULONG)PosData->PosData1 & 0xfe)<<12;
|
||
RAMSize = (ULONG) (1<<((PosData->PosData2 & 0x0c)>>2)) * 8192L;
|
||
ROMSize = 8192L;
|
||
break;
|
||
|
||
//
|
||
// 3119 Scanner
|
||
// formula (shl (and (not (shr POS[0] 4)) 0xf) 13) + 0xC0000
|
||
//
|
||
|
||
case 0xE04F:
|
||
|
||
RAMAddr = (((~((ULONG)PosData->PosData1 >> 4)) & 0xf) << 13) + 0xC0000L;
|
||
RAMSize = 0x2000L; // size is fixed
|
||
break;
|
||
|
||
//
|
||
// 3270 Version A
|
||
//
|
||
|
||
case 0xE7FF:
|
||
|
||
RAMAddr = 0xCE000L; // address is fixed
|
||
RAMSize = 8192L; // size is fixed
|
||
break;
|
||
|
||
//
|
||
// 3270 Version B
|
||
//
|
||
|
||
case 0xE1FF:
|
||
|
||
RAMAddr = ((ULONG)PosData->PosData2) << 12;
|
||
RAMSize = 8192L; // size is fixed
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
//
|
||
// if adapter has ROM, then add it
|
||
//
|
||
|
||
if (ROMAddr) {
|
||
AddRomBlock(ROMAddr, ROMSize);
|
||
}
|
||
|
||
//
|
||
// if adapter has RAM, then add it
|
||
//
|
||
|
||
if (RAMAddr) {
|
||
AddRomBlock(RAMAddr, RAMSize);
|
||
}
|
||
}
|
||
}
|
||
|
||
BOOLEAN
|
||
ScanRomBlocks(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans the ROM IO area and checks for 55AA at every
|
||
512 bytes for valid ROM blocks.
|
||
|
||
|
||
NOTES:
|
||
|
||
-------------
|
||
| |
|
||
| |
|
||
------------------100000
|
||
^ | |
|
||
| | |
|
||
| -------------f0000 (ROMBIOS_START) ---
|
||
| | | ^
|
||
| | | |
|
||
EXTROM_LEN -------------e0000 (PS2BIOS_START) --- |
|
||
| | | ^ Search |
|
||
| | | Search | Range |
|
||
| -------------d0000 Range | on AT |
|
||
| | | on PS/2| |
|
||
V | | V V
|
||
------------------c0000 (EXTROM_START) --- ---
|
||
|
||
ON AT:
|
||
Scan through EXTROM_START-effff for ROM Blocks
|
||
ON PS2
|
||
Scan through EXTROM_START-dffff for ROM Blocks
|
||
|
||
Arguments:
|
||
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG BlockSize;
|
||
BOOLEAN Success = TRUE;
|
||
FPUCHAR Current;
|
||
ULONG RomAddr, RomEnd;
|
||
|
||
//
|
||
// As per the machine type restrict the search range
|
||
//
|
||
|
||
MAKE_FP(Current, EXTROM_START);
|
||
RomAddr = EXTROM_START;
|
||
|
||
if ((HwBusType == MACHINE_TYPE_MCA) ||
|
||
(BiosSystemEnvironment.Model == PS2_L40) ||
|
||
(BiosSystemEnvironment.Model == PS1_386) ||
|
||
(BiosSystemEnvironment.Model == PS2_AT)) {
|
||
|
||
RomEnd = PS2BIOS_START;
|
||
} else {
|
||
RomEnd = ROMBIOS_START;
|
||
}
|
||
|
||
while (RomAddr < RomEnd) {
|
||
|
||
if (((FPROM_HEADER)Current)->Signature == ROM_HEADER_SIGNATURE) {
|
||
|
||
BlockSize = (ULONG)((FPROM_HEADER)Current)->NumberBlocks * BLOCKSIZE;
|
||
|
||
if ((RomAddr + BlockSize) > RomEnd) {
|
||
BlockSize = RomEnd - RomAddr;
|
||
}
|
||
|
||
//
|
||
// V7 VRAM card does not correctly report its BlockSize. Since
|
||
// this is a very popular video card, we provide a workaround
|
||
// for it.
|
||
//
|
||
|
||
if ((RomAddr == 0xC0000) && (BlockSize < 0x8000)) {
|
||
BlockSize = 0x8000;
|
||
}
|
||
if (!AddRomBlock(RomAddr, BlockSize)) {
|
||
Success = FALSE;
|
||
break;
|
||
}
|
||
RomAddr += BlockSize;
|
||
RomAddr = ALIGN_UP(RomAddr, ROM_HEADER_INCREMENT);
|
||
MAKE_FP(Current, RomAddr);
|
||
continue;
|
||
}
|
||
RomAddr += ROM_HEADER_INCREMENT;
|
||
MAKE_FP(Current, RomAddr);
|
||
}
|
||
|
||
//
|
||
// Last but not least, add the system ROM to the list
|
||
//
|
||
|
||
if (Success) {
|
||
|
||
RomAddr = ROMBIOS_START;
|
||
BlockSize = ROMBIOS_LEN;
|
||
if ((HwBusType == MACHINE_TYPE_MCA) ||
|
||
(BiosSystemEnvironment.Model == PS2_L40) ||
|
||
(BiosSystemEnvironment.Model == PS1_386) ||
|
||
(BiosSystemEnvironment.Model == PS2_AT)) {
|
||
RomAddr = PS2BIOS_START;
|
||
BlockSize = PS2BIOS_LEN;
|
||
}
|
||
|
||
if (!AddRomBlock(RomAddr, BlockSize)) {
|
||
Success = FALSE;
|
||
}
|
||
}
|
||
|
||
return Success;
|
||
}
|
||
|
||
FPTEMPORARY_ROM_BLOCK
|
||
MatchRomBlock (
|
||
ULONG PhysicalAddr
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine finds the ROM block which the 'PhysicalAddr' is in.
|
||
|
||
Arguments:
|
||
|
||
PhysicalAddr - the physical address ...
|
||
|
||
Return Value:
|
||
|
||
A pointer to the detected ROM block.
|
||
|
||
--*/
|
||
|
||
{
|
||
FPTEMPORARY_ROM_BLOCK CurrentBlock;
|
||
ROM_BLOCK RomBlock;
|
||
|
||
CurrentBlock = BlockHead;
|
||
while (CurrentBlock) {
|
||
RomBlock = CurrentBlock->RomBlock;
|
||
if (RomBlock.Address <= PhysicalAddr &&
|
||
RomBlock.Address + RomBlock.Size > PhysicalAddr) {
|
||
break;
|
||
} else {
|
||
CurrentBlock = CurrentBlock->Next;
|
||
}
|
||
}
|
||
return(CurrentBlock);
|
||
}
|
||
|
||
BOOLEAN
|
||
IsSameRomBlock (
|
||
FPTEMPORARY_ROM_BLOCK Source,
|
||
FPTEMPORARY_ROM_BLOCK Destination
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks if the passed in ROM blocks contain the same
|
||
information. This ususally happens when the two ROM blocks are for
|
||
video ROM and shadowed video ROM.
|
||
|
||
Arguments:
|
||
|
||
Source - the source ROM block.
|
||
|
||
Destination - the ROM block to compare with.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN TRUE if the two ROM blocks are the same else FALSE is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
if (Source == NULL || Destination == NULL) {
|
||
return(FALSE);
|
||
}
|
||
|
||
//
|
||
// First make sure their sizes are the same.
|
||
//
|
||
|
||
if (Source->RomBlock.Size == Destination->RomBlock.Size) {
|
||
if (!HwRomCompare(Source->RomBlock.Address,
|
||
Destination->RomBlock.Address,
|
||
Source->RomBlock.Size)){
|
||
return(TRUE);
|
||
}
|
||
}
|
||
return(FALSE);
|
||
|
||
}
|
||
|
||
VOID
|
||
CheckVideoRom (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks if the int 10h video handler is in the video
|
||
ROM block detected by us. If not, the video ROM must have been
|
||
remapped/shadowed to other area (usually 0xE0000.)
|
||
|
||
NOTE: In this function, I commented out the code which removes the
|
||
Video ROM block if it has been shadowed. I found out
|
||
machine POST code does not modify ALL the VIDEO ROM related
|
||
pointers.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG Vector, Handler, VectorAddr = 0x10 * sizeof(ULONG);
|
||
FPULONG pVectorAddr;
|
||
FPTEMPORARY_ROM_BLOCK RomBlock, VideoRomBlock;
|
||
ULONG Size;
|
||
|
||
MAKE_FP(pVectorAddr, VectorAddr);
|
||
Vector = *pVectorAddr;
|
||
Handler = ((Vector >> 16) << 4) + (Vector & 0xffff);
|
||
RomBlock = MatchRomBlock(Handler);
|
||
|
||
//
|
||
// Check if the int 10h handler falls in one of our ROM blocks.
|
||
//
|
||
|
||
if (RomBlock) {
|
||
if (RomBlock->RomBlock.Address >= 0xC0000 &&
|
||
RomBlock->RomBlock.Address < 0xC8000) {
|
||
|
||
//
|
||
// if int 10h handler is in the standard video ROM area, we simply
|
||
// return. Either the video ROM is not shadowed or it
|
||
// is a in-place shadow.
|
||
//
|
||
|
||
return;
|
||
} else {
|
||
|
||
//
|
||
// The ROM block associated with the int 10h handler is not in
|
||
// standard video bios ROM area. It must have been mapped to
|
||
// the current location. We now need to make sure we have the
|
||
// ROM block which contains the 40:a8 VGA parameter.
|
||
//
|
||
|
||
VectorAddr = VGA_PARAMETER_POINTER;
|
||
MAKE_FP(pVectorAddr, VectorAddr);
|
||
Vector = *pVectorAddr;
|
||
Handler = ((Vector >> 16) << 4) + (Vector & 0xffff);
|
||
VideoRomBlock = MatchRomBlock(Handler);
|
||
if (VideoRomBlock == NULL) {
|
||
|
||
//
|
||
// We did not find the Video ROM associated with the
|
||
// VGA parameters. Try detect it.
|
||
//
|
||
|
||
//
|
||
// In the following memory comparison, we skip the first 16 bytes.
|
||
// Because most likely the reason we did not find the standard
|
||
// Video ROM is because the signature word is missing.
|
||
//
|
||
|
||
Handler = (Handler & 0xF0000) +
|
||
(RomBlock->RomBlock.Address & 0xFFFF);
|
||
if (!HwRomCompare(RomBlock->RomBlock.Address + 0x10,
|
||
Handler + 0x10,
|
||
RomBlock->RomBlock.Size - 0x10)) {
|
||
if ( ( ( Handler & 0xFFFF ) == 0 ) && ( RomBlock->RomBlock.Size < 0x8000 ) ) {
|
||
Size = 0x8000;
|
||
} else {
|
||
Size = RomBlock->RomBlock.Size;
|
||
}
|
||
AddRomBlock(Handler, Size);
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// There is no ROM block associated with the int 10h handler.
|
||
// We can find the shadowed video ROM block if:
|
||
// We detected the original video ROM in 0xC0000 - 0xC8000 range
|
||
//
|
||
|
||
VideoRomBlock = MatchRomBlock((Handler & 0xFFFF) + 0xC0000);
|
||
if (VideoRomBlock != NULL) {
|
||
|
||
//
|
||
// In the following memory comparison, we skip the first 16 bytes.
|
||
// Because most likely the reason we did not find the shadow rom
|
||
// is the signature word is missing.
|
||
//
|
||
|
||
if (!HwRomCompare(VideoRomBlock->RomBlock.Address + 0x10,
|
||
(Handler & 0xF0000) +
|
||
(VideoRomBlock->RomBlock.Address & 0xFFFF) + 0x10,
|
||
VideoRomBlock->RomBlock.Size - 0x10)) {
|
||
|
||
AddRomBlock((VideoRomBlock->RomBlock.Address & 0xFFFF) +
|
||
(Handler & 0xF0000),
|
||
VideoRomBlock->RomBlock.Size);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#endif // _GAMBIT_
|
||
|
||
VOID
|
||
GetRomBlocks(
|
||
FPUCHAR ReservedBuffer,
|
||
PUSHORT Size
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans the ROM IO area and collects all the ROM blocks.
|
||
|
||
Arguments:
|
||
|
||
ReservedBuffer - Supplies a far pointer to the buffer.
|
||
|
||
Size - Supplies a near pointer to a variable to receive the size
|
||
of the ROM block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
#if defined(_GAMBIT_)
|
||
*Size = 0;
|
||
#else
|
||
FPTEMPORARY_ROM_BLOCK Source;
|
||
ULONG StartAddr, EndAddr;
|
||
FPUSHORT TestAddr;
|
||
FPROM_BLOCK Destination;
|
||
USHORT BufferSize;
|
||
ULONG EBiosAddress = 0, EBiosLength = 0;
|
||
ULONG far *EBiosInformation = (ULONG far *)
|
||
((DOS_BEGIN_SEGMENT << 4) + EBIOS_INFO_OFFSET);
|
||
|
||
//
|
||
// First we reserve the max space needed and build our temporary rom
|
||
// block list in the heap space below the space reservedand. After
|
||
// the temporary list is built, we then copy it to the caller supplied
|
||
// reserved space.
|
||
//
|
||
|
||
BlockPointer = (FPTEMPORARY_ROM_BLOCK)HwAllocateHeap(0, FALSE);
|
||
BlockHead = NULL;
|
||
*Size = 0;
|
||
|
||
GetBiosSystemEnvironment((PUCHAR)&BiosSystemEnvironment);
|
||
if (BiosSystemEnvironment.ConfigurationFlags & 0x4) {
|
||
|
||
//
|
||
// If extened BIOS data area is allocated, we will find out its
|
||
// location and size and save in ROM blocks.
|
||
//
|
||
|
||
_asm {
|
||
push es
|
||
mov ah, 0xC1
|
||
int 15h
|
||
jc short Exit
|
||
|
||
cmp ah, 0x86
|
||
je short Exit
|
||
|
||
mov bx, 0
|
||
mov dx, 0
|
||
mov ax, 0
|
||
mov al, es:[bx]
|
||
shl ax, 10
|
||
mov word ptr EBiosLength, ax
|
||
mov ax, es
|
||
mov dx, es
|
||
shl ax, 4
|
||
shr dx, 12
|
||
mov word ptr EBiosAddress, ax
|
||
mov word ptr EBiosAddress + 2, dx
|
||
Exit:
|
||
pop es
|
||
}
|
||
}
|
||
|
||
//
|
||
// Save the Extended BIOS data area address and size at 700:40
|
||
//
|
||
|
||
if (EBiosLength) {
|
||
*EBiosInformation++ = EBiosAddress;
|
||
*EBiosInformation = EBiosLength;
|
||
} else {
|
||
*EBiosInformation++ = 0L;
|
||
*EBiosInformation = 0L;
|
||
}
|
||
if (!ScanRomBlocks()) {
|
||
return;
|
||
}
|
||
|
||
if (HwBusType == MACHINE_TYPE_MCA) {
|
||
AddPs2CardRomRam();
|
||
}
|
||
|
||
//
|
||
// On some machines, when they shadow video ROM from 0xC0000 to
|
||
// 0xE0000, they copy code only (no signature.) So, we need
|
||
// special code to work around the problem.
|
||
//
|
||
|
||
CheckVideoRom();
|
||
|
||
//
|
||
// Now do our special hack for IBM. On SOME IBM PCs, they use
|
||
// E0000-FFFFF for system BIOS (even on non PS/2 machines.) Since
|
||
// system BIOS has no ROM header, it is very hard to know the starting
|
||
// address of system ROM. So we:
|
||
//
|
||
// 1. Make sure there is no ROM block in E0000-EFFFF area.
|
||
// 2. and E0000-EFFFF contains valid data.
|
||
//
|
||
// If both 1 and 2 are true, we assume E0000-EFFFF is part of system
|
||
// ROM.
|
||
//
|
||
|
||
Source = BlockHead;
|
||
while (Source) {
|
||
StartAddr = Source->RomBlock.Address;
|
||
EndAddr = StartAddr + Source->RomBlock.Size - 1;
|
||
if ((StartAddr < 0xE0000 && EndAddr < 0xE0000) ||
|
||
(StartAddr >= 0xF0000)) {
|
||
Source = Source->Next;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
if (Source == NULL) {
|
||
for (StartAddr = 0xE0000; StartAddr < 0xF0000; StartAddr += 0x800) {
|
||
MAKE_FP(TestAddr, StartAddr);
|
||
if (*TestAddr != 0xffff) {
|
||
AddRomBlock(0xE0000, 0x10000);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now copy the rom block list to our reserved space and release
|
||
// the extra space we reserved.
|
||
//
|
||
|
||
Source = BlockHead;
|
||
Destination = (FPROM_BLOCK)ReservedBuffer;
|
||
BufferSize = 0;
|
||
while (Source) {
|
||
*Destination = *((FPROM_BLOCK)&Source->RomBlock);
|
||
BufferSize += sizeof(ROM_BLOCK);
|
||
Source = Source->Next;
|
||
Destination++;
|
||
}
|
||
*Size = BufferSize;
|
||
#endif // _GAMBIT_
|
||
}
|
||
|
||
VOID
|
||
HwGetBiosDate(
|
||
ULONG StartingAddress,
|
||
USHORT Length,
|
||
PUSHORT Year,
|
||
PUSHORT Month,
|
||
PUSHORT Day
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Scans the specified area for the most recent date of the
|
||
form xx/xx/xx.
|
||
|
||
Arguments:
|
||
|
||
StartingAddress - First address to scan
|
||
Length - Length of area to scan
|
||
|
||
Return Value:
|
||
|
||
Year - If non-zero, the year of the date (1991, 1992, ...)
|
||
Month - If non-zero, then month of the date found
|
||
Day - If non-zero, the day of the date found
|
||
|
||
|
||
--*/
|
||
{
|
||
FPUCHAR fp, date;
|
||
USHORT y, m, d;
|
||
UCHAR c;
|
||
ULONG i, temp;
|
||
|
||
#if defined(_GAMBIT_)
|
||
{
|
||
SSC_TIME_FIELDS TimeFields;
|
||
|
||
SscQueryRealTimeClock(&TimeFields);
|
||
|
||
*Year = (USHORT) TimeFields.Year;
|
||
*Month = (USHORT) TimeFields.Month;
|
||
*Day = (USHORT) TimeFields.Day;
|
||
}
|
||
#else
|
||
//
|
||
//
|
||
// Zero return values
|
||
//
|
||
|
||
*Year = 0;
|
||
*Month = 0;
|
||
*Day = 0;
|
||
|
||
//
|
||
// Search for date with the format MM/DD/YY or M1M1M2M2//D1D1D2D2//Y1Y1Y2Y2
|
||
//
|
||
|
||
MAKE_FP(fp, StartingAddress); // initialize fp pointer
|
||
while (Length > 8) {
|
||
|
||
c = fp[7];
|
||
if ((c < '0' || c > '9') && (c != '/' && c != '-')) {
|
||
// these 8 bytes are not a date, next location
|
||
|
||
fp += 8;
|
||
Length -= 8;
|
||
continue;
|
||
}
|
||
|
||
date = fp; // check for date at this pointer
|
||
fp += 1; // skip to next byte
|
||
Length -= 1;
|
||
|
||
//
|
||
// Check for date of the form MM/DD/YY
|
||
//
|
||
|
||
y = 0;
|
||
if (date[0] >= '0' && date[0] <= '9' &&
|
||
date[1] >= '0' && date[1] <= '9' &&
|
||
(date[2] == '/' || date[2] == '-') &&
|
||
date[3] >= '0' && date[3] <= '9' &&
|
||
date[4] >= '0' && date[4] <= '9' &&
|
||
(date[5] == '/' || date[5] == '-') &&
|
||
date[6] >= '0' && date[6] <= '9' &&
|
||
date[7] >= '0' && date[7] <= '9' ) {
|
||
|
||
|
||
//
|
||
// A valid looking date field at date, crack it
|
||
//
|
||
|
||
y = (date[6] - '0') * 10 + date[7] - '0' + 1900;
|
||
m = (date[0] - '0') * 10 + date[1] - '0';
|
||
d = (date[3] - '0') * 10 + date[4] - '0';
|
||
}
|
||
|
||
//
|
||
// Check for date of the form M1M1M2M2//D1D1D2D2//Y1Y1Y2Y2
|
||
//
|
||
|
||
if (Length >= 15 &&
|
||
date[ 0] >= '0' && date[ 0] <= '9' && date[ 0] == date[ 1] &&
|
||
date[ 2] >= '0' && date[ 2] <= '9' && date[ 2] == date[ 3] &&
|
||
(date[ 4] == '/' || date[ 4] == '-') && date[ 4] == date[ 5] &&
|
||
date[ 6] >= '0' && date[ 6] <= '9' && date[ 6] == date[ 7] &&
|
||
date[ 8] >= '0' && date[ 8] <= '9' && date[ 8] == date[ 9] &&
|
||
(date[10] == '/' || date[10] == '-') && date[10] == date[11] &&
|
||
date[12] >= '0' && date[12] <= '9' && date[12] == date[13] &&
|
||
date[14] >= '0' && date[14] <= '9' && date[14] == date[15]) {
|
||
|
||
//
|
||
// A valid looking date field at date, crack it
|
||
//
|
||
|
||
y = (date[12] - '0') * 10 + date[14] - '0' + 1900;
|
||
m = (date[ 0] - '0') * 10 + date[ 2] - '0';
|
||
d = (date[ 6] - '0') * 10 + date[ 8] - '0';
|
||
}
|
||
|
||
if (y != 0) {
|
||
if (m < 1 || m > 12 || d < 1 || d > 31) {
|
||
y = 0; // bad field in date, skip it
|
||
} else {
|
||
if (y < 1980) {
|
||
|
||
//
|
||
// Roll to next century.
|
||
//
|
||
|
||
y += 100;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check for date of the form 19xx or 20xx
|
||
//
|
||
// First, check the 5th character is not a digit.
|
||
//
|
||
|
||
#define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
|
||
|
||
if (!IS_DIGIT(date[4])) {
|
||
for (i = 0, temp = 0; i < 4; i++) {
|
||
if (!IS_DIGIT(date[i])) {
|
||
temp = 0;
|
||
break;
|
||
}
|
||
temp = (temp * 10) + date[i] - '0';
|
||
}
|
||
if ((temp >= 1980) || (temp < 2599)) {
|
||
|
||
//
|
||
// Looks like a reasonable date, use it.
|
||
//
|
||
|
||
y = temp;
|
||
m = 0;
|
||
d = 0;
|
||
}
|
||
}
|
||
|
||
if (!y) {
|
||
// not a date - skip it
|
||
continue;
|
||
}
|
||
|
||
if ((y > *Year) ||
|
||
(y == *Year && m > *Month) ||
|
||
(y == *Year && m == *Month && d > *Day) ) {
|
||
|
||
//
|
||
// This date is more recent
|
||
//
|
||
|
||
*Year = y;
|
||
*Month = m;
|
||
*Day = d;
|
||
}
|
||
}
|
||
#endif // _GAMBIT_
|
||
}
|
||
|
||
|