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