856 lines
26 KiB
C
856 lines
26 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
Copyright (c) 1992 Digital Equipment Corporation
|
||
|
||
Module Name:
|
||
|
||
ntsetup.c
|
||
|
||
Abstract:
|
||
|
||
This module is the tail-end of the OS loader program. It performs all
|
||
ALPHA AXP specific allocations and initialize. The OS loader invokes this
|
||
this routine immediately before calling the loaded kernel image.
|
||
|
||
Author:
|
||
|
||
John Vert (jvert) 20-Jun-1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
John DeRosa [DEC] 22-Apr-1993
|
||
|
||
Added code to remove extra ScsiAdapter node from ARC configuration
|
||
tree.
|
||
|
||
Rod Gamache [DEC] 24-Sep-1992
|
||
|
||
Add Alpha AXP hooks.
|
||
--*/
|
||
|
||
#include "bldr.h"
|
||
#include "arc.h"
|
||
#include "fwcallbk.h"
|
||
#include "stdio.h"
|
||
|
||
#define chartoi(x) \
|
||
isalnum(x) ? ( ((x) >= '0') && ((x) <= '9') ? (x) - '0' : \
|
||
tolower((x)) - 'a' + 10 ) : 0
|
||
|
||
|
||
//
|
||
// Define macro to round structure size to next 16-byte boundary
|
||
//
|
||
|
||
#define ROUND_UP(x) ((sizeof(x) + 15) & (~15))
|
||
|
||
|
||
//
|
||
// Configuration Data Header
|
||
// The following structure is copied from fw\mips\oli2msft.h
|
||
// NOTE shielint - Somehow, this structure got incorporated into
|
||
// firmware EISA configuration data. We need to know the size of the
|
||
// header and remove it before writing eisa configuration data to
|
||
// registry.
|
||
//
|
||
|
||
typedef struct _CONFIGURATION_DATA_HEADER {
|
||
USHORT Version;
|
||
USHORT Revision;
|
||
PCHAR Type;
|
||
PCHAR Vendor;
|
||
PCHAR ProductName;
|
||
PCHAR SerialNumber;
|
||
} CONFIGURATION_DATA_HEADER;
|
||
|
||
#define CONFIGURATION_DATA_HEADER_SIZE sizeof(CONFIGURATION_DATA_HEADER)
|
||
|
||
//
|
||
// Internal function references
|
||
//
|
||
|
||
ARC_STATUS
|
||
ReorganizeEisaConfigurationTree(
|
||
IN PCONFIGURATION_COMPONENT_DATA RootEntry
|
||
);
|
||
|
||
ARC_STATUS
|
||
CreateEisaConfigurationData (
|
||
IN PCONFIGURATION_COMPONENT_DATA RootEntry,
|
||
OUT PULONG FloppyControllerNode
|
||
);
|
||
|
||
ARC_STATUS
|
||
BlAllocateAnyMemory (
|
||
IN TYPE_OF_MEMORY MemoryType,
|
||
IN ULONG BasePage,
|
||
IN ULONG PageCount,
|
||
OUT PULONG ActualBase
|
||
);
|
||
|
||
|
||
ARC_STATUS
|
||
BlSetupForNt(
|
||
IN PLOADER_PARAMETER_BLOCK BlLoaderBlock
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the MIPS specific kernel data structures
|
||
required by the NT system.
|
||
|
||
Arguments:
|
||
|
||
BlLoaderBlock - Supplies the address of the loader parameter block.
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS is returned if the setup is successfully complete. Otherwise,
|
||
an unsuccessful status is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PCONFIGURATION_COMPONENT_DATA ConfigEntry;
|
||
ULONG KernelPage;
|
||
ULONG LinesPerBlock;
|
||
ULONG LineSize;
|
||
ARC_STATUS Status;
|
||
EXTENDED_SYSTEM_INFORMATION SystemInfo;
|
||
ULONG FirmwareMajorVersion;
|
||
ULONG FirmwareMinorVersion;
|
||
CHAR SystemIdName[32] = "";
|
||
PCHAR SystemId;
|
||
PCONFIGURATION_COMPONENT ComponentInfo;
|
||
|
||
//
|
||
// Find the System Class component in the ARC Component Database to get
|
||
// our System Id.
|
||
//
|
||
|
||
ComponentInfo = ArcGetChild(NULL); // Get ARC component info
|
||
|
||
while (ComponentInfo != NULL) {
|
||
|
||
if ( ComponentInfo->Class == SystemClass &&
|
||
ComponentInfo->Identifier != NULL) {
|
||
|
||
strncat(SystemIdName, ComponentInfo->Identifier, 31);
|
||
break;
|
||
|
||
} else {
|
||
|
||
ComponentInfo = ArcGetPeer(ComponentInfo); // Look through all entries
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// The SystemIdName should be of the form: mmm-vrName, where
|
||
// mmm - is the manufacturer
|
||
// v - is the system variation
|
||
// r - is the system revision
|
||
// Name - is the system name
|
||
//
|
||
|
||
SystemId = strchr(SystemIdName, '-');
|
||
SystemIdName[0] = '\0';
|
||
|
||
if ( SystemId ) {
|
||
SystemId++; // Skip '-'
|
||
strncat(SystemIdName, SystemId, 31); // Save System Name
|
||
}
|
||
|
||
// Find System entry and check each of its direct child to
|
||
// look for EisaAdapter.
|
||
//
|
||
|
||
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
|
||
SystemClass,
|
||
ArcSystem,
|
||
NULL);
|
||
if (ConfigEntry) {
|
||
ConfigEntry = ConfigEntry->Child;
|
||
}
|
||
|
||
while (ConfigEntry) {
|
||
|
||
if ((ConfigEntry->ComponentEntry.Class == AdapterClass) &&
|
||
(ConfigEntry->ComponentEntry.Type == EisaAdapter)) {
|
||
|
||
//
|
||
// Convert EISA format configuration data to our CM_ format.
|
||
//
|
||
|
||
Status = ReorganizeEisaConfigurationTree(ConfigEntry);
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
}
|
||
ConfigEntry = ConfigEntry->Sibling;
|
||
}
|
||
|
||
//
|
||
// Find the primary data and instruction cache configuration entries, and
|
||
// compute the fill size and cache size for each cache. These entries MUST
|
||
// be present on all ARC compliant systems.
|
||
//
|
||
|
||
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
|
||
CacheClass,
|
||
PrimaryDcache,
|
||
NULL);
|
||
|
||
if (ConfigEntry != NULL) {
|
||
LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
|
||
LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
|
||
BlLoaderBlock->u.Alpha.FirstLevelDcacheFillSize = LinesPerBlock * LineSize;
|
||
BlLoaderBlock->u.Alpha.FirstLevelDcacheSize =
|
||
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
|
||
|
||
} else {
|
||
return EINVAL;
|
||
}
|
||
|
||
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
|
||
CacheClass,
|
||
PrimaryIcache,
|
||
NULL);
|
||
|
||
if (ConfigEntry != NULL) {
|
||
LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
|
||
LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
|
||
BlLoaderBlock->u.Alpha.FirstLevelIcacheFillSize = LinesPerBlock * LineSize;
|
||
BlLoaderBlock->u.Alpha.FirstLevelIcacheSize =
|
||
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
|
||
|
||
} else {
|
||
return EINVAL;
|
||
}
|
||
|
||
//
|
||
// Find the secondary data and instruction cache configuration entries,
|
||
// and if present, compute the fill size and cache size for each cache.
|
||
// These entries are optional, and may or may not, be present.
|
||
//
|
||
|
||
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
|
||
CacheClass,
|
||
SecondaryCache,
|
||
NULL);
|
||
|
||
if (ConfigEntry != NULL) {
|
||
LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
|
||
LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
|
||
BlLoaderBlock->u.Alpha.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
|
||
BlLoaderBlock->u.Alpha.SecondLevelDcacheSize =
|
||
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
|
||
|
||
BlLoaderBlock->u.Alpha.SecondLevelIcacheSize = 0;
|
||
BlLoaderBlock->u.Alpha.SecondLevelIcacheFillSize = 0;
|
||
|
||
} else {
|
||
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
|
||
CacheClass,
|
||
SecondaryDcache,
|
||
NULL);
|
||
|
||
if (ConfigEntry != NULL) {
|
||
LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
|
||
LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
|
||
BlLoaderBlock->u.Alpha.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
|
||
BlLoaderBlock->u.Alpha.SecondLevelDcacheSize =
|
||
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
|
||
|
||
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
|
||
CacheClass,
|
||
SecondaryIcache,
|
||
NULL);
|
||
|
||
if (ConfigEntry != NULL) {
|
||
LinesPerBlock = ConfigEntry->ComponentEntry.Key >> 24;
|
||
LineSize = 1 << ((ConfigEntry->ComponentEntry.Key >> 16) & 0xff);
|
||
BlLoaderBlock->u.Alpha.SecondLevelIcacheFillSize = LinesPerBlock * LineSize;
|
||
BlLoaderBlock->u.Alpha.SecondLevelIcacheSize =
|
||
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
|
||
|
||
} else {
|
||
BlLoaderBlock->u.Alpha.SecondLevelIcacheSize = 0;
|
||
BlLoaderBlock->u.Alpha.SecondLevelIcacheFillSize = 0;
|
||
}
|
||
|
||
} else {
|
||
BlLoaderBlock->u.Alpha.SecondLevelDcacheSize = 0;
|
||
BlLoaderBlock->u.Alpha.SecondLevelDcacheFillSize = 0;
|
||
BlLoaderBlock->u.Alpha.SecondLevelIcacheSize = 0;
|
||
BlLoaderBlock->u.Alpha.SecondLevelIcacheFillSize = 0;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Allocate DPC stack pages for the boot processor.
|
||
//
|
||
|
||
Status = BlAllocateAnyMemory(LoaderStartupDpcStack,
|
||
0,
|
||
KERNEL_STACK_SIZE >> PAGE_SHIFT,
|
||
&KernelPage);
|
||
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
BlLoaderBlock->u.Alpha.DpcStack =
|
||
(KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
|
||
|
||
//
|
||
// Allocate kernel stack pages for the boot processor idle thread.
|
||
//
|
||
|
||
Status = BlAllocateAnyMemory(LoaderStartupKernelStack,
|
||
0,
|
||
KERNEL_STACK_SIZE >> PAGE_SHIFT,
|
||
&KernelPage);
|
||
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
BlLoaderBlock->KernelStack =
|
||
(KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
|
||
|
||
//
|
||
// Allocate panic stack pages for the boot processor.
|
||
//
|
||
|
||
Status = BlAllocateAnyMemory(LoaderStartupPanicStack,
|
||
0,
|
||
KERNEL_STACK_SIZE >> PAGE_SHIFT,
|
||
&KernelPage);
|
||
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
BlLoaderBlock->u.Alpha.PanicStack =
|
||
(KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
|
||
|
||
//
|
||
// Allocate and zero a page for the PCR.
|
||
//
|
||
|
||
Status = BlAllocateAnyMemory(LoaderStartupPcrPage,
|
||
0,
|
||
1,
|
||
&BlLoaderBlock->u.Alpha.PcrPage);
|
||
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Alpha.PcrPage << PAGE_SHIFT)),
|
||
PAGE_SIZE);
|
||
|
||
//
|
||
// Allocate and zero four pages for the PDR.
|
||
//
|
||
|
||
Status = BlAllocateAnyMemory(LoaderStartupPdrPage,
|
||
0,
|
||
4,
|
||
&BlLoaderBlock->u.Alpha.PdrPage);
|
||
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Alpha.PdrPage << PAGE_SHIFT)),
|
||
PAGE_SIZE * 4);
|
||
|
||
//
|
||
// The storage for processor control block, the idle thread object, and
|
||
// the idle thread process object are allocated from the second half of
|
||
// the exception page. The addresses of these data structures are computed
|
||
// and stored in the loader parameter block and the memory is zeroed.
|
||
//
|
||
|
||
//
|
||
// Allocate a page for PRCB, PROCESS, and THREAD.
|
||
//
|
||
#define OS_DATA_SIZE ((ROUND_UP(KPRCB)+ROUND_UP(EPROCESS)+ROUND_UP(ETHREAD)+\
|
||
PAGE_SIZE - 1) >> PAGE_SHIFT)
|
||
|
||
Status = BlAllocateAnyMemory(LoaderStartupPdrPage,
|
||
0,
|
||
OS_DATA_SIZE,
|
||
&KernelPage);
|
||
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
BlLoaderBlock->Prcb =
|
||
(KSEG0_BASE | (KernelPage << PAGE_SHIFT));
|
||
|
||
RtlZeroMemory((PVOID)BlLoaderBlock->Prcb, OS_DATA_SIZE << PAGE_SHIFT);
|
||
BlLoaderBlock->Process = BlLoaderBlock->Prcb + ROUND_UP(KPRCB);
|
||
BlLoaderBlock->Thread = BlLoaderBlock->Process + ROUND_UP(EPROCESS);
|
||
|
||
//
|
||
// Set up LPB fields from Extended System Information
|
||
//
|
||
|
||
// Defaults
|
||
|
||
BlLoaderBlock->u.Alpha.PhysicalAddressBits = 32;
|
||
BlLoaderBlock->u.Alpha.MaximumAddressSpaceNumber = 0;
|
||
BlLoaderBlock->u.Alpha.SystemSerialNumber[0] = '\0';
|
||
BlLoaderBlock->u.Alpha.CycleClockPeriod = 0x8000;
|
||
BlLoaderBlock->u.Alpha.PageSize = PAGE_SIZE;
|
||
|
||
//
|
||
// Read real system info
|
||
//
|
||
|
||
VenReturnExtendedSystemInformation(&SystemInfo);
|
||
|
||
BlLoaderBlock->u.Alpha.PhysicalAddressBits =
|
||
SystemInfo.NumberOfPhysicalAddressBits;
|
||
|
||
BlLoaderBlock->u.Alpha.MaximumAddressSpaceNumber =
|
||
SystemInfo.MaximumAddressSpaceNumber;
|
||
|
||
BlLoaderBlock->u.Alpha.PageSize =
|
||
SystemInfo.ProcessorPageSize;
|
||
|
||
BlLoaderBlock->u.Alpha.CycleClockPeriod =
|
||
SystemInfo.ProcessorCycleCounterPeriod;
|
||
|
||
strncat(BlLoaderBlock->u.Alpha.SystemSerialNumber,
|
||
SystemInfo.SystemSerialNumber,
|
||
15);
|
||
|
||
BlLoaderBlock->u.Alpha.ProcessorType = SystemInfo.ProcessorId;
|
||
BlLoaderBlock->u.Alpha.ProcessorRevision = SystemInfo.ProcessorRevision;
|
||
|
||
BlLoaderBlock->u.Alpha.SystemType[0] = '\0';
|
||
strncat( BlLoaderBlock->u.Alpha.SystemType, &SystemIdName[2], 8 );
|
||
BlLoaderBlock->u.Alpha.SystemVariant = chartoi(SystemIdName[1]);
|
||
BlLoaderBlock->u.Alpha.SystemRevision = SystemInfo.SystemRevision;
|
||
|
||
BlLoaderBlock->u.Alpha.ProcessorType = SystemInfo.ProcessorId;
|
||
BlLoaderBlock->u.Alpha.ProcessorRevision = SystemInfo.ProcessorRevision;
|
||
|
||
BlLoaderBlock->u.Alpha.RestartBlock = SYSTEM_BLOCK->RestartBlock;
|
||
BlLoaderBlock->u.Alpha.FirmwareRestartAddress =
|
||
(LONG)SYSTEM_BLOCK->FirmwareVector[HaltRoutine];
|
||
|
||
sscanf(SystemInfo.FirmwareVersion, "%lx %lx", &FirmwareMajorVersion,
|
||
&FirmwareMinorVersion);
|
||
FirmwareMinorVersion &= 0xFFFF; // Only low 16 bits of minor version
|
||
FirmwareMajorVersion = FirmwareMajorVersion << 16; // Shift up major version
|
||
BlLoaderBlock->u.Alpha.FirmwareRevisionId =
|
||
FirmwareMajorVersion | FirmwareMinorVersion;
|
||
|
||
//
|
||
// Flush all caches.
|
||
//
|
||
|
||
if (SYSTEM_BLOCK->FirmwareVectorLength > (sizeof(PVOID) * FlushAllCachesRoutine)) {
|
||
ArcFlushAllCaches();
|
||
}
|
||
|
||
#if 0
|
||
DbgSetup(); // Allow for debug setup
|
||
#endif
|
||
|
||
return(ESUCCESS);
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
ReorganizeEisaConfigurationTree(
|
||
IN PCONFIGURATION_COMPONENT_DATA RootEntry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sorts the eisa adapter configuration tree based on
|
||
the slot the component resided in. It also creates a new configuration
|
||
data for EisaAdapter component to contain ALL the eisa slot and function
|
||
information. Finally the Eisa tree will be wiped out.
|
||
|
||
A difference between the Alpha AXP and MIPS versions of this function
|
||
is that one of the Alpha AXP machines (Jensen) needs to retain a Floppy
|
||
disk controller node under the EISA Adapter, so that the NT floppy
|
||
driver will start properly. So this function does not delete an
|
||
independent Floppy Disk Controller subtree under the EISA Adapter.
|
||
Other Alpha AXP machines may need slightly differ code than this. \TBD\.
|
||
|
||
Arguments:
|
||
|
||
RootEntry - Supplies a pointer to a EisaAdapter component. This is
|
||
the root of Eisa adapter tree.
|
||
|
||
|
||
Returns:
|
||
|
||
ESUCCESS is returned if the reorganization is successfully complete.
|
||
Otherwise, an unsuccessful status is returned.
|
||
|
||
--*/
|
||
{
|
||
|
||
PCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry;
|
||
PCONFIGURATION_COMPONENT_DATA EntryFound, EntryFoundPrevious;
|
||
PCONFIGURATION_COMPONENT_DATA AttachedEntry, DetachedList;
|
||
ULONG FloppyControllerNode;
|
||
ARC_STATUS Status;
|
||
|
||
//
|
||
// We sort the direct children of EISA adapter tree based on the slot
|
||
// they reside in. Only the direct children of EISA root need to be
|
||
// sorted.
|
||
// Note the "Key" field of CONFIGURATION_COMPONENT contains
|
||
// EISA slot number.
|
||
//
|
||
|
||
//
|
||
// First, detach all the children from EISA root.
|
||
//
|
||
|
||
AttachedEntry = NULL; // Child list of Eisa root
|
||
DetachedList = RootEntry->Child; // Detached child list
|
||
PreviousEntry = NULL;
|
||
|
||
while (DetachedList) {
|
||
|
||
//
|
||
// Find the component with the smallest slot number from detached
|
||
// list.
|
||
//
|
||
|
||
EntryFound = DetachedList;
|
||
EntryFoundPrevious = NULL;
|
||
CurrentEntry = DetachedList->Sibling;
|
||
PreviousEntry = DetachedList;
|
||
while (CurrentEntry) {
|
||
if (CurrentEntry->ComponentEntry.Key <
|
||
EntryFound->ComponentEntry.Key) {
|
||
EntryFound = CurrentEntry;
|
||
EntryFoundPrevious = PreviousEntry;
|
||
}
|
||
PreviousEntry = CurrentEntry;
|
||
CurrentEntry = CurrentEntry->Sibling;
|
||
}
|
||
|
||
//
|
||
// Remove the component from the detached child list.
|
||
// If the component is not the head of the detached list, we remove it
|
||
// by setting its previous entry's sibling to the component's sibling.
|
||
// Otherwise, we simply update Detach list head to point to the
|
||
// component's sibling.
|
||
//
|
||
|
||
if (EntryFoundPrevious) {
|
||
EntryFoundPrevious->Sibling = EntryFound->Sibling;
|
||
} else {
|
||
DetachedList = EntryFound->Sibling;
|
||
}
|
||
|
||
//
|
||
// Attach the component to the child list of Eisa root.
|
||
//
|
||
|
||
if (AttachedEntry) {
|
||
AttachedEntry->Sibling = EntryFound;
|
||
} else {
|
||
RootEntry->Child = EntryFound;
|
||
}
|
||
AttachedEntry = EntryFound;
|
||
AttachedEntry->Sibling = NULL;
|
||
}
|
||
|
||
//
|
||
// Finally, we traverse the Eisa tree to collect all the Eisa slot
|
||
// and function information and put it to the configuration data of
|
||
// Eisa root entry.
|
||
//
|
||
|
||
Status = CreateEisaConfigurationData(RootEntry, &FloppyControllerNode);
|
||
|
||
//
|
||
// Wipe out all the children of EISA tree except for the Floppy
|
||
// controller node (if present).
|
||
//
|
||
// NOTE shielint - For each child component, we should convert its
|
||
// configuration data from EISA format to our CM_ format.
|
||
//
|
||
|
||
if( FloppyControllerNode != 0 ){
|
||
|
||
RootEntry->Child = (PCONFIGURATION_COMPONENT_DATA)FloppyControllerNode;
|
||
RootEntry->Child->Sibling = NULL;
|
||
return(Status);
|
||
|
||
} else {
|
||
|
||
return ESUCCESS;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
ARC_STATUS
|
||
CreateEisaConfigurationData (
|
||
IN PCONFIGURATION_COMPONENT_DATA RootEntry,
|
||
OUT PULONG FloppyControllerNode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine traverses Eisa configuration tree to collect all the
|
||
slot and function information and attaches it to the configuration data
|
||
of Eisa RootEntry.
|
||
|
||
Note that this routine assumes that the EISA tree has been sorted based
|
||
on the slot number.
|
||
|
||
A difference between the Alpha AXP and MIPS versions of this function
|
||
is that one of the Alpha AXP machines (Jensen) needs to retain a Floppy
|
||
disk controller node under the EISA Adapter, so that the NT floppy
|
||
driver will start properly. So this function does not incorporate
|
||
independent Floppy Disk Controller configuration data into the collapsed
|
||
ESIA Adapter node. Other Alpha AXP machines may need different code than
|
||
this. \TBD\.
|
||
|
||
Arguments:
|
||
|
||
RootEntry - Supplies a pointer to the Eisa configuration
|
||
component entry.
|
||
|
||
FloppyControllerNode - A pointer to a location that returns with either
|
||
a NULL or the address of an independent floppy disk
|
||
controller node underneath the EISA Adapter.
|
||
|
||
Returns:
|
||
|
||
ESUCCESS is returned if the new EisaAdapter configuration data is
|
||
successfully created. Otherwise, an unsuccessful status is returned.
|
||
|
||
--*/
|
||
{
|
||
ULONG DataSize, NextSlot = 0, i;
|
||
PCM_PARTIAL_RESOURCE_LIST Descriptor;
|
||
PCONFIGURATION_COMPONENT Component;
|
||
PCONFIGURATION_COMPONENT_DATA CurrentEntry;
|
||
PUCHAR DataPointer;
|
||
CM_EISA_SLOT_INFORMATION EmptySlot =
|
||
{EISA_EMPTY_SLOT, 0, 0, 0, 0, 0, 0, 0};
|
||
|
||
//
|
||
// The default return value is no floppy controller node found.
|
||
//
|
||
|
||
*FloppyControllerNode = (ULONG)NULL;
|
||
|
||
//
|
||
// Remove the configuration data of Eisa Adapter
|
||
//
|
||
|
||
RootEntry->ConfigurationData = NULL;
|
||
RootEntry->ComponentEntry.ConfigurationDataLength = 0;
|
||
|
||
//
|
||
// If the EISA stree contains valid slot information, i.e.
|
||
// root has children attaching to it.
|
||
//
|
||
|
||
if (RootEntry->Child) {
|
||
|
||
//
|
||
// First find out how much memory is needed to store EISA config
|
||
// data.
|
||
//
|
||
|
||
DataSize = sizeof(CM_PARTIAL_RESOURCE_LIST);
|
||
CurrentEntry = RootEntry->Child;
|
||
|
||
while (CurrentEntry) {
|
||
Component = &CurrentEntry->ComponentEntry;
|
||
if (CurrentEntry->ConfigurationData) {
|
||
if (Component->Key > NextSlot) {
|
||
|
||
//
|
||
// If there is any empty slot between current slot
|
||
// and previous checked slot, we need to count the
|
||
// space for the empty slots.
|
||
//
|
||
|
||
DataSize += (Component->Key - NextSlot) *
|
||
sizeof(CM_EISA_SLOT_INFORMATION);
|
||
}
|
||
DataSize += Component->ConfigurationDataLength + 1 -
|
||
CONFIGURATION_DATA_HEADER_SIZE;
|
||
NextSlot = Component->Key + 1;
|
||
}
|
||
CurrentEntry = CurrentEntry->Sibling;
|
||
}
|
||
|
||
//
|
||
// Allocate memory from heap to hold the EISA configuration data.
|
||
//
|
||
|
||
DataPointer = BlAllocateHeap(DataSize);
|
||
|
||
if (DataPointer == NULL) {
|
||
return ENOMEM;
|
||
} else {
|
||
RootEntry->ConfigurationData = DataPointer;
|
||
RootEntry->ComponentEntry.ConfigurationDataLength = DataSize;
|
||
}
|
||
|
||
//
|
||
// Create a CM_PARTIAL_RESOURCE_LIST for the new configuration data.
|
||
//
|
||
|
||
Descriptor = (PCM_PARTIAL_RESOURCE_LIST)DataPointer;
|
||
Descriptor->Version = 0;
|
||
Descriptor->Revision = 0;
|
||
Descriptor->Count = 1;
|
||
Descriptor->PartialDescriptors[0].Type = CmResourceTypeDeviceSpecific;
|
||
Descriptor->PartialDescriptors[0].ShareDisposition = 0;
|
||
Descriptor->PartialDescriptors[0].Flags = 0;
|
||
Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved1 = 0;
|
||
Descriptor->PartialDescriptors[0].u.DeviceSpecificData.Reserved2 = 0;
|
||
Descriptor->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
|
||
DataSize - sizeof(CM_PARTIAL_RESOURCE_LIST);
|
||
|
||
//
|
||
// Visit each child of the RootEntry and copy its ConfigurationData
|
||
// to the new configuration data area.
|
||
// N.B. The configuration data includes a slot information and zero
|
||
// or more function information. The slot information provided
|
||
// by ARC eisa data does not have "ReturnedCode" as defined in
|
||
// our CM_EISA_SLOT_INFORMATION. This code will convert the
|
||
// standard EISA slot information to our CM format.
|
||
//
|
||
// N.B. Configuration data for independent floppy controllers
|
||
// is not incorporated into the collapsed configuration data.
|
||
//
|
||
|
||
CurrentEntry = RootEntry->Child;
|
||
DataPointer += sizeof(CM_PARTIAL_RESOURCE_LIST);
|
||
NextSlot = 0;
|
||
|
||
while (CurrentEntry) {
|
||
Component = &CurrentEntry->ComponentEntry;
|
||
|
||
//
|
||
// If this component is a floppy disk controller, remember where
|
||
// it is and return the value to the caller. Otherwise, if it
|
||
// has configuration data, process it.
|
||
//
|
||
|
||
if ((Component->Class == ControllerClass) &&
|
||
(Component->Type == DiskController) &&
|
||
(CurrentEntry->Child != NULL) &&
|
||
(CurrentEntry->Child->ComponentEntry.Class == PeripheralClass) &&
|
||
(CurrentEntry->Child->ComponentEntry.Type == FloppyDiskPeripheral)) {
|
||
|
||
*FloppyControllerNode = (ULONG)CurrentEntry;
|
||
|
||
} else if (CurrentEntry->ConfigurationData) {
|
||
|
||
//
|
||
// Check if there is any empty slot. If yes, create empty
|
||
// slot information. Also make sure the config data area is
|
||
// big enough.
|
||
//
|
||
|
||
if (Component->Key > NextSlot) {
|
||
for (i = NextSlot; i < CurrentEntry->ComponentEntry.Key; i++ ) {
|
||
*(PCM_EISA_SLOT_INFORMATION)DataPointer = EmptySlot;
|
||
DataPointer += sizeof(CM_EISA_SLOT_INFORMATION);
|
||
}
|
||
}
|
||
|
||
*DataPointer++ = 0; // See comment above
|
||
RtlMoveMemory( // Skip config data header
|
||
DataPointer,
|
||
(PUCHAR)CurrentEntry->ConfigurationData +
|
||
CONFIGURATION_DATA_HEADER_SIZE,
|
||
Component->ConfigurationDataLength -
|
||
CONFIGURATION_DATA_HEADER_SIZE
|
||
);
|
||
DataPointer += Component->ConfigurationDataLength -
|
||
CONFIGURATION_DATA_HEADER_SIZE;
|
||
NextSlot = Component->Key + 1;
|
||
}
|
||
CurrentEntry = CurrentEntry->Sibling;
|
||
}
|
||
}
|
||
return(ESUCCESS);
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
DeleteARCVolatileTree (
|
||
IN PCONFIGURATION_COMPONENT Entry
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function recursively deletes a subtree from the ARC Component
|
||
Data Structure. The tree is only deleted in volatile storage, i.e.
|
||
it is not saved back to the ROM.
|
||
|
||
Arguments:
|
||
|
||
Entry - Supplies a pointer to a component which is the top of the
|
||
tree to be deleted.
|
||
|
||
Returns:
|
||
|
||
ESUCCESS if the subtree was deleted, otherwise an unsuccessful status
|
||
is returned.
|
||
|
||
--*/
|
||
{
|
||
ARC_STATUS Status;
|
||
PCONFIGURATION_COMPONENT ChildEntry;
|
||
|
||
//
|
||
// Delete the children of this node.
|
||
//
|
||
|
||
while ((ChildEntry = ArcGetChild(Entry)) != NULL) {
|
||
|
||
if ((Status = DeleteARCVolatileTree(ChildEntry)) != ESUCCESS) {
|
||
return (Status);
|
||
}
|
||
}
|
||
|
||
//
|
||
// And now delete this node too.
|
||
//
|
||
|
||
return (ArcDeleteComponent(Entry));
|
||
}
|
||
|