NT4/private/ntos/boot/lib/alpha/ntsetup.c
2020-09-30 17:12:29 +02:00

856 lines
26 KiB
C
Raw 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) 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));
}