windows-nt/Source/XPSP1/NT/base/boot/startrom/i386/eisac.c
2020-09-26 16:20:57 +08:00

536 lines
14 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}