653 lines
21 KiB
C
653 lines
21 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ntsetup.c
|
||
|
||
Abstract:
|
||
|
||
This module is the tail-end of the OS loader program. It performs all
|
||
MIPS 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:
|
||
|
||
--*/
|
||
|
||
#include "bldr.h"
|
||
#include "stdio.h"
|
||
|
||
//
|
||
// 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
|
||
);
|
||
|
||
VOID
|
||
BlQueryImplementationAndRevision (
|
||
OUT PULONG ProcessorId,
|
||
OUT PULONG FloatingId
|
||
);
|
||
|
||
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 FloatingId;
|
||
CHAR Identifier[256];
|
||
ULONG KernelPage;
|
||
ULONG LinesPerBlock;
|
||
ULONG LineSize;
|
||
PCHAR NewIdentifier;
|
||
ULONG PrcbPage;
|
||
ULONG ProcessorId;
|
||
ARC_STATUS Status;
|
||
|
||
//
|
||
// If the host configuration is not a multiprocessor machine, then add
|
||
// the processor and floating point coprocessor identification to the
|
||
// processor identification string.
|
||
//
|
||
|
||
if (SYSTEM_BLOCK->RestartBlock == NULL) {
|
||
ConfigEntry = KeFindConfigurationEntry(BlLoaderBlock->ConfigurationRoot,
|
||
ProcessorClass,
|
||
CentralProcessor,
|
||
NULL);
|
||
|
||
if (ConfigEntry != NULL) {
|
||
BlQueryImplementationAndRevision(&ProcessorId, &FloatingId);
|
||
sprintf(&Identifier[0],
|
||
"%s - Pr %d/%d, Fp %d/%d",
|
||
ConfigEntry->ComponentEntry.Identifier,
|
||
(ProcessorId >> 8) & 0xff,
|
||
ProcessorId & 0xff,
|
||
(FloatingId >> 8) & 0xff,
|
||
FloatingId & 0xff);
|
||
|
||
NewIdentifier = (PCHAR)BlAllocateHeap(strlen(&Identifier[0]) + 1);
|
||
if (NewIdentifier != NULL) {
|
||
strcpy(NewIdentifier, &Identifier[0]);
|
||
ConfigEntry->ComponentEntry.IdentifierLength = strlen(NewIdentifier);
|
||
ConfigEntry->ComponentEntry.Identifier = NewIdentifier;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// 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.Mips.FirstLevelDcacheFillSize = LinesPerBlock * LineSize;
|
||
BlLoaderBlock->u.Mips.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.Mips.FirstLevelIcacheFillSize = LinesPerBlock * LineSize;
|
||
BlLoaderBlock->u.Mips.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.Mips.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
|
||
BlLoaderBlock->u.Mips.SecondLevelDcacheSize =
|
||
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
|
||
|
||
BlLoaderBlock->u.Mips.SecondLevelIcacheSize = 0;
|
||
BlLoaderBlock->u.Mips.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.Mips.SecondLevelDcacheFillSize = LinesPerBlock * LineSize;
|
||
BlLoaderBlock->u.Mips.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.Mips.SecondLevelIcacheFillSize = LinesPerBlock * LineSize;
|
||
BlLoaderBlock->u.Mips.SecondLevelIcacheSize =
|
||
1 << ((ConfigEntry->ComponentEntry.Key & 0xffff) + PAGE_SHIFT);
|
||
|
||
} else {
|
||
BlLoaderBlock->u.Mips.SecondLevelIcacheSize = 0;
|
||
BlLoaderBlock->u.Mips.SecondLevelIcacheFillSize = 0;
|
||
}
|
||
|
||
} else {
|
||
BlLoaderBlock->u.Mips.SecondLevelDcacheSize = 0;
|
||
BlLoaderBlock->u.Mips.SecondLevelDcacheFillSize = 0;
|
||
BlLoaderBlock->u.Mips.SecondLevelIcacheSize = 0;
|
||
BlLoaderBlock->u.Mips.SecondLevelIcacheFillSize = 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Allocate DPC stack pages for the boot processor.
|
||
//
|
||
|
||
Status = BlAllocateDescriptor(LoaderStartupDpcStack,
|
||
0,
|
||
KERNEL_STACK_SIZE >> PAGE_SHIFT,
|
||
&KernelPage);
|
||
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
BlLoaderBlock->u.Mips.InterruptStack =
|
||
(KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
|
||
|
||
//
|
||
// Allocate kernel stack pages for the boot processor idle thread.
|
||
//
|
||
|
||
Status = BlAllocateDescriptor(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 = BlAllocateDescriptor(LoaderStartupPanicStack,
|
||
0,
|
||
KERNEL_STACK_SIZE >> PAGE_SHIFT,
|
||
&KernelPage);
|
||
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
BlLoaderBlock->u.Mips.PanicStack =
|
||
(KSEG0_BASE | (KernelPage << PAGE_SHIFT)) + KERNEL_STACK_SIZE;
|
||
|
||
//
|
||
// Allocate and zero two pages for the PCR.
|
||
//
|
||
|
||
Status = BlAllocateDescriptor(LoaderStartupPcrPage,
|
||
0,
|
||
2,
|
||
&BlLoaderBlock->u.Mips.PcrPage);
|
||
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
BlLoaderBlock->u.Mips.PcrPage2 = BlLoaderBlock->u.Mips.PcrPage + 1;
|
||
RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Mips.PcrPage << PAGE_SHIFT)),
|
||
PAGE_SIZE * 2);
|
||
|
||
//
|
||
// Allocate and zero two pages for the PDR and one page of memory for
|
||
// the initial processor block, idle process, and idle thread structures.
|
||
//
|
||
|
||
Status = BlAllocateDescriptor(LoaderStartupPdrPage,
|
||
0,
|
||
3,
|
||
&BlLoaderBlock->u.Mips.PdrPage);
|
||
|
||
if (Status != ESUCCESS) {
|
||
return(Status);
|
||
}
|
||
|
||
RtlZeroMemory((PVOID)(KSEG0_BASE | (BlLoaderBlock->u.Mips.PdrPage << PAGE_SHIFT)),
|
||
PAGE_SIZE * 3);
|
||
|
||
//
|
||
// The storage for processor control block, the idle thread object, and
|
||
// the idle thread process object are allocated from the third page of the
|
||
// PDR allocation. The addresses of these data structures are computed
|
||
// and stored in the loader parameter block and the memory is zeroed.
|
||
//
|
||
|
||
PrcbPage = BlLoaderBlock->u.Mips.PdrPage + 2;
|
||
if (PAGE_SIZE >= (ROUND_UP(KPRCB) + ROUND_UP(EPROCESS) + ROUND_UP(ETHREAD))) {
|
||
BlLoaderBlock->Prcb = KSEG0_BASE | (PrcbPage << PAGE_SHIFT);
|
||
BlLoaderBlock->Process = BlLoaderBlock->Prcb + ROUND_UP(KPRCB);
|
||
BlLoaderBlock->Thread = BlLoaderBlock->Process + ROUND_UP(EPROCESS);
|
||
|
||
} else {
|
||
return(ENOMEM);
|
||
}
|
||
|
||
//
|
||
// Flush all caches.
|
||
//
|
||
|
||
if (SYSTEM_BLOCK->FirmwareVectorLength > (sizeof(PVOID) * FlushAllCachesRoutine)) {
|
||
ArcFlushAllCaches();
|
||
}
|
||
|
||
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.
|
||
|
||
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;
|
||
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);
|
||
|
||
//
|
||
// Wipe out all the children of EISA tree.
|
||
// NOTE shielint - For each child component, we should convert its
|
||
// configuration data from EISA format to our CM_ format.
|
||
//
|
||
|
||
RootEntry->Child = NULL;
|
||
return(Status);
|
||
|
||
}
|
||
|
||
ARC_STATUS
|
||
CreateEisaConfigurationData (
|
||
IN PCONFIGURATION_COMPONENT_DATA RootEntry
|
||
)
|
||
|
||
/*++
|
||
|
||
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.
|
||
|
||
Arguments:
|
||
|
||
RootEntry - Supplies a pointer to the Eisa configuration
|
||
component entry.
|
||
|
||
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};
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
|
||
CurrentEntry = RootEntry->Child;
|
||
DataPointer += sizeof(CM_PARTIAL_RESOURCE_LIST);
|
||
NextSlot = 0;
|
||
|
||
while (CurrentEntry) {
|
||
Component = &CurrentEntry->ComponentEntry;
|
||
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);
|
||
}
|
||
|