Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1307 lines
37 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
abiosc.c
Abstract:
This module implements ABIOS support C routines for i386 NT.
Author:
Shie-Lin Tzong (shielint) 7-May-1991
Environment:
Boot loader privileged, FLAT mode.
Revision History:
--*/
#include <bootx86.h>
#include <memory.h>
#include <string.h>
#include "abios.h"
//
// NOTE The TYPE_CODE in ntos\inc\i386.h is incorrect for abios code
// segment. So, I define a correct value here.
//
#define ABIOS_TYPE_CODE 0x1a
extern UCHAR BootPartitionName[];
PCOMMON_DATA_AREA CommonDataArea = NULL;
static MACHINE_INFORMATION MachineInformation;
static USHORT NumberFreeSelectors;
static PFREE_GDT_ENTRY FreeGdtListHead;
static PFUNCTION_TRANSFER_TABLE FuncTransferTables;
static PUCHAR DeviceBlocks;
static USHORT CdaSize;
static USHORT FttsLength = 0;
static USHORT DeviceBlocksLength = 0;
static USHORT DataPointersLength = 0;
static PUCHAR RamExtension = NULL;
static ULONG GdtAddress;
VOID
ConvertFtt (
IN PFUNCTION_TRANSFER_TABLE FunctionTransferTable
);
BOOLEAN
LoadRamExtensions (
IN VOID
);
USHORT
AllocateGdtSelector (
VOID
);
USHORT
SearchGdtSelector (
IN ULONG BaseAddress,
IN USHORT Limit,
IN UCHAR Type
);
USHORT
MapVirtualAddress (
IN USHORT Selector,
IN ULONG BaseAddress,
IN BOOLEAN CodeSegment,
IN ULONG Length
);
ARC_STATUS
DetermineFileSize(
IN ULONG FileId,
OUT PULONG FileSize
)
/*++
Routine Description:
This routine determines the size of the specified file.
Arguments:
FileId - Supplies the file id. Caller must ensure the fileId
is opened for read (at least)
FileSize - Supplies a pointer to a variable which will receive
the length of the file.
Return Value:
Return the ARC_STATUS code.
--*/
{
ULONG Size;
ARC_STATUS Status;
UCHAR LocalBuffer[SECTOR_SIZE];
ULONG Count;
LARGE_INTEGER SeekPosition;
//
// Determine the length of the file by reading to the end of
// file.
//
Size = 0;
SeekPosition.QuadPart = 0;
Status = BlSeek(FileId,
&SeekPosition,
SeekAbsolute);
if (Status != ESUCCESS) {
return(Status);
}
do {
Status = BlRead(FileId, LocalBuffer, SECTOR_SIZE, &Count);
if (Status != ESUCCESS) {
return Status;
}
Size += Count;
} while (Count == SECTOR_SIZE);
SeekPosition.QuadPart = 0;
Status = BlSeek(FileId,
&SeekPosition,
SeekAbsolute);
*FileSize = Size;
return(Status);
}
BOOLEAN
LoadRamExtensions (
VOID
)
/*++
Routine Description:
This function loads ABIOS RAM extensions.
Arguments:
None.
Return Value:
TRUE - If the operation is success. Otherwise, a value of FALSE is
returned.
--*/
{
PCHAR AbiosSys = "\\ABIOS.SYS";
PCHAR Device80 = "multi(0)disk(0)rdisk(0)partition(1)";
PCHAR AbiosPartition;
PCHAR PatchFileList;
PCHAR PatchFileName, NextPatchFileName;
PRAM_EXTENSION_HEADER PatchFileHeader;
ULONG TotalPatchSize, FileSize, BytesRead;
ULONG DriveId, FileId;
ARC_STATUS Status;
PUCHAR PatchAddress;
BOOLEAN ReturnCode = TRUE;
AbiosPartition = BootPartitionName;
TryAgain:
//
// Open ABIOS.SYS. Allocate buffer to read in ABIOS.SYS.
// Allocate 512 bytes for patch file header.
//
Status = ArcOpen(AbiosPartition, ArcOpenReadOnly, &DriveId);
if (Status != ESUCCESS) {
// BlPrint("ABIOS: Couldn't open Boot Drive, status = %x\n", Status);
return(FALSE);
}
Status = BlOpen( DriveId,
AbiosSys,
ArcOpenReadOnly,
&FileId );
if (Status != ESUCCESS) {
if (strstr(AbiosPartition, "fdisk") != NULL) {
//
// Boot device is floppy. We need to try to read the abios.sys
// from c:.
//
AbiosPartition = Device80;
goto TryAgain;
} else {
goto CloseAndExit;
}
}
if ((Status = DetermineFileSize(FileId, &FileSize)) != ESUCCESS) {
BlPuts("ABIOS: Could not read ABIOS.sys\n");
BlClose(FileId);
ReturnCode = FALSE;
goto CloseAndExit;
}
PatchFileList = FwAllocateHeap(FileSize + 2);
PatchFileHeader = FwAllocateHeap(PATCH_FILE_BUFFER_SIZE);
if (PatchFileHeader == NULL || PatchFileList == NULL) {
BlClose(FileId);
BlPuts("ABIOS: Unable to allocate Heap for Patch.\n");
ReturnCode = FALSE;
goto CloseAndExit;
}
Status = BlRead(FileId,
PatchFileList,
FileSize,
&BytesRead
);
if (Status != ESUCCESS || BytesRead != FileSize) {
BlClose(FileId);
BlPuts("ABIOS: Error reading ABIOS.SYS.\n");
ReturnCode = FALSE;
goto CloseAndExit;
}
*(PatchFileList + FileSize) = END_OF_FILE;
*(PatchFileList + FileSize + 1) = END_OF_FILE;
BlClose(FileId); // Close ABIOS.SYS
//
// For each patch file listed in the abios.sys, we read in its
// patch header (first 512 bytes) and examine if we should load
// this patch. At the end of the loop, we will be able to know
// the global size of the ABIOS extension required.
//
TotalPatchSize = PATCH_FILE_HEADER_SIZE; // For the Last empty header
//
// Scan the name buffer; skip all the blacks, LFs, CRs and zeros.
//
while (*PatchFileList == LINE_FEED ||
*PatchFileList == CARRAGE_RETURN ||
*PatchFileList == ' ' ||
*PatchFileList == '\t' ||
*PatchFileList == 0) {
PatchFileList++;
}
NextPatchFileName = PatchFileList;
while (*NextPatchFileName != END_OF_FILE) {
PatchFileName = NextPatchFileName;
while (*NextPatchFileName != LINE_FEED &&
*NextPatchFileName != CARRAGE_RETURN &&
*NextPatchFileName != 0 &&
*NextPatchFileName != '\t' &&
*NextPatchFileName != ' ') {
NextPatchFileName++;
}
*NextPatchFileName++ = 0; // make ASCIIZ filename
if ((Status = BlOpen(DriveId, PatchFileName, ArcOpenReadOnly, &FileId))
== ESUCCESS) {
Status = DetermineFileSize(FileId, &FileSize);
if (Status == ESUCCESS) {
Status = BlRead(FileId,
(PUCHAR)PatchFileHeader,
PATCH_FILE_BUFFER_SIZE,
&BytesRead
);
if (Status == ESUCCESS &&
(BytesRead == PATCH_FILE_BUFFER_SIZE ||BytesRead == FileSize)) {
//
// Make sure the patch is for this particular machine.
//
if ((PatchFileHeader->Signature == PATCH_SIGNATURE) &&
(PatchFileHeader->Model == MachineInformation.Model ||
PatchFileHeader->Model == 0 ) &&
(PatchFileHeader->Submodel == MachineInformation.Submodel ||
PatchFileHeader->Submodel == 0) &&
(PatchFileHeader->RomRevision == MachineInformation.BiosRevision ||
PatchFileHeader->RomRevision == 0)) {
TotalPatchSize += (ULONG)PatchFileHeader->NumberBlocks * SECTOR_SIZE;
} else {
Status = ESUCCESS + 1;
}
} else {
Status = ESUCCESS + 1;
}
}
BlClose(FileId);
}
//
// If fails, remove the name from our patch file list.
//
if (Status != ESUCCESS) {
while (*PatchFileName != 0) {
*PatchFileName++= 0;
}
}
while (*NextPatchFileName == LINE_FEED ||
*NextPatchFileName == CARRAGE_RETURN ||
*NextPatchFileName == ' ' ||
*NextPatchFileName == '\t' ||
*NextPatchFileName == 0) {
NextPatchFileName++;
}
}
//
// If No Ram Extension To load, simply return.
//
if (TotalPatchSize == PATCH_FILE_HEADER_SIZE) {
goto CloseAndExit;
}
//
// Allocate permanent memory for RAM Extension.
//
// NOTE: The RamExtension memory MUST be identity mapped, i.e.
// Virtual address == Physical Address
//
RamExtension = (PUCHAR)FwAllocateHeapPermanent(
ROUND_UP(TotalPatchSize, PAGE_SIZE) >> PAGE_SHIFT
);
if (!RamExtension) {
BlPuts("ABIOS: Not enough memory for RAM extensions\n");
ReturnCode = FALSE;
goto CloseAndExit;
}
//
// Read in the patch files in the order in which they are listed in
// the ABIOS.SYS
//
NextPatchFileName = PatchFileList;
PatchAddress = RamExtension;
while (*NextPatchFileName != END_OF_FILE) {
PatchFileName = NextPatchFileName;
//
// Move next patch file pointer to the end of current file name
//
while (*NextPatchFileName != 0) {
NextPatchFileName++;
}
if ((Status = BlOpen(DriveId, PatchFileName, ArcOpenReadOnly, &FileId))
== ESUCCESS) {
Status = DetermineFileSize(FileId, &FileSize);
if (Status == ESUCCESS) {
Status = BlRead(FileId,
PatchAddress,
FileSize,
&BytesRead
);
}
if (Status == ESUCCESS && BytesRead == FileSize) {
PatchAddress += FileSize;
}
BlClose(FileId);
}
//
// Skip leading garbage.
//
while (*NextPatchFileName == LINE_FEED ||
*NextPatchFileName == CARRAGE_RETURN ||
*NextPatchFileName == ' ' ||
*NextPatchFileName == '\t' ||
*NextPatchFileName == 0) {
NextPatchFileName++;
}
}
//
// Create an empty RAM extension header to serve as the end patch.
//
((PRAM_EXTENSION_HEADER)PatchAddress)->Signature = PATCH_SIGNATURE;
((PRAM_EXTENSION_HEADER)PatchAddress)->NumberBlocks = 0;
CloseAndExit:
BlClose(FileId);
return ReturnCode;
}
BOOLEAN
AbiosBuildRealModeCda (
IN USHORT NumberInitTableEntries,
IN PINIT_TABLE_ENTRY InitializationTable
)
/*++
Routine Description:
This function builds Real Mode ABIOS Common Data Area. It computes
the sizes of CDA, Function transfer tables, and Device Blocks. Memory
is then allocated for these tables. ABIOS Device Block and Ftt
initialization routines are invoked to do the actual work.
Arguments:
NumberInitTableEntry - Supplies the number of Init Table Entries.
InitializationTable - Supplies the pointer to Initialization Table.
Return Value:
TRUE - If the operation is success. Otherwise, a value of FALSE is
returned.
--*/
{
USHORT i;
PINIT_TABLE_ENTRY InitTableEntry;
USHORT NumberLids = 2; // includes Lid 0 and 1
PUCHAR FuncTransferTable;
PUCHAR DeviceBlock;
USHORT DeviceCount;
PDB_FTT_SECTION CdaPointer;
USHORT StartingLid;
BOOLEAN Success;
//
// Determine the sizes of Common Data Area, FTTs, Device Blocks
// Device Blocks are aligned on double word boundary.
//
InitTableEntry = InitializationTable;
for (i = 1; i <= NumberInitTableEntries; i++) {
NumberLids += InitTableEntry->NumberLids;
DeviceBlocksLength += ((InitTableEntry->DeviceBlockLength + 3) & ~3) *
InitTableEntry->NumberLids;
FttsLength += (InitTableEntry->FttLength + 3) & ~3;
DataPointersLength += InitTableEntry->DataPointerLength;
InitTableEntry++;
}
CdaSize = (USHORT)(NumberLids * 2 * sizeof(ULONG) + DataPointersLength + 2);
//
// Allocate memory blocks for Common Data Area, Function Transfer Tables,
// and Device Blocks. Then, we zero initialize common data area.
//
CommonDataArea = (PCOMMON_DATA_AREA)FwAllocateHeapPermanent(
ROUND_UP(CdaSize, PAGE_SIZE) >> PAGE_SHIFT
);
if (!CommonDataArea) {
BlPuts("ABIOS: Unable to allocate memory for Common Data Area.\n");
return FALSE;
}
FuncTransferTables = (PFUNCTION_TRANSFER_TABLE)FwAllocateHeapPermanent(
ROUND_UP(FttsLength, PAGE_SIZE) >> PAGE_SHIFT
);
if (!FuncTransferTables) {
BlPuts("ABIOS: Unable to allocate memory for Function Transfer tables.\n");
return FALSE;
}
DeviceBlocks = (PUCHAR)FwAllocateHeapPermanent(
ROUND_UP(DeviceBlocksLength, PAGE_SIZE) >> PAGE_SHIFT
);
if (!DeviceBlocks) {
BlPuts("ABIOS: Unable to allocate memory for Device Blocks.\n");
return FALSE;
}
memset((PVOID)CommonDataArea, 0, ROUND_UP(CdaSize, PAGE_SIZE));
//
// For each entry of Initialization table, we set up device blocks and
// function transfer table pointers in the CDA. Note, the initialization
// loop starts from logical id 2.
//
CommonDataArea->DataPointer0Offset = CdaSize - (USHORT)8;
CommonDataArea->NumberLids = NumberLids;
CdaPointer = (PDB_FTT_SECTION)&CommonDataArea->DbFttPointer + 1;
InitTableEntry = InitializationTable;
FuncTransferTable = (PUCHAR)FuncTransferTables;
DeviceBlock = DeviceBlocks;
for (i = 1; i <= NumberInitTableEntries; i++) {
DeviceCount = InitTableEntry->NumberLids;
while (DeviceCount != 0) {
//
// Each Lid of the same IT entry needs individual device block but
// is operated by the same Ftt.
//
if (InitTableEntry->FttLength) {
CdaPointer->FttPointer.LowPart =
LOWWORD(FuncTransferTable);
CdaPointer->FttPointer.HighPart.Segment =
HIGHWORD(FuncTransferTable) << 12;
}
if (InitTableEntry->DeviceBlockLength) {
CdaPointer->DeviceBlockPointer.LowPart =
LOWWORD(DeviceBlock);
CdaPointer->DeviceBlockPointer.HighPart.Segment =
HIGHWORD(DeviceBlock) << 12;
DeviceBlock += (InitTableEntry->DeviceBlockLength + 3 ) & ~3;
}
DeviceCount--;
CdaPointer++;
}
FuncTransferTable += (InitTableEntry->FttLength + 3) & ~3;
InitTableEntry++;
}
//
// Now switch to real mode and for each entry of Initialization Table,
// the corresponding DeviceBlock and Function transfer table initialization
// routine is called to initialize Device blocks and FTT.
//
CdaPointer = (PDB_FTT_SECTION)&CommonDataArea->DbFttPointer + 1;
InitTableEntry = InitializationTable;
StartingLid = 2;
for (i = 1; i <= NumberInitTableEntries; i++) {
Success = (BOOLEAN)ABIOS_SERVICES(
ABIOS_SERVICE_INIT_DB_FTT,
(PUCHAR)CommonDataArea,
NULL,
NULL,
(PUCHAR)InitTableEntry->InitializeRoutine,
StartingLid,
InitTableEntry->NumberLids
);
//
// If initialization of the device fails, we need to invalidate
// the device block and function transfer table pointers.
//
if (!Success) {
DeviceCount = InitTableEntry->NumberLids;
while (DeviceCount != 0) {
//
// Each Lid of the same IT entry needs individual device
// block but is operated by the same Ftt.
//
CdaPointer->FttPointer.LowPart = 0;
CdaPointer->FttPointer.HighPart.Segment = 0;
CdaPointer->DeviceBlockPointer.LowPart = 0;
CdaPointer->DeviceBlockPointer.HighPart.Segment = 0;
CdaPointer++;
DeviceCount--;
}
}
StartingLid += InitTableEntry->NumberLids;
CdaPointer += InitTableEntry->NumberLids;
InitTableEntry++;
}
}
BOOLEAN
AbiosBuildProtectedModeCda (
IN PINIT_TABLE_ENTRY InitializationTable
)
/*++
Routine Description:
This function builds protected Mode ABIOS Common Data Area. Basically,
this routine simply converts the real mode addresses in the real mode
Commom Data Area to protected mode addresses. To do this, the following
steps are performed:
. Convert each real mode device block pointer to a protected mode device
block pointer.
. Convert each real mode function transfer table pointer to a protected
mode function transfer table pointer.
. Convert each real mode function pointer within each real mode function
transfer table to a protected mode function pointer.
. Convert each real mode data pointer to a protected mode data pointer.
Arguments:
InitializationTable - supplies a pointer to Initialization Table
Return Value:
TRUE - If the operation is success. Otherwise, a value of FALSE is
returned.
--*/
{
PDB_FTT_SECTION CdaPointer;
USHORT FttLength, DbLength;
USHORT FttSelector, DbSelector, DpSelector;
ULONG FttSelectorBase, DbSelectorBase;
PINIT_TABLE_ENTRY InitTableEntry;
USHORT CurrentLid = 2, NewItEntryLid;
USHORT NumberDataPointers, i;
PDATA_POINTER_SECTION CurrentDataPointer;
ULONG TablePointer;
BOOLEAN InitializeFtt = TRUE;
CdaPointer = (PDB_FTT_SECTION)((ULONG)CommonDataArea +
2 * sizeof(DB_FTT_SECTION));
InitTableEntry = InitializationTable;
FttSelectorBase = (ULONG)FuncTransferTables;
DbSelectorBase = (ULONG)DeviceBlocks;
FttSelector = AllocateGdtSelector();
DbSelector = AllocateGdtSelector();
NewItEntryLid = CurrentLid + InitTableEntry->NumberLids;
while (CurrentLid < CommonDataArea->NumberLids) {
//
// Convert the Function Transfer Table pointers in CDA and then
// convert each routine pointer in Function transfer table.
//
TablePointer = ((ULONG)CdaPointer->FttPointer.HighPart.Segment << 4) |
(ULONG)CdaPointer->FttPointer.LowPart;
if (TablePointer) {
//
// If the current table accross 64K, we need to have a new
// selector for it.
//
if (TablePointer - FttSelectorBase > 64 * 1024) {
FttSelector = MapVirtualAddress(FttSelector,
FttSelectorBase,
FALSE,
(ULONG)FttLength
);
if (FttSelector == 0) {
return FALSE;
}
CdaPointer->FttPointer.LowPart = 0;
FttsLength -= FttLength;
FttSelector = AllocateGdtSelector();
FttSelectorBase = TablePointer;
} else {
CdaPointer->FttPointer.LowPart =
(USHORT)(TablePointer - FttSelectorBase);
FttLength = (USHORT)(TablePointer - FttSelectorBase);
if (CurrentLid == CommonDataArea->NumberLids - (USHORT)1) {
FttSelector = MapVirtualAddress(FttSelector,
FttSelectorBase,
FALSE,
(ULONG)FttsLength
);
FttLength = 0;
}
}
CdaPointer->FttPointer.HighPart.Selector = FttSelector;
if (InitializeFtt) {
ConvertFtt((PFUNCTION_TRANSFER_TABLE)TablePointer);
InitializeFtt = FALSE;
}
}
//
// Convert the Device Block pointers in CDA.
//
TablePointer = ((ULONG)CdaPointer->DeviceBlockPointer.HighPart.Segment << 4) |
(ULONG)CdaPointer->DeviceBlockPointer.LowPart;
if (TablePointer) {
//
// If the current table accross 64K, we need to have a new
// selector for it.
//
if (TablePointer - DbSelectorBase > 64 * 1024) {
DbSelector = MapVirtualAddress(DbSelector,
DbSelectorBase,
FALSE,
(ULONG)DbLength
);
if (DbSelector == 0) {
return FALSE;
}
CdaPointer->DeviceBlockPointer.LowPart = 0;
DeviceBlocksLength -= DbLength;
DbSelector = AllocateGdtSelector();
DbSelectorBase = TablePointer;
} else {
CdaPointer->DeviceBlockPointer.LowPart =
(USHORT)(TablePointer - DbSelectorBase);
DbLength = (USHORT)(TablePointer - DbSelectorBase);
if (CurrentLid == CommonDataArea->NumberLids - (USHORT)1) {
DbSelector = MapVirtualAddress(DbSelector,
DbSelectorBase,
FALSE,
(ULONG)DeviceBlocksLength
);
DeviceBlocksLength = 0;
}
}
CdaPointer->DeviceBlockPointer.HighPart.Selector = DbSelector;
}
CdaPointer++;
CurrentLid++;
if (CurrentLid == NewItEntryLid) {
InitTableEntry++;
NewItEntryLid += InitTableEntry->NumberLids;
InitializeFtt = TRUE;
}
}
//
// Now check if any part of Function transfer table or Debice block
// need to be mapped.
//
if (FttsLength) {
FttSelector = MapVirtualAddress(FttSelector,
FttSelectorBase,
FALSE,
(ULONG)FttsLength
);
}
if (DeviceBlocksLength) {
DbSelector = MapVirtualAddress(DbSelector,
DbSelectorBase,
FALSE,
(ULONG)DeviceBlocksLength
);
}
//
// Convert each Data pointer in RealMode CDA to protected mode pointer
//
CurrentDataPointer = (PDATA_POINTER_SECTION)((ULONG)CommonDataArea +
CommonDataArea->DataPointer0Offset);
NumberDataPointers = *(PUSHORT)((ULONG)CurrentDataPointer +
sizeof(DATA_POINTER_SECTION));
for (i = 1; i <= NumberDataPointers; i++) {
DpSelector = MapVirtualAddress(
(USHORT)0,
(ULONG)CurrentDataPointer->DataPointer.PhysicalPointer,
FALSE,
(ULONG)ROUND_UP(CurrentDataPointer->DataPointerLimit + 1, PAGE_SIZE)
);
CurrentDataPointer->DataPointer.VirtualPointer.LowPart = 0;
CurrentDataPointer->DataPointer.VirtualPointer.HighPart.Selector =
DpSelector;
CurrentDataPointer--;
}
}
VOID
ConvertFtt (
IN PFUNCTION_TRANSFER_TABLE FunctionTransferTable
)
/*++
Routine Description:
This function goes through each entry of Function Transfer Table
to convert the real mode pointer to protected mode pointer.
Arguments:
FunctionTransferTable - supplies a pointer to the function transfer
table to be converted.
Return Value:
None.
--*/
{
PULONG FttEntry;
ULONG RoutinePointer;
PRAM_EXTENSION_HEADER RamHeader;
USHORT i, Selector;
//
// Convert the Start, Interrupt and Timeout routine pointers to
// protected mode addresses.
//
for (i = 0; i < 3; i++) {
RoutinePointer = FunctionTransferTable->CommonRoutine[i];
if (RoutinePointer != 0L) {
RamHeader = (PRAM_EXTENSION_HEADER)((RoutinePointer >> 16) << 4);
if (RamHeader->Signature == PATCH_SIGNATURE) {
Selector = SearchGdtSelector(
(ULONG)RamHeader,
(USHORT)(RamHeader->NumberBlocks * 512 - 1),
(UCHAR)ABIOS_TYPE_CODE
);
if (Selector == 0) {
Selector = MapVirtualAddress(
0,
(ULONG)RamHeader,
TRUE,
(ULONG)(RamHeader->NumberBlocks * 512)
);
}
} else {
Selector = SearchGdtSelector((ULONG)RamHeader,
(USHORT)(64 * 1024 - 1),
(UCHAR)ABIOS_TYPE_CODE
);
if (Selector == 0) {
Selector = MapVirtualAddress(
0,
(ULONG)RamHeader,
TRUE,
(ULONG)(64 * 1024)
);
}
}
FunctionTransferTable->CommonRoutine[i] = ((ULONG)Selector << 16) |
(ULONG)(LOWWORD(FunctionTransferTable->CommonRoutine[i]));
}
}
//
// Convert Device Specific routine pointers to protected mode addresses.
//
FttEntry = &FunctionTransferTable->SpecificRoutine;
for (i = 0; i < FunctionTransferTable->FunctionCount; i++) {
RoutinePointer = *FttEntry;
if (RoutinePointer != 0L) {
RamHeader = (PRAM_EXTENSION_HEADER)((RoutinePointer >> 16) << 4);
if (RamHeader->Signature == PATCH_SIGNATURE) {
Selector = SearchGdtSelector((ULONG)RamHeader,
(USHORT)(RamHeader->NumberBlocks * 512 - 1),
(UCHAR)ABIOS_TYPE_CODE
);
if (Selector == 0) {
Selector = MapVirtualAddress(
0,
(ULONG)RamHeader,
TRUE,
(ULONG)(RamHeader->NumberBlocks * 512) );
}
} else {
Selector = SearchGdtSelector((ULONG)RamHeader,
(USHORT)(64 * 1024 - 1),
(UCHAR)ABIOS_TYPE_CODE
);
if (Selector == 0) {
Selector = MapVirtualAddress(
0,
(ULONG)RamHeader,
TRUE,
(ULONG)(64 * 1024)
);
}
}
*FttEntry = ((ULONG)Selector << 16) | (ULONG)(LOWWORD(*FttEntry));
}
FttEntry++;
}
}
VOID
InitializeGdtFreeList (
VOID
)
/*++
Routine Description:
This function initializes gdt free list by linking all the unused gdt
entries to a free list.
Arguments:
None.
Return Value:
None.
--*/
{
#pragma pack(2)
static struct {
USHORT Limit;
ULONG Base;
} GdtDef;
#pragma pack(4)
PFREE_GDT_ENTRY GdtEntry;
//
// Get the current location of the GDT
//
_asm {
sgdt GdtDef;
}
GdtAddress = GdtDef.Base;
NumberFreeSelectors = 0;
GdtEntry = (PFREE_GDT_ENTRY)(GdtAddress + GdtDef.Limit + 1 -
sizeof(FREE_GDT_ENTRY));
FreeGdtListHead = (PFREE_GDT_ENTRY)0;
while ((ULONG)GdtEntry >= GdtAddress + ABIOS_GDT_SELECTOR_START) {
if (GdtEntry->Present == 0) {
GdtEntry->Flink = FreeGdtListHead;
FreeGdtListHead = GdtEntry;
NumberFreeSelectors++;
}
GdtEntry--;
}
}
USHORT
AllocateGdtSelector (
VOID
)
/*++
Routine Description:
This function allocates a gdt selector from GDT.
Arguments:
None.
Return Value:
A Gdt selector is returned if success. Otherwise, a value of 0 is
returned. (Zero is an invalid selector.)
--*/
{
PFREE_GDT_ENTRY GdtEntry;
if (NumberFreeSelectors) {
GdtEntry = FreeGdtListHead;
FreeGdtListHead = GdtEntry->Flink;
NumberFreeSelectors--;
return (USHORT)((ULONG)GdtEntry - GdtAddress);
} else {
BlPuts("ABIOS: Out of Gdt Selector.\n");
return 0;
}
}
USHORT
SearchGdtSelector (
IN ULONG BaseAddress,
IN USHORT Limit,
IN UCHAR Type
)
/*++
Routine Description:
This function searches the gdt table for the Gdt selector entry which
has the base address and limit caller specified.
N.B. This routine handles 16 bit code and data selectors ONLY, i.e.,
the limit is always less than 64k. The search ends at the head
of free Gdt list. So, this is not GENERAL PURPOSE Gdt selector
search routine.
Arguments:
BaseAddress - the base address of the desired Gdt Selector.
Limit - The Limit of the desired Gdt Selector.
Type - Code or Data selector
Return Value:
A Gdt selector is returned if sguccess. Otherwise, a value of 0 is
returned. (Zero is an invalid selector.)
--*/
{
PKGDTENTRY GdtEntry;
ULONG SelectorBase;
GdtEntry = (PKGDTENTRY)(GdtAddress + ABIOS_GDT_SELECTOR_START);
while (GdtEntry != (PKGDTENTRY)FreeGdtListHead) {
if (GdtEntry->HighWord.Bits.Pres != 0 &&
GdtEntry->HighWord.Bits.LimitHi == 0 &&
GdtEntry->LimitLow == Limit &&
GdtEntry->HighWord.Bits.Type == Type) {
SelectorBase = (ULONG)GdtEntry->BaseLow |
(ULONG)GdtEntry->HighWord.Bytes.BaseMid << 16 |
(ULONG)GdtEntry->HighWord.Bytes.BaseHi << 24;
if (BaseAddress == SelectorBase) {
return (USHORT)((ULONG)GdtEntry - GdtAddress);
}
}
GdtEntry++;
}
return 0;
}
USHORT
MapVirtualAddress (
IN USHORT Selector,
IN ULONG BaseAddress,
IN BOOLEAN CodeSegment,
IN ULONG Length
)
/*++
Routine Description:
This function allocates a gdt selector, if necessary, and map the
specified area to the gdt selector.
Arguments:
Selector - Supplies a Gdt selector to set up the mapping. If 0, caller
does not supply the selector. this routine will allocate one.
BaseAddress - Base address of the Gdt selector.
CodeSegment - Indicates if this is for a code segment.
Length - the length of the area to be mapped.
Return Value:
ReturnedSelector - If the operation is success. Otherwise, a value of 0
is returned.
--*/
{
PKGDTENTRY GdtEntry;
USHORT ReturnedSelector;
if (Selector == 0) {
if ((ReturnedSelector = AllocateGdtSelector()) == 0) {
return 0;
}
} else {
ReturnedSelector = Selector;
}
GdtEntry = (PKGDTENTRY)(GdtAddress + ReturnedSelector);
GdtEntry->LimitLow = (USHORT)(Length - 1L);
GdtEntry->BaseLow = LOWWORD(BaseAddress);
GdtEntry->HighWord.Bytes.BaseMid = LOWBYTE(HIGHWORD(BaseAddress));
GdtEntry->HighWord.Bytes.BaseHi = HIGHBYTE(HIGHWORD(BaseAddress));
if (CodeSegment) {
GdtEntry->HighWord.Bits.Type = ABIOS_TYPE_CODE;
} else {
GdtEntry->HighWord.Bits.Type = TYPE_DATA;
}
GdtEntry->HighWord.Bits.Pres = 1;
GdtEntry->HighWord.Bits.Dpl = DPL_SYSTEM;
return ReturnedSelector;
}
VOID
RemapAbiosSelectors (
VOID
)
/*++
Routine Description:
This function goes thru each ABIOS specific GDT entry, allocates
virtual memory and remaps the GDT entry to the newly allocated
virtual address.
Arguments:
None.
Return Value:
None.
--*/
{
PKGDTENTRY GdtEntry;
ULONG Size;
ULONG SelectorBase;
GdtEntry = (PKGDTENTRY)(GdtAddress + ABIOS_GDT_SELECTOR_START);
while (GdtEntry != (PKGDTENTRY)FreeGdtListHead) {
if (GdtEntry->HighWord.Bits.Pres == 1 ) {
Size = ((ULONG)GdtEntry->LimitLow & 0xffff) |
((ULONG)(GdtEntry->HighWord.Bits.LimitHi << 16) & 0xf0000);
SelectorBase = ((ULONG)GdtEntry->BaseLow & 0xffff) |
((ULONG)GdtEntry->HighWord.Bytes.BaseMid << 16 ) |
((ULONG)GdtEntry->HighWord.Bytes.BaseHi << 24);
SelectorBase |= KSEG0_BASE;
GdtEntry->BaseLow = (USHORT)(SelectorBase & 0xffff);
GdtEntry->HighWord.Bytes.BaseMid =
(UCHAR)((SelectorBase & 0xff0000) >> 16);
GdtEntry->HighWord.Bytes.BaseHi =
(UCHAR)((SelectorBase & 0xff000000) >> 24);
}
GdtEntry++;
}
CommonDataArea = (PCOMMON_DATA_AREA)((ULONG)CommonDataArea | KSEG0_BASE);
}
VOID
AbiosInitDataStructures (
VOID
)
/*++
Routine Description:
This function performs ABIOS initialization by invoking ABIOS external
service routines to do real mode initialization and finally converting
real mode Common Data Area to protected mode Common Data Area.
Arguments:
None.
Return Value:
None.
--*/
{
BOOLEAN Success;
USHORT NumberInitTableEntries;
PINIT_TABLE_ENTRY InitializationTable;
ULONG TempULong;
//
// Initialize CommonDataArea to NULL
//
CommonDataArea = NULL;
if (MachineType != MACHINE_TYPE_MCA) {
return;
}
//
// Try to collect machine model, submodel
// and Bios revision such that we can check the validity of Ram
// Extensions.
//
TempULong = ABIOS_SERVICES(
ABIOS_SERVICE_MACHINE_INFOR,
NULL,
NULL,
NULL,
NULL,
0,
0
);
MachineInformation = *(PMACHINE_INFORMATION)&TempULong;
if (MachineInformation.Valid == FALSE) {
BlPuts("ABIOS: Can not identify machine model, BIOS revision.\n");
} else {
//
// Load RAM Extensions.
//
LoadRamExtensions();
}
//
// Initialize System Parameter Table to get number of initialization
// table entries.
//
NumberInitTableEntries = (USHORT)ABIOS_SERVICES (
ABIOS_SERVICE_INITIALIZE_SPT,
NULL,
NULL,
RamExtension,
NULL,
0,
0
);
if (NumberInitTableEntries == 0) {
return;
}
//
// Allocate Initialization Table memory and build ABIOS Initialization
// Table.
//
InitializationTable = (PINIT_TABLE_ENTRY)FwAllocateHeap(NumberInitTableEntries *
INITIALIZATION_TABLE_ENTRY_SIZE);
Success = (BOOLEAN)ABIOS_SERVICES (ABIOS_SERVICE_BUILD_IT,
NULL,
(PUCHAR)InitializationTable,
RamExtension,
NULL,
0,
0
);
if (!Success) {
// BlPuts("ABIOS: cannot build Initialization Table.\n");
return;
}
//
// Build Real mode ABIOS Common Data Area, Device Blocks and Function
// transfer tables.
//
Success = AbiosBuildRealModeCda (NumberInitTableEntries,
InitializationTable
);
if (!Success) {
BlPuts("ABIOS: cannot build real mode Common Data Area.\n");
return;
}
//
// Before initializing protected mode Common Data Area, we need to
// set up the free gdt selector list.
//
InitializeGdtFreeList();
//
// Build protected mode ABIOS Common Data Area and free Initialization
// Table Space.
//
Success = AbiosBuildProtectedModeCda(InitializationTable);
if (!Success) {
BlPuts("ABIOS: cannot build protected mode Common Data Area.\n");
return;
}
}