536 lines
14 KiB
C
536 lines
14 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
eisac.c
|
||
|
||
Abstract:
|
||
|
||
This module implements routines to get EISA configuration information.
|
||
|
||
Author:
|
||
|
||
Shie-Lin Tzong (shielint) 10-June-1991
|
||
|
||
Environment:
|
||
|
||
16-bit real mode.
|
||
|
||
|
||
Revision History:
|
||
|
||
John Vert (jvert) 5-Sep-1991
|
||
Moved into the SU module of portable bootloader
|
||
|
||
--*/
|
||
#include "su.h"
|
||
#include "eisa.h"
|
||
|
||
//
|
||
// HACKHACK - John Vert (jvert) 12-Sep-1991
|
||
// We have to initialize this or else it gets stuck in our BSS section
|
||
// which is right in the middle of the osloader.exe header
|
||
//
|
||
extern BTEISA_FUNCTION_INFORMATION FunctionInformation;
|
||
|
||
|
||
BOOLEAN
|
||
FindFunctionInformation (
|
||
IN UCHAR SlotFlags,
|
||
IN UCHAR FunctionFlags,
|
||
OUT PBTEISA_FUNCTION_INFORMATION Buffer,
|
||
IN BOOLEAN FromBeginning
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine finds function information that matches the specified
|
||
flags. It starts, either where it left off last time, or at the
|
||
beginning (slot 0, function 0)
|
||
|
||
Arguments:
|
||
|
||
Flags - Flags to check against EISA function and slot information.
|
||
|
||
Buffer - pointer to buffer to store EISA information in.
|
||
|
||
FromBeginning - if TRUE, search starts at slot 0, function 0.
|
||
else continue from where it left off last time.
|
||
|
||
Return Value:
|
||
|
||
TRUE - If the operation is success (Buffer is filled in.)
|
||
FALSE - Request fails.
|
||
|
||
Notes: The buffer is always changed, reguardless of the success
|
||
of the function. When failure is returned, the info is invalid.
|
||
|
||
--*/
|
||
|
||
{
|
||
static UCHAR Slot=0;
|
||
static UCHAR Function=0;
|
||
BTEISA_SLOT_INFORMATION SlotInformation;
|
||
UCHAR Flags;
|
||
UCHAR ReturnCode;
|
||
|
||
if (FromBeginning) {
|
||
Slot = 0;
|
||
Function = 0;
|
||
}
|
||
BtGetEisaSlotInformation(&SlotInformation, Slot);
|
||
while (SlotInformation.ReturnCode != EISA_INVALID_SLOT) {
|
||
|
||
//
|
||
// insure that the slot is not empty, and all of the flags are set.
|
||
// the flags are tested by performing the following logic:
|
||
//
|
||
// -- (RequestSlotFlags XOR (SlotFlags AND RequestSlotFlags)) --
|
||
//
|
||
// if all the requested flags are set, the result will be zero
|
||
//
|
||
|
||
if ((SlotInformation.ReturnCode != EISA_EMPTY_SLOT) &&
|
||
(!(SlotFlags ^ (SlotInformation.FunctionInformation & SlotFlags)))) {
|
||
|
||
while (SlotInformation.NumberFunctions > Function) {
|
||
ReturnCode = BtGetEisaFunctionInformation(Buffer, Slot, Function);
|
||
Function++;
|
||
|
||
//
|
||
// if function call succeeded
|
||
//
|
||
|
||
if (!ReturnCode){
|
||
|
||
Flags = Buffer->FunctionFlags;
|
||
|
||
//
|
||
// Function Enable/Disable bit reversed.
|
||
//
|
||
|
||
Flags |= (~Flags & EISA_FUNCTION_ENABLED);
|
||
|
||
//
|
||
// insure that all the function flags are set.
|
||
// the flags are tested by performing the following logic:
|
||
//
|
||
// -- (ReqFuncFlags XOR (FuncFlags AND ReqFuncFlags)) --
|
||
//
|
||
// if all the requested flags are set, the result will
|
||
// be zero
|
||
//
|
||
|
||
if (!(FunctionFlags ^ (Flags & FunctionFlags))) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
Slot++;
|
||
Function = 0;
|
||
BtGetEisaSlotInformation(&SlotInformation, Slot);
|
||
}
|
||
|
||
Slot = 0;
|
||
Function = 0;
|
||
return FALSE;
|
||
}
|
||
|
||
VOID
|
||
InsertDescriptor (
|
||
ULONG Address,
|
||
ULONG Size
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine inserts a descriptor into the correct place in the
|
||
memory descriptor list.
|
||
|
||
Arguments:
|
||
|
||
Address - Starting address of the memory block.
|
||
|
||
Size - Size of the memory block to be inserted.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
MEMORY_LIST_ENTRY _far *CurrentEntry;
|
||
|
||
#ifdef DEBUG1
|
||
BlPrint("Inserting descriptor %lx at %lx\n",Size,Address);
|
||
_asm {
|
||
push ax
|
||
mov ax, 0
|
||
int 16h
|
||
pop ax
|
||
}
|
||
#endif
|
||
//
|
||
// Search the spot to insert the new descriptor.
|
||
//
|
||
|
||
CurrentEntry = MemoryDescriptorList;
|
||
|
||
while (CurrentEntry->BlockSize > 0) {
|
||
//
|
||
// Check to see if this memory descriptor is contiguous with
|
||
// the current one. If so, coalesce them. (yes, some machines
|
||
// will return memory descriptors that look like this. Compaq
|
||
// Prosignia machines)
|
||
//
|
||
if (Address+Size == CurrentEntry->BlockBase) {
|
||
#ifdef DEBUG1
|
||
BlPrint(" coalescing with descriptor at %lx (%lx)\n",
|
||
CurrentEntry->BlockBase,
|
||
CurrentEntry->BlockSize);
|
||
#endif
|
||
CurrentEntry->BlockBase = Address;
|
||
CurrentEntry->BlockSize += Size;
|
||
#ifdef DEBUG1
|
||
BlPrint(" new descriptor at %lx (%lx)\n",
|
||
CurrentEntry->BlockBase,
|
||
CurrentEntry->BlockSize);
|
||
#endif
|
||
break;
|
||
}
|
||
if (Address == (CurrentEntry->BlockBase + CurrentEntry->BlockSize)) {
|
||
#ifdef DEBUG1
|
||
BlPrint(" coalescing with descriptor at %lx (%lx)\n",
|
||
CurrentEntry->BlockBase,
|
||
CurrentEntry->BlockSize);
|
||
#endif
|
||
CurrentEntry->BlockSize += Size;
|
||
#ifdef DEBUG1
|
||
BlPrint(" new descriptor at %lx (%lx)\n",
|
||
CurrentEntry->BlockBase,
|
||
CurrentEntry->BlockSize);
|
||
#endif
|
||
break;
|
||
}
|
||
|
||
CurrentEntry++;
|
||
}
|
||
|
||
if (CurrentEntry->BlockSize == 0) {
|
||
//
|
||
// If CurrentEntry->BlockSize == 0, we have reached the end of the list
|
||
// So, insert the new descriptor here, and create a new end-of-list entry
|
||
//
|
||
CurrentEntry->BlockBase = Address;
|
||
CurrentEntry->BlockSize = Size;
|
||
|
||
++CurrentEntry;
|
||
//
|
||
// Create a new end-of-list marker
|
||
//
|
||
CurrentEntry->BlockBase = 0L;
|
||
CurrentEntry->BlockSize = 0L;
|
||
}
|
||
#ifdef DEBUG1
|
||
//
|
||
// Wait for a keypress
|
||
//
|
||
_asm {
|
||
push ax
|
||
mov ax, 0
|
||
int 16h
|
||
pop ax
|
||
}
|
||
#endif
|
||
|
||
}
|
||
|
||
ULONG
|
||
EisaConstructMemoryDescriptors (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine gets the information EISA memory function above 16M
|
||
and creates entries in the memory Descriptor array for them.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Number of pages of usable memory.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN Success;
|
||
PBTEISA_MEMORY_CONFIGURATION MemoryConfiguration;
|
||
ULONG Address;
|
||
ULONG EndAddress;
|
||
ULONG Size;
|
||
ULONG MemorySize=0;
|
||
ULONG IsaMemUnder1Mb=0xffffffff;
|
||
MEMORY_LIST_ENTRY _far *CurrentEntry;
|
||
|
||
//
|
||
// HACKHACK John Vert (jvert) 5-Mar-1993
|
||
//
|
||
// See if there is already a memory descriptor for the 640k under
|
||
// 1Mb. If so, we will believe it instead of the EISA routine. This
|
||
// is because many EISA routines will always return 640k, even if
|
||
// the disk parameter table is in the last 1k. The ISA routines will
|
||
// always account for the disk parameter tables. If we believe the
|
||
// EISA routines, we can overwrite the disk parameter tables, causing
|
||
// much grief.
|
||
//
|
||
CurrentEntry = MemoryDescriptorList;
|
||
while (CurrentEntry->BlockSize > 0) {
|
||
if (CurrentEntry->BlockBase == 0) {
|
||
//
|
||
// found a descriptor starting at zero with a size > 0, so
|
||
// this is the one we want to override the EISA information.
|
||
//
|
||
IsaMemUnder1Mb = CurrentEntry->BlockSize;
|
||
break;
|
||
}
|
||
++CurrentEntry;
|
||
}
|
||
|
||
//
|
||
// Initialize the first entry in the list to zero (end-of-list)
|
||
//
|
||
|
||
MemoryDescriptorList->BlockSize = 0;
|
||
MemoryDescriptorList->BlockBase = 0;
|
||
|
||
Success = FindFunctionInformation(
|
||
EISA_HAS_MEMORY_ENTRY,
|
||
EISA_FUNCTION_ENABLED | EISA_HAS_MEMORY_ENTRY,
|
||
&FunctionInformation,
|
||
TRUE
|
||
);
|
||
|
||
//
|
||
// while there are more memory functions, and more free descriptors
|
||
//
|
||
|
||
while (Success) {
|
||
|
||
MemoryConfiguration = &FunctionInformation.EisaMemory[0];
|
||
|
||
do {
|
||
|
||
//
|
||
// Get physical address of the memory.
|
||
// Note: physical address is stored divided by 100h
|
||
//
|
||
|
||
Address = (((ULONG)MemoryConfiguration->AddressHighByte << 16)
|
||
+ MemoryConfiguration->AddressLowWord) * 0x100;
|
||
|
||
//
|
||
// Get the size of the memory block.
|
||
// Note: Size is stored divided by 400h with the value of 0
|
||
// meaning a size of 64M
|
||
//
|
||
|
||
if (MemoryConfiguration->MemorySize) {
|
||
Size = ((ULONG)MemoryConfiguration->MemorySize) * 0x400;
|
||
} else {
|
||
Size = (_64MEGB);
|
||
}
|
||
|
||
#ifdef DEBUG1
|
||
BlPrint("EISA memory at %lx Size=%lx Type=%x ",
|
||
Address,
|
||
Size,
|
||
MemoryConfiguration->ConfigurationByte);
|
||
|
||
if ((MemoryConfiguration->ConfigurationByte.Type == EISA_SYSTEM_MEMORY) &&
|
||
(MemoryConfiguration->ConfigurationByte.ReadWrite == EISA_MEMORY_TYPE_RAM) ) {
|
||
|
||
BlPrint(" (USED BY NT)\n");
|
||
} else {
|
||
BlPrint(" (not used)\n");
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Compute end address to determine if any part of the block
|
||
// is above 16M
|
||
//
|
||
|
||
EndAddress = Address + Size;
|
||
|
||
//
|
||
// If it is SYSTEM memory and RAM, add the descriptor to the list.
|
||
//
|
||
|
||
if ((MemoryConfiguration->ConfigurationByte.Type == EISA_SYSTEM_MEMORY) &&
|
||
(MemoryConfiguration->ConfigurationByte.ReadWrite == EISA_MEMORY_TYPE_RAM) ) {
|
||
|
||
if (Address==0) {
|
||
//
|
||
// This is the descriptor for the memory under 1Mb.
|
||
// Compare it with the ISA routine's result, and see
|
||
// if the ISA one is smaller. If it is, use the ISA
|
||
// answer.
|
||
//
|
||
if (Size > IsaMemUnder1Mb) {
|
||
Size = IsaMemUnder1Mb;
|
||
}
|
||
}
|
||
InsertDescriptor(Address, Size);
|
||
MemorySize += (Size >> 12);
|
||
}
|
||
|
||
} while (MemoryConfiguration++->ConfigurationByte.MoreEntries);
|
||
|
||
Success = FindFunctionInformation(
|
||
EISA_HAS_MEMORY_ENTRY,
|
||
EISA_FUNCTION_ENABLED | EISA_HAS_MEMORY_ENTRY,
|
||
&FunctionInformation,
|
||
FALSE
|
||
);
|
||
}
|
||
#ifdef DEBUG1
|
||
//
|
||
// Wait for a keypress
|
||
//
|
||
_asm {
|
||
push ax
|
||
mov ax, 0
|
||
int 16h
|
||
pop ax
|
||
}
|
||
#endif
|
||
return(MemorySize);
|
||
}
|
||
|
||
BOOLEAN
|
||
Int15E820 (
|
||
E820Frame *Frame
|
||
);
|
||
|
||
|
||
BOOLEAN
|
||
ConstructMemoryDescriptors (
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
ULONG BAddr, EAddr;
|
||
E820Frame Frame;
|
||
|
||
//
|
||
// Initialize the first entry in the list to zero (end-of-list)
|
||
//
|
||
|
||
MemoryDescriptorList->BlockSize = 0;
|
||
MemoryDescriptorList->BlockBase = 0;
|
||
|
||
//
|
||
// Any entries returned for E820?
|
||
//
|
||
|
||
Frame.Key = 0;
|
||
Frame.Size = sizeof (Frame.Descriptor);
|
||
Int15E820 (&Frame);
|
||
if (Frame.ErrorFlag || Frame.Size < sizeof (Frame.Descriptor)) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Found memory in table, use the reported memory
|
||
//
|
||
|
||
Frame.Key = 0;
|
||
do {
|
||
Frame.Size = sizeof (Frame.Descriptor);
|
||
Int15E820 (&Frame);
|
||
if (Frame.ErrorFlag || Frame.Size < sizeof (Frame.Descriptor)) {
|
||
break ;
|
||
}
|
||
|
||
#ifdef DEBUG1
|
||
BlPrint("E820: %lx %lx:%lx %lx:%lx %lx %lx\n",
|
||
Frame.Size,
|
||
Frame.Descriptor.BaseAddrHigh, Frame.Descriptor.BaseAddrLow,
|
||
Frame.Descriptor.SizeHigh, Frame.Descriptor.SizeLow,
|
||
Frame.Descriptor.MemoryType,
|
||
Frame.Key
|
||
);
|
||
|
||
_asm {
|
||
push ax
|
||
mov ax, 0
|
||
int 16h
|
||
pop ax
|
||
}
|
||
#endif
|
||
|
||
BAddr = Frame.Descriptor.BaseAddrLow;
|
||
EAddr = Frame.Descriptor.BaseAddrLow + Frame.Descriptor.SizeLow - 1;
|
||
|
||
//
|
||
// All the processors we have right now only support 32 bits
|
||
// If the upper 32 bits of the Base Address is non-zero, then
|
||
// this range is entirely above the 4g mark and can be ignored
|
||
//
|
||
|
||
if (Frame.Descriptor.BaseAddrHigh == 0) {
|
||
|
||
if (EAddr < BAddr) {
|
||
//
|
||
// address wrapped - truncate the Ending address to
|
||
// 32 bits of address space
|
||
//
|
||
|
||
EAddr = 0xFFFFFFFF;
|
||
}
|
||
|
||
//
|
||
// Based upon the address range descriptor type, find the
|
||
// available memory and add it to the descriptor list
|
||
//
|
||
|
||
switch (Frame.Descriptor.MemoryType) {
|
||
case 1:
|
||
//
|
||
// This is a memory descriptor
|
||
//
|
||
|
||
InsertDescriptor (BAddr, EAddr - BAddr + 1);
|
||
break;
|
||
}
|
||
}
|
||
|
||
} while (Frame.Key) ;
|
||
|
||
return TRUE;
|
||
}
|