You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
535 lines
14 KiB
535 lines
14 KiB
/*++
|
|
|
|
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;
|
|
}
|