3012 lines
96 KiB
C
3012 lines
96 KiB
C
/*++
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
assign.c
|
|
|
|
Abstract:
|
|
IoAssignResources
|
|
|
|
Author:
|
|
Ken Reneris
|
|
|
|
Environment:
|
|
EDIT IN 110 COLUMN MODE
|
|
|
|
Revision History:
|
|
Add PnP support - shielint
|
|
--*/
|
|
|
|
#include "iop.h"
|
|
|
|
#define IDBG DBG
|
|
#define PAGED 1
|
|
#define INLINE __inline
|
|
#define STATIC static
|
|
|
|
//#define IDBG 1
|
|
//#define DBG 1
|
|
//#define PAGED
|
|
//#define INLINE
|
|
//#define STATIC
|
|
|
|
|
|
/*
|
|
* IDBG - Internal debugging. Turn on for runtime DbgPrints of calls to IoAssignResources
|
|
* PAGED - Declare functions as pageable or not. (usefull for debugging)
|
|
* INLINE - Inline functions
|
|
* STATIC - internal functions to this module which are static
|
|
*/
|
|
|
|
|
|
extern WCHAR IopWstrOtherDrivers[];
|
|
extern WCHAR IopWstrAssignedResources[];
|
|
extern WCHAR IopWstrRequestedResources[];
|
|
extern WCHAR IopWstrSystemResources[];
|
|
extern WCHAR IopWstrReservedResources[];
|
|
extern WCHAR IopWstrAssignmentOrdering[];
|
|
extern WCHAR IopWstrBusValues[];
|
|
extern WCHAR IopWstrTranslated[];
|
|
extern WCHAR IopWstrBusTranslated[];
|
|
|
|
#define HRESOURCE_MAP 0
|
|
#define HDEVICE_STORAGE 1
|
|
#define HCURRENT_CONTROL_SET 2
|
|
#define HSYSTEMRESOURCES 3
|
|
#define HORDERING 4
|
|
#define HRESERVEDRESOURCES 5
|
|
#define HBUSVALUES 6
|
|
#define HOWNER_MAP 7
|
|
#define MAX_REG_HANDLES 8
|
|
|
|
#define INVALID_HANDLE (HANDLE) -1
|
|
|
|
#define BUFFERSIZE (2048 + sizeof( KEY_FULL_INFORMATION ))
|
|
#define MAX_ENTRIES 50
|
|
#define SCONFLICT 5
|
|
|
|
|
|
// Wrapper structures around IO_RESOURCE lists
|
|
|
|
|
|
// owner of TENTRY
|
|
typedef struct {
|
|
LIST_ENTRY InConflict;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING DeviceName;
|
|
WCHAR UnicodeBuffer[1]; // Must be last!
|
|
} *POWNER;
|
|
|
|
// translated entry
|
|
typedef struct {
|
|
LONGLONG BAddr; // Beginning address
|
|
LONGLONG EAddr; // Ending address
|
|
KAFFINITY Affinity; // Processor affinity of resource
|
|
POWNER Owner; // Owner of this resource
|
|
#if IDBG
|
|
ULONG na[2];
|
|
#endif
|
|
} TENTRY, *PTENTRY; // Translated resource
|
|
|
|
#define DoesTEntryCollide(a,b) \
|
|
( (a).EAddr >= (b).BAddr && (a).BAddr <= (b).EAddr && ((a).Affinity & (b).Affinity) )
|
|
|
|
|
|
// list of translated entries
|
|
typedef struct _LTENTRY {
|
|
struct _LTENTRY *Next; // Allocated table size
|
|
ULONG CurEntries; // No entries in table
|
|
ULONG na[2];
|
|
TENTRY Table[MAX_ENTRIES];
|
|
} LTENTRY, *PLTENTRY; // List of translated resources
|
|
|
|
// list of translated entries by CmResourceType
|
|
typedef struct {
|
|
PLTENTRY ByType[CmResourceTypeMaximum];
|
|
} TENTRIESBYTYPE, *PTENTRIESBYTYPE;
|
|
|
|
// information about conflict
|
|
typedef struct {
|
|
ULONG NoConflicts; // # of BAddrs
|
|
struct {
|
|
UCHAR Type;
|
|
LONGLONG BAddr;
|
|
POWNER Owner;
|
|
} EasyConflict[SCONFLICT];
|
|
|
|
LIST_ENTRY OtherConflicts;
|
|
} IO_TRACK_CONFLICT, *PIO_TRACK_CONFLICT;
|
|
|
|
// a required resource with it's alternatives
|
|
typedef struct {
|
|
// work in progress...
|
|
ULONG CurLoc; // Which IoResourceDescriptor
|
|
ULONG RunLen; // length of alternative run
|
|
ULONG PassNo;
|
|
|
|
// current bus specific ordering location
|
|
ULONG CurBusLoc; // Current Bus descriptor location
|
|
LONGLONG CurBusMin; // Current bus desc min
|
|
LONGLONG CurBusMax; // Current bus desc max
|
|
|
|
// raw selection being considered...
|
|
UCHAR Type; // type of descriptor
|
|
ULONG CurBLoc;
|
|
LONGLONG CurBAddr; // bus native BAddr
|
|
|
|
// the raw selection's translation
|
|
UCHAR TType; // Translated type
|
|
TENTRY Trans; // Translated info
|
|
|
|
LONG BestPref; // only has meaning on first pass
|
|
LONG CurPref; // Prefernce of current selection
|
|
|
|
// Phase 3
|
|
ULONG PrefCnt; // # of times this level skipped
|
|
ULONG Pass2HoldCurLoc; // CurBLoc of best selection so far
|
|
LONGLONG Pass2HoldBAddr; // CurBAddr of best selection so far
|
|
|
|
// resource options
|
|
ULONG NoAlternatives; // entries in IoResourceDescriptor
|
|
PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor[1]; // MUST BE LAST ENTRY
|
|
} DIR_REQUIRED_RESOURCE, *PDIR_REQUIRED_RESOURCE;
|
|
|
|
// a list of required resources for the alternative list
|
|
typedef struct _DIR_RESOURCE_LIST {
|
|
struct _DIR_RESOURCE_LIST *Next; // next alternative list
|
|
PDIR_REQUIRED_RESOURCE ResourceByType[CmResourceTypeMaximum]; // catagorized list
|
|
LONG CurPref;
|
|
ULONG LastLevel; // last level tried
|
|
ULONG FailedLevel; // which level had conflict
|
|
IO_TRACK_CONFLICT Conflict; // pass3
|
|
PIO_RESOURCE_LIST IoResourceList; // this IO_RESOURCE_LIST
|
|
ULONG NoRequiredResources; // entries in RequiredResource
|
|
PDIR_REQUIRED_RESOURCE RequiredResource[1]; // MUST BE LAST ENTRY
|
|
} DIR_RESOURCE_LIST, *PDIR_RESOURCE_LIST;
|
|
|
|
// top level structure
|
|
typedef struct _DIR_RESREQ_LIST {
|
|
HANDLE RegHandle[MAX_REG_HANDLES]; // handles to different registry locations
|
|
struct _DIR_RESREQ_LIST *UserDir;
|
|
struct _DIR_RESREQ_LIST *BusDir;
|
|
struct _DIR_RESREQ_LIST *FreeResReqList; // other DIR_RESREQ_LIST which need freed
|
|
SINGLE_LIST_ENTRY AllocatedHeap; // heap which needs freed
|
|
TENTRIESBYTYPE InUseResources;
|
|
TENTRIESBYTYPE InUseSharableResources;
|
|
TENTRIESBYTYPE ReservedSharableResources;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST IoResourceReq; // this IO_RESOURCES_REQUIREMENTS_LIST
|
|
PDIR_RESOURCE_LIST Alternative; // list of alternatives
|
|
PWCHAR Buffer; // Scratch memory
|
|
} DIR_RESREQ_LIST, *PDIR_RESREQ_LIST;
|
|
|
|
// a list of heap which was allocated
|
|
typedef struct {
|
|
SINGLE_LIST_ENTRY FreeLink; // List of heap to free
|
|
PVOID FreeHeap; // pointer to heap to free
|
|
} USED_HEAP, *PUSED_HEAP;
|
|
|
|
|
|
// Internal prototypes
|
|
|
|
|
|
PIO_RESOURCE_REQUIREMENTS_LIST
|
|
IopGetResourceReqRegistryValue (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN HANDLE KeyHandle,
|
|
IN PWSTR ValueName
|
|
);
|
|
|
|
NTSTATUS
|
|
IopAssignResourcesPhase1 (
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources,
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST *CopiedList
|
|
);
|
|
|
|
NTSTATUS
|
|
IopAssignResourcesPhase2 (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PUNICODE_STRING DriverClassName,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
);
|
|
|
|
PDIR_RESOURCE_LIST
|
|
IopAssignResourcesPhase3 (
|
|
IN PDIR_RESREQ_LIST Dir
|
|
);
|
|
|
|
PCM_RESOURCE_LIST
|
|
IopAssignResourcesPhase4 (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PDIR_RESOURCE_LIST CurList,
|
|
OUT PULONG Length
|
|
);
|
|
|
|
STATIC VOID
|
|
IopLogConflict (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN NTSTATUS FinalStatus
|
|
);
|
|
|
|
STATIC PVOID
|
|
IopAllocateDirPool (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN ULONG Length
|
|
);
|
|
|
|
INLINE PTENTRY
|
|
IopNewTransEntry (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PTENTRIESBYTYPE pTypes,
|
|
IN ULONG Type
|
|
);
|
|
|
|
STATIC NTSTATUS
|
|
IopAddCmDescriptorToInUseList (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PTENTRIESBYTYPE pTypes,
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc,
|
|
IN POWNER Owner
|
|
);
|
|
|
|
ULONG
|
|
IopFindCollisionInTList (
|
|
IN PTENTRY SEntry,
|
|
IN PLTENTRY List
|
|
);
|
|
|
|
VOID
|
|
IopPickupCollisionInTList (
|
|
IN PDIR_RESOURCE_LIST CurList,
|
|
IN UCHAR Type,
|
|
IN LONGLONG BAddr,
|
|
IN PTENTRY SEntry,
|
|
IN PLTENTRY List
|
|
);
|
|
|
|
NTSTATUS
|
|
IopBuildResourceDir (
|
|
IN PDIR_RESREQ_LIST ParentDir,
|
|
IN PDIR_RESREQ_LIST *DirResourceList,
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources
|
|
);
|
|
|
|
VOID IopFreeResourceDir (IN PDIR_RESREQ_LIST DirResourceList);
|
|
VOID IopSortDescriptors (IN OUT PDIR_RESREQ_LIST Dir);
|
|
NTSTATUS IopCatagorizeDescriptors (IN OUT PDIR_RESREQ_LIST Dir);
|
|
ULONG IopDescriptorSortingWeight (IN PIO_RESOURCE_DESCRIPTOR Descriptor);
|
|
|
|
BOOLEAN
|
|
IopGenNextValidResourceList (
|
|
IN ULONG level,
|
|
IN PDIR_RESOURCE_LIST CurList,
|
|
IN PDIR_RESREQ_LIST Dir
|
|
);
|
|
|
|
BOOLEAN
|
|
IopGenNextValidDescriptor (
|
|
IN ULONG level,
|
|
IN PDIR_RESOURCE_LIST CurList,
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PULONG collisionlevel
|
|
);
|
|
|
|
BOOLEAN
|
|
IopSlotResourceOwner (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources,
|
|
IN BOOLEAN AddOwner
|
|
);
|
|
|
|
#if IDBG
|
|
VOID
|
|
IopDumpIoResourceDir (
|
|
IN PDIR_RESREQ_LIST Dir
|
|
);
|
|
|
|
VOID
|
|
IopDumpIoResourceDescriptor (
|
|
IN PUCHAR Indent,
|
|
IN PIO_RESOURCE_DESCRIPTOR Desc
|
|
);
|
|
#endif
|
|
|
|
#if DBG
|
|
#define CHECK_STATUS(a,b) { if(!NT_SUCCESS(a)) { DebugString = b; goto Exit; } }
|
|
#else
|
|
#define CHECK_STATUS(a,b) { if(!NT_SUCCESS(a)) goto Exit; }
|
|
#endif
|
|
|
|
#if DBG
|
|
#define DBGMSG(a) DbgPrint(a)
|
|
#else
|
|
#define DBGMSG(a)
|
|
#endif
|
|
|
|
#if IDBG
|
|
#define IDBGMSG(a) DbgPrint(a)
|
|
#else
|
|
#define IDBGMSG(a)
|
|
#endif
|
|
|
|
#ifdef PAGED
|
|
#ifdef ALLOC_PRAGMA
|
|
|
|
#pragma alloc_text(PAGE,IoAssignResources)
|
|
#pragma alloc_text(PAGE,IopAssignResourcesPhase1)
|
|
#pragma alloc_text(PAGE,IopAssignResourcesPhase2)
|
|
#pragma alloc_text(PAGE,IopAssignResourcesPhase3)
|
|
#pragma alloc_text(PAGE,IopAssignResourcesPhase4)
|
|
#pragma alloc_text(PAGE,IopLogConflict)
|
|
#pragma alloc_text(PAGE,IopGenNextValidResourceList)
|
|
#pragma alloc_text(PAGE,IopGenNextValidDescriptor)
|
|
#pragma alloc_text(PAGE,IopFindCollisionInTList)
|
|
#pragma alloc_text(PAGE,IopPickupCollisionInTList)
|
|
#pragma alloc_text(PAGE,IopAllocateDirPool)
|
|
#pragma alloc_text(PAGE,IopGetResourceReqRegistryValue)
|
|
#pragma alloc_text(PAGE,IopBuildResourceDir)
|
|
#pragma alloc_text(PAGE,IopFreeResourceDir)
|
|
#pragma alloc_text(PAGE,IopCatagorizeDescriptors)
|
|
#pragma alloc_text(PAGE,IopSortDescriptors)
|
|
#pragma alloc_text(PAGE,IopAddCmDescriptorToInUseList)
|
|
#pragma alloc_text(PAGE,IopSlotResourceOwner)
|
|
#if IDBG
|
|
#pragma alloc_text(PAGE,IopDumpIoResourceDir)
|
|
#pragma alloc_text(PAGE,IopDumpIoResourceDescriptor)
|
|
#endif
|
|
|
|
#ifndef INLINE
|
|
#pragma alloc_text(PAGE,IO_DESC_MIN)
|
|
#pragma alloc_text(PAGE,IO_DESC_MAX)
|
|
#pragma alloc_text(PAGE,IopDescriptorSortingWeight)
|
|
#pragma alloc_text(PAGE,IopNewTransEntry)
|
|
#endif // INLINE
|
|
|
|
#endif // ALLOC_PRAGMA
|
|
#endif // PAGED
|
|
|
|
|
|
NTSTATUS
|
|
IoAssignResources (
|
|
IN PUNICODE_STRING RegistryPath,
|
|
IN PUNICODE_STRING DriverClassName OPTIONAL,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST RequestedResources,
|
|
IN OUT PCM_RESOURCE_LIST *pAllocatedResources
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This routine takes an input request of RequestedResources, and returned allocated resources in pAllocatedResources.
|
|
The allocated resources are automatically recorded in the registry under the ResourceMap for the DriverClassName/DriverObject/DeviceObject requestor.
|
|
Arguments:
|
|
|
|
RegistryPath
|
|
For a simple driver, this would be the value passed to the drivers
|
|
initialization function. For drivers call IoAssignResources with
|
|
multiple DeviceObjects are responsible for passing in a unique
|
|
RegistryPath for each object.
|
|
|
|
The registry path is checked for:
|
|
RegitryPath:
|
|
AssignedSystemResources.
|
|
|
|
AssignSystemResources is of type REG_RESOURCE_REQUIREMENTS_LIST
|
|
|
|
If present, IoAssignResources will attempt to use these settings to
|
|
satisify the requested resources. If the listed settings do
|
|
not conform to the resource requirements, then IoAssignResources
|
|
will fail.
|
|
|
|
Note: IoAssignResources may store other internal binary information
|
|
in the supplied RegisteryPath.
|
|
|
|
DriverObject:
|
|
The driver object of the caller.
|
|
|
|
DeviceObject:
|
|
If non-null, then requested resoruce list refers to this device.
|
|
If null, the requested resource list refers to the driver.
|
|
|
|
DriverClassName
|
|
Used to partition allocated resources into different device classes.
|
|
|
|
RequestedResources
|
|
A list of resources to allocate.
|
|
|
|
Allocated resources may be appended or freed by re-invoking
|
|
IoAssignResources with the same RegistryPath, DriverObject and
|
|
DeviceObject. (editing requirements on a resource list by using
|
|
sucessive calls is not preferred driver behaviour).
|
|
|
|
AllocatedResources
|
|
Returns the allocated resources for the requested resource list.
|
|
|
|
Note that the driver is responsible for passing in a pointer to
|
|
an uninitialized pointer. IoAssignResources will initialize the
|
|
pointer to point to the allocated CM_RESOURCE_LIST. The driver
|
|
is responisble for returning the memory back to pool when it is
|
|
done with them structure.
|
|
|
|
Return Value:
|
|
|
|
The status returned is the final completion status of the operation.
|
|
|
|
--*/
|
|
{
|
|
if (DeviceObject) {
|
|
if (DeviceObject->DeviceObjectExtension->DeviceNode &&
|
|
!(((PDEVICE_NODE)DeviceObject->DeviceObjectExtension->DeviceNode)->Flags & DNF_LEGACY_RESOURCE_DEVICENODE)) {
|
|
KeBugCheckEx(PNP_DETECTED_FATAL_ERROR, PNP_ERR_INVALID_PDO, (ULONG_PTR)DeviceObject, 0, 0);
|
|
}
|
|
}
|
|
|
|
if (RequestedResources) {
|
|
if (RequestedResources->AlternativeLists == 0 || RequestedResources->List[0].Count == 0) {
|
|
RequestedResources = NULL;
|
|
}
|
|
}
|
|
|
|
if (pAllocatedResources) {
|
|
*pAllocatedResources = NULL;
|
|
}
|
|
|
|
return IopLegacyResourceAllocation(ArbiterRequestLegacyAssigned,
|
|
DriverObject,
|
|
DeviceObject,
|
|
RequestedResources,
|
|
pAllocatedResources);
|
|
}
|
|
|
|
|
|
#if 0
|
|
BOOLEAN
|
|
IopSlotResourceOwner (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources,
|
|
IN BOOLEAN AddOwner
|
|
)
|
|
{
|
|
ULONG busflags, len, i;
|
|
PWCHAR KeyName;
|
|
UNICODE_STRING KeyString, ValueString;
|
|
POBJECT_NAME_INFORMATION ObjectName;
|
|
PKEY_VALUE_PARTIAL_INFORMATION PartInf;
|
|
BOOLEAN Match;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
KeyName = ExAllocatePool (PagedPool, BUFFERSIZE * 2);
|
|
if (!KeyName) {
|
|
return FALSE;
|
|
}
|
|
|
|
ObjectName = (POBJECT_NAME_INFORMATION) ((PCHAR)KeyName + BUFFERSIZE);
|
|
Match = TRUE;
|
|
|
|
|
|
// Find bus specific ordering
|
|
status = IopLookupBusStringFromID (Dir->RegHandle[HBUSVALUES], IoResources->InterfaceType, KeyName, BUFFERSIZE-40, &busflags);
|
|
|
|
// Does this bus have unique SlotNumber ownership?
|
|
if (NT_SUCCESS(status) && (busflags & 0x1)) {
|
|
// Build keyname
|
|
for (i=0; KeyName[i]; i++) ;
|
|
swprintf (KeyName+i, L"_%d_%x", IoResources->BusNumber, IoResources->SlotNumber);
|
|
RtlInitUnicodeString( &KeyString, KeyName );
|
|
|
|
|
|
// Build valuename
|
|
status = ObQueryNameString(
|
|
DeviceObject ? (PVOID) DeviceObject : (PVOID) DriverObject,
|
|
ObjectName,
|
|
BUFFERSIZE,
|
|
&len);
|
|
if (NT_SUCCESS(status)) {
|
|
// Look it up
|
|
PartInf = (PKEY_VALUE_PARTIAL_INFORMATION) Dir->Buffer;
|
|
status = ZwQueryValueKey (
|
|
Dir->RegHandle[HOWNER_MAP],
|
|
&KeyString,
|
|
KeyValuePartialInformation,
|
|
Dir->Buffer,
|
|
BUFFERSIZE,
|
|
&len);
|
|
if (!NT_SUCCESS(status)) {
|
|
// No owner listed, see if we should add ourselves
|
|
if (AddOwner) {
|
|
// Add the key
|
|
ZwSetValueKey (
|
|
Dir->RegHandle[HOWNER_MAP],
|
|
&KeyString,
|
|
0L,
|
|
REG_SZ,
|
|
ObjectName->Name.Buffer,
|
|
ObjectName->Name.Length);
|
|
}
|
|
} else {
|
|
// Owner is listed, see if it's us
|
|
ValueString.Buffer = (PWCHAR) PartInf->Data;
|
|
ValueString.Length = (USHORT) len - (USHORT) FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data);
|
|
ValueString.MaximumLength = ValueString.Length;
|
|
Match = RtlEqualUnicodeString (&ObjectName->Name, &ValueString, TRUE);
|
|
if (Match && !AddOwner) {
|
|
// Free ownership
|
|
ZwDeleteValueKey( Dir->RegHandle[HOWNER_MAP], &KeyString);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ExFreePool (KeyName);
|
|
return Match;
|
|
}
|
|
|
|
/*++
|
|
Routine Description:
|
|
IO_DESC_MIN - Returns the descriptor's MIN,MAX or ALIGMENT requirements
|
|
IO_DESC_MAX
|
|
--*/
|
|
INLINE LONGLONG IO_DESC_MIN (IN PIO_RESOURCE_DESCRIPTOR Desc)
|
|
{
|
|
LONGLONG li;
|
|
|
|
switch (Desc->Type) {
|
|
case CmResourceTypePort:
|
|
li = Desc->u.Port.MinimumAddress.QuadPart;
|
|
break;
|
|
case CmResourceTypeMemory:
|
|
li = Desc->u.Memory.MinimumAddress.QuadPart;
|
|
break;
|
|
case CmResourceTypeInterrupt:
|
|
li = Desc->u.Interrupt.MinimumVector;
|
|
break;
|
|
case CmResourceTypeDma:
|
|
li = Desc->u.Dma.MinimumChannel;
|
|
break;
|
|
}
|
|
|
|
return li;
|
|
}
|
|
|
|
|
|
INLINE LONGLONG IO_DESC_MAX (IN PIO_RESOURCE_DESCRIPTOR Desc)
|
|
/*++
|
|
Routine Description:
|
|
Returns the IO_RESORUCE_DESCRIPTOR's maximum value
|
|
--*/
|
|
{
|
|
LONGLONG li;
|
|
|
|
switch (Desc->Type) {
|
|
case CmResourceTypePort:
|
|
li = Desc->u.Port.MaximumAddress.QuadPart;
|
|
break;
|
|
case CmResourceTypeMemory:
|
|
li = Desc->u.Memory.MaximumAddress.QuadPart;
|
|
break;
|
|
case CmResourceTypeInterrupt:
|
|
li = Desc->u.Interrupt.MaximumVector;
|
|
break;
|
|
case CmResourceTypeDma:
|
|
li = Desc->u.Dma.MaximumChannel;
|
|
break;
|
|
}
|
|
|
|
return li;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
IopGenNextValidResourceList (
|
|
IN ULONG level,
|
|
IN PDIR_RESOURCE_LIST CurList,
|
|
IN PDIR_RESREQ_LIST Dir
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Attempts to find a setting for every required resource in the CurList
|
|
|
|
Arguments:
|
|
|
|
level - Index to which required resource list to start finding resources from
|
|
CurList - List of required resources being processed
|
|
Dir - The top directory of resources
|
|
|
|
PassNo - The pass #
|
|
1 - Preferred settings only
|
|
2 - Available settings
|
|
3 - Available settings, find conflict to report
|
|
|
|
Return Value
|
|
|
|
TRUE if all required resources found available settings
|
|
|
|
--*/
|
|
{
|
|
ULONG collisionlevel;
|
|
BOOLEAN flag;
|
|
|
|
do {
|
|
if (level > CurList->LastLevel) {
|
|
CurList->LastLevel = level;
|
|
}
|
|
|
|
flag = IopGenNextValidDescriptor (level, CurList, Dir, &collisionlevel);
|
|
if (flag == FALSE) {
|
|
// Could not generate a valid descriptor setting
|
|
if (level == 0 || collisionlevel == -1) {
|
|
// No more settings
|
|
CurList->FailedLevel = level;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Backup to the collision level and try anew
|
|
while (level > collisionlevel) {
|
|
CurList->RequiredResource[level]->CurLoc = 0;
|
|
CurList->RequiredResource[level]->RunLen = 0;
|
|
level--;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (CurList->RequiredResource[level]->PassNo == 1 &&
|
|
CurList->RequiredResource[level]->CurPref <
|
|
CurList->RequiredResource[level]->BestPref) {
|
|
// First time through don't mess with unpreferred settings, continue
|
|
// looking at this level
|
|
continue;
|
|
}
|
|
|
|
|
|
// Go to next level
|
|
level++;
|
|
} while (level < CurList->NoRequiredResources);
|
|
|
|
// Determine list's preference
|
|
// (only used on PassNo > 1 since PassNo == 1 only suceedes when
|
|
// preferred settings are used)
|
|
CurList->CurPref = 0;
|
|
for (level = 0; level < CurList->NoRequiredResources; level++) {
|
|
CurList->CurPref += CurList->RequiredResource[level]->CurPref;
|
|
}
|
|
|
|
// Got a setting for each requested resource, return TRUE
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
IopGenNextValidDescriptor (
|
|
IN ULONG level,
|
|
IN PDIR_RESOURCE_LIST CurList,
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
OUT PULONG collisionlevel
|
|
)
|
|
/*++
|
|
Return Value
|
|
TRUE if descriptor setting was found
|
|
FALSE if no setting found
|
|
--*/
|
|
{
|
|
PDIR_REQUIRED_RESOURCE Res, CRes;
|
|
PIO_RESOURCE_DESCRIPTOR *Desc, DescTmp;
|
|
LONGLONG BAddr, EAddr;
|
|
LONGLONG NBAddr;
|
|
LONGLONG DescMax, MinAddr, LiILen, LiELen, LiTmp;
|
|
LONGLONG NAddr, BusMax, BusMin, PBAddr;
|
|
ULONG indx, j, k, NBLoc;
|
|
ULONG DescLen, Align, len;
|
|
BOOLEAN NBSet, flag, flag2;
|
|
LONG Preference, NPref;
|
|
UCHAR TType, NTType;
|
|
TENTRY Trans, NTrans;
|
|
|
|
Res = CurList->RequiredResource[level];
|
|
|
|
*collisionlevel = (ULONG) -1; // assume no collision
|
|
NBSet = FALSE;
|
|
|
|
do {
|
|
Desc = &Res->IoResourceDescriptor[Res->CurLoc];
|
|
if (!Res->RunLen) {
|
|
if (Res->CurLoc >= Res->NoAlternatives) {
|
|
// No more runs
|
|
return FALSE;
|
|
}
|
|
|
|
// Get number of alternatives which are of the same type
|
|
// (alternatives have been sorted into types).
|
|
Res->Type = Desc[0]->Type;
|
|
for (j=Res->CurLoc; j < Res->NoAlternatives; j++) {
|
|
if (Res->Type != Res->IoResourceDescriptor[j]->Type) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Res->RunLen = j - Res->CurLoc;
|
|
if (!Res->RunLen) {
|
|
// Out of alternatives for this resource
|
|
return FALSE;
|
|
}
|
|
|
|
// Start at beginning of bus options
|
|
Res->CurBusLoc = 0;
|
|
DescTmp = Dir->BusDir->Alternative->ResourceByType[Res->Type]->IoResourceDescriptor[0];
|
|
if (!DescTmp) {
|
|
// There are no bus settings for this type of resource
|
|
return FALSE;
|
|
}
|
|
|
|
Res->CurBusMin = IO_DESC_MIN (DescTmp);
|
|
Res->CurBusMax = IO_DESC_MAX (DescTmp);
|
|
NAddr = Res->CurBusMax;
|
|
} else {
|
|
// Decrease current value by one - this will cause this
|
|
// function to find the next acceptable value.
|
|
NAddr = Res->CurBAddr - 1;
|
|
}
|
|
|
|
|
|
// Return the next available address from NAddr
|
|
|
|
|
|
DescLen = Res->RunLen;
|
|
BusMax = Res->CurBusMax;
|
|
BusMin = Res->CurBusMin;
|
|
|
|
NBAddr = 0;
|
|
|
|
for (; ;) {
|
|
|
|
|
|
// Loop for each descriptor in this run and pick the numerical highest
|
|
// value available for this resource
|
|
|
|
|
|
for (indx=0; indx < DescLen ; indx++) {
|
|
|
|
|
|
// Set len, Align, MinAddr, DescMax
|
|
|
|
|
|
DescTmp = Desc[indx];
|
|
switch (DescTmp->Type) {
|
|
case CmResourceTypePort:
|
|
len = DescTmp->u.Port.Length;
|
|
Align = DescTmp->u.Port.Alignment;
|
|
MinAddr = DescTmp->u.Port.MinimumAddress.QuadPart;
|
|
DescMax = DescTmp->u.Port.MaximumAddress.QuadPart;
|
|
break;
|
|
|
|
case CmResourceTypeMemory:
|
|
len = DescTmp->u.Memory.Length;
|
|
Align = DescTmp->u.Memory.Alignment;
|
|
MinAddr = DescTmp->u.Memory.MinimumAddress.QuadPart;
|
|
DescMax = DescTmp->u.Memory.MaximumAddress.QuadPart;
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
len = 1;
|
|
Align = 1;
|
|
MinAddr = DescTmp->u.Interrupt.MinimumVector;
|
|
DescMax = DescTmp->u.Interrupt.MaximumVector;
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
len = 1;
|
|
Align = 1;
|
|
MinAddr = DescTmp->u.Dma.MinimumChannel;
|
|
DescMax = DescTmp->u.Dma.MaximumChannel;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
// MinAddr is the largest of Descriptor-MinAddr, Bus-MinAddr, or
|
|
// NextBest-MinAddr. Don't go below the last MinAddr (NBAddr).
|
|
// So the search is from NAddr -to-> NBAddr
|
|
|
|
|
|
if (BusMin > MinAddr) {
|
|
MinAddr = BusMin;
|
|
}
|
|
|
|
if (NBAddr > MinAddr) {
|
|
MinAddr = NBAddr;
|
|
}
|
|
|
|
BAddr = NAddr;
|
|
LiELen = len; // Exclusive length
|
|
LiILen = len - 1; // Inclusive length
|
|
|
|
|
|
// Set initial preference
|
|
|
|
|
|
Preference = 0;
|
|
if (Res->PassNo == 1) {
|
|
if (DescTmp->Option & IO_RESOURCE_PREFERRED) {
|
|
// Account for device's preference durning first pass
|
|
Preference = 1;
|
|
|
|
} else if (Res->BestPref) {
|
|
// Some resource in this list has a prefernce, but it's not
|
|
// this one. Since this is the PassNo == 1 skip non-preferred.
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Loop while BAddr being tested is above MinAddr
|
|
|
|
|
|
while (BAddr >= MinAddr) {
|
|
|
|
EAddr = BAddr + LiILen;
|
|
if (EAddr > DescMax) {
|
|
|
|
// The ending address is above the requested limit
|
|
// compute the best possible beginning address
|
|
|
|
|
|
BAddr = DescMax - LiILen;
|
|
continue;
|
|
}
|
|
|
|
if (EAddr > BusMax) {
|
|
|
|
// The ending address is above the bus'es limit
|
|
// compute best possible beginning address
|
|
|
|
|
|
BAddr = BusMax - LiILen;
|
|
continue;
|
|
}
|
|
|
|
|
|
// Verify selection is within any user supplied requirements
|
|
// (this is from RegistryPath\AssignResources)
|
|
|
|
|
|
if (Dir->UserDir) {
|
|
CRes = Dir->UserDir->Alternative->ResourceByType[Res->Type];
|
|
flag = FALSE;
|
|
PBAddr = -1;
|
|
|
|
for (j=0; j < CRes->NoAlternatives; j++) {
|
|
LiTmp = IO_DESC_MIN (CRes->IoResourceDescriptor[j]);
|
|
|
|
if (BAddr < LiTmp) {
|
|
|
|
// Beginning address is before user's range, check
|
|
// next descriptor
|
|
|
|
|
|
continue;
|
|
}
|
|
|
|
LiTmp = IO_DESC_MAX (CRes->IoResourceDescriptor[j]);
|
|
if (EAddr > LiTmp) {
|
|
|
|
|
|
// Ending address is above user's range.
|
|
// Check for new BAddr to continue from
|
|
|
|
|
|
LiTmp = LiTmp - LiILen;
|
|
if (LiTmp > PBAddr && LiTmp < BAddr) {
|
|
|
|
|
|
// Update next possible setting
|
|
|
|
|
|
PBAddr = LiTmp;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
|
|
// Within user's requested range
|
|
|
|
|
|
flag = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (!flag) {
|
|
BAddr = PBAddr;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
// So far resource looks good - translate it to system global
|
|
// settings and verify resource is available
|
|
|
|
|
|
LiTmp = 0;
|
|
switch (Res->Type) {
|
|
case CmResourceTypePort:
|
|
case CmResourceTypeMemory:
|
|
j = k = Res->Type == CmResourceTypePort ? 1 : 0;
|
|
flag = HalTranslateBusAddress (
|
|
Dir->IoResourceReq->InterfaceType,
|
|
Dir->IoResourceReq->BusNumber,
|
|
*((PPHYSICAL_ADDRESS) &BAddr),
|
|
&j,
|
|
(PPHYSICAL_ADDRESS) &Trans.BAddr
|
|
);
|
|
|
|
// precheck alignment on first half
|
|
if (Align > 1 && (Trans.BAddr & 0xffffffff00000000) == 0) {
|
|
RtlEnlargedUnsignedDivide (
|
|
*((PULARGE_INTEGER) &Trans.BAddr), Align, (PULONG) &LiTmp);
|
|
|
|
if (LiTmp & 0xffffffff) {
|
|
break; // alignment is off - don't bother with second translation
|
|
}
|
|
}
|
|
|
|
flag2 = HalTranslateBusAddress (
|
|
Dir->IoResourceReq->InterfaceType,
|
|
Dir->IoResourceReq->BusNumber,
|
|
*((PPHYSICAL_ADDRESS) &EAddr),
|
|
&k,
|
|
(PPHYSICAL_ADDRESS) &Trans.EAddr
|
|
);
|
|
|
|
TType = j == 1 ? CmResourceTypePort : CmResourceTypeMemory;
|
|
Trans.Affinity = (KAFFINITY) -1;
|
|
|
|
if (flag == FALSE || flag2 == FALSE || j != k) {
|
|
// HalAdjustResourceList should ensure that the returned range
|
|
// for the bus is within the bus limits and no translation
|
|
// within those limits should ever fail
|
|
|
|
DBGMSG ("IopGenNextValidDescriptor: Error return for HalTranslateBusAddress\n");
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
TType = CmResourceTypeInterrupt;
|
|
|
|
Trans.Affinity = 0;
|
|
Trans.BAddr = HalGetInterruptVector (
|
|
Dir->IoResourceReq->InterfaceType,
|
|
Dir->IoResourceReq->BusNumber,
|
|
(ULONG) BAddr, // bus level
|
|
(ULONG) BAddr, // bus vector
|
|
(PKIRQL) &j, // translated level
|
|
&Trans.Affinity
|
|
);
|
|
|
|
Trans.EAddr = Trans.BAddr;
|
|
|
|
if (Trans.Affinity == 0) {
|
|
// skip vectors which can not be translated
|
|
LiTmp = 1;
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
TType = CmResourceTypeDma;
|
|
Trans.BAddr = BAddr;
|
|
Trans.EAddr = EAddr;
|
|
Trans.Affinity = (KAFFINITY) -1;
|
|
break;
|
|
|
|
default:
|
|
DBGMSG ("IopGenNextValidDescriptor: Invalid resource type\n");
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Check bias from translation
|
|
|
|
|
|
if (LiTmp != 0) {
|
|
|
|
// move to next address
|
|
BAddr = BAddr - LiTmp;
|
|
continue;
|
|
}
|
|
|
|
|
|
// Check alignment restrictions
|
|
|
|
|
|
if (Align > 1) {
|
|
if ((Trans.BAddr & 0xffffffff00000000) == 0) {
|
|
RtlEnlargedUnsignedDivide (
|
|
*((PULARGE_INTEGER) &Trans.BAddr), Align, (PULONG) &LiTmp);
|
|
} else {
|
|
RtlExtendedLargeIntegerDivide (
|
|
*((PLARGE_INTEGER) &Trans.BAddr), Align, (PULONG) &LiTmp);
|
|
|
|
}
|
|
|
|
if (LiTmp != 0) {
|
|
|
|
// Starting address not on proper alignment, move to next
|
|
// aligned address
|
|
|
|
|
|
BAddr = BAddr - LiTmp;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
// Check for collision with other settings being considered
|
|
|
|
|
|
for (j=0; j < level; j++) {
|
|
if (CurList->RequiredResource[j]->TType == TType) {
|
|
CRes = CurList->RequiredResource[j];
|
|
if (DoesTEntryCollide (Trans, CRes->Trans)) {
|
|
// collision
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (j < level) {
|
|
|
|
// Current BAddr - EAddr collides with CRes selection
|
|
|
|
|
|
if (j < *collisionlevel) {
|
|
|
|
|
|
// If we fail, back up to this level
|
|
|
|
|
|
*collisionlevel = j;
|
|
}
|
|
|
|
|
|
// Try BAddr just best address before collision range
|
|
|
|
|
|
BAddr = CRes->CurBAddr - LiELen;
|
|
continue;
|
|
}
|
|
|
|
|
|
// Check InUse system resources to verify this range is available.
|
|
|
|
|
|
j = IopFindCollisionInTList (&Trans, Dir->InUseResources.ByType[TType]);
|
|
if (j) {
|
|
if (Res->PassNo == 3) {
|
|
|
|
// Track this collision
|
|
|
|
|
|
IopPickupCollisionInTList (
|
|
CurList,
|
|
Res->Type,
|
|
BAddr,
|
|
&Trans,
|
|
Dir->InUseResources.ByType[TType]
|
|
);
|
|
}
|
|
|
|
|
|
// This range collides with a resource which is already in use.
|
|
// Moving begining address to next possible setting
|
|
|
|
|
|
BAddr = BAddr - j;
|
|
continue;
|
|
}
|
|
|
|
|
|
// Check to see if this resource selection is being shared
|
|
|
|
|
|
j = IopFindCollisionInTList (&Trans, Dir->InUseSharableResources.ByType[TType]);
|
|
if (j) {
|
|
|
|
// Current range collided with a resource which is already in use,
|
|
// but is sharable. If the current required resource is not sharable,
|
|
// then skip this range; otherwise, reduce the preference for this setting.
|
|
|
|
|
|
if (Res->PassNo == 1 || Desc[indx]->ShareDisposition != CmResourceShareShared) {
|
|
if (Res->PassNo == 3) {
|
|
|
|
// Track this collision
|
|
|
|
|
|
IopPickupCollisionInTList (
|
|
CurList,
|
|
Res->Type,
|
|
BAddr,
|
|
&Trans,
|
|
Dir->InUseSharableResources.ByType[TType]
|
|
);
|
|
}
|
|
|
|
// required resource can't be shared, move to next possible setting or
|
|
// this is the Pass#1 and we don't bother with non-preferred settings
|
|
|
|
BAddr = BAddr - j;
|
|
continue;
|
|
}
|
|
|
|
Preference -= 4;
|
|
}
|
|
|
|
|
|
// Check to see if this resource reserved, but sharable
|
|
|
|
|
|
j = IopFindCollisionInTList (&Trans, Dir->ReservedSharableResources.ByType[TType]);
|
|
if (j) {
|
|
|
|
// Current range collosided with a resource which is in the
|
|
// ReservedResource list, but is marked sharable. These resources
|
|
// are treated as non-preferred regions.
|
|
|
|
|
|
if (Res->PassNo == 1) {
|
|
// don't bother with non-preferred settings on the first pass.
|
|
|
|
BAddr = BAddr - j;
|
|
continue;
|
|
}
|
|
|
|
Preference -= 2;
|
|
}
|
|
|
|
|
|
// BAddr - EAddr is a good selection
|
|
// (BAddr is greater than NBAddr)
|
|
|
|
|
|
NBSet = TRUE;
|
|
NBAddr = BAddr;
|
|
|
|
NTType = TType;
|
|
NTrans = Trans;
|
|
NPref = Preference;
|
|
NBLoc = Res->CurLoc + indx;
|
|
break; // check next selector in run
|
|
|
|
} // next BAddr
|
|
} // next descriptor in run
|
|
|
|
if (NBSet) {
|
|
// SUCCESS We have a hit
|
|
break;
|
|
}
|
|
|
|
|
|
// No setting so far, move to next bus ordering descriptor
|
|
|
|
|
|
Res->CurBusLoc++;
|
|
CRes = Dir->BusDir->Alternative->ResourceByType[Res->Type];
|
|
|
|
if (Res->CurBusLoc >= CRes->NoAlternatives) {
|
|
|
|
// no more bus ordering descriptors, move to next ResRun
|
|
|
|
|
|
Res->CurLoc += Res->RunLen;
|
|
Res->RunLen = 0;
|
|
break;
|
|
}
|
|
|
|
DescTmp = CRes->IoResourceDescriptor[Res->CurBusLoc];
|
|
Res->CurBusMin = IO_DESC_MIN (DescTmp);
|
|
Res->CurBusMax = IO_DESC_MAX (DescTmp);
|
|
BusMin = Res->CurBusMin;
|
|
BusMax = Res->CurBusMax;
|
|
NAddr = Res->CurBusMax;
|
|
} // next bus ordering descriptor
|
|
|
|
} while (!NBSet);
|
|
|
|
|
|
// We have a setting for this resource. Remember it and return.
|
|
|
|
|
|
Res->TType = NTType; // used to detect internal conflicts of translated values
|
|
Res->Trans = NTrans; // "
|
|
|
|
Res->CurPref = NPref; // Return prefernce of setting
|
|
Res->CurBAddr = NBAddr; // Return raw BAddr of resource (used by Phase3&4)
|
|
Res->CurBLoc = NBLoc; // Return location of resource (used by Phase3&4)
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
ULONG
|
|
IopFindCollisionInTList (
|
|
IN PTENTRY SEntry,
|
|
IN PLTENTRY List
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks to see if there's a collision between the source TENTRY and the list
|
|
of TENTRIES passed by PLTENTRY.
|
|
|
|
Arguments:
|
|
|
|
Return Value
|
|
|
|
Returns the skew amount required to continue searching for next possible
|
|
setting and a pointer to the conflicted entry.
|
|
A zero skew means no collision occured.
|
|
|
|
--*/
|
|
{
|
|
LONGLONG LiTmp;
|
|
TENTRY Source;
|
|
ULONG i, j;
|
|
|
|
Source = *SEntry;
|
|
while (List) {
|
|
j = List->CurEntries;
|
|
for (i=0; i < j; i++) {
|
|
SEntry = List->Table+i;
|
|
if (DoesTEntryCollide (Source, *SEntry)) {
|
|
|
|
LiTmp = Source.EAddr - SEntry->BAddr;
|
|
return (ULONG) LiTmp + 1;
|
|
}
|
|
}
|
|
List = List->Next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
IopPickupCollisionInTList (
|
|
IN PDIR_RESOURCE_LIST CurList,
|
|
IN UCHAR Type,
|
|
IN LONGLONG BAddr,
|
|
IN PTENTRY SEntry,
|
|
IN PLTENTRY List
|
|
)
|
|
{
|
|
TENTRY Source;
|
|
ULONG i, j, conflicts;
|
|
|
|
Source = *SEntry;
|
|
|
|
|
|
// If resource already listed in easy collision list, skip it
|
|
|
|
|
|
j = CurList->Conflict.NoConflicts;
|
|
if (j > SCONFLICT) {
|
|
j = SCONFLICT;
|
|
}
|
|
|
|
for (i=0; i < j; i++) {
|
|
if (CurList->Conflict.EasyConflict[i].BAddr == BAddr &&
|
|
CurList->Conflict.EasyConflict[i].Type == Type) {
|
|
return ;
|
|
}
|
|
}
|
|
|
|
|
|
// Add valid, but conflicting, resource setting to failed list
|
|
|
|
|
|
conflicts = CurList->Conflict.NoConflicts;
|
|
if (conflicts < SCONFLICT) {
|
|
CurList->Conflict.EasyConflict[conflicts].Type = Type;
|
|
CurList->Conflict.EasyConflict[conflicts].BAddr = BAddr;
|
|
}
|
|
|
|
|
|
// Find collision
|
|
|
|
|
|
while (List) {
|
|
j = List->CurEntries;
|
|
for (i=0; i < j; i++) {
|
|
SEntry = List->Table+i;
|
|
if (DoesTEntryCollide (Source, *SEntry)) {
|
|
|
|
if (SEntry->Owner) {
|
|
if (conflicts < SCONFLICT) {
|
|
CurList->Conflict.EasyConflict[conflicts].Owner = SEntry->Owner;
|
|
SEntry->Owner->InConflict.Flink = (PVOID) -1;
|
|
}
|
|
|
|
if (SEntry->Owner->InConflict.Flink == NULL) {
|
|
|
|
// Add owner of this conflict to list of colliding owners
|
|
|
|
|
|
InsertTailList (&CurList->Conflict.OtherConflicts, &SEntry->Owner->InConflict);
|
|
}
|
|
|
|
}
|
|
|
|
CurList->Conflict.NoConflicts += 1;
|
|
return ;
|
|
}
|
|
}
|
|
List = List->Next;
|
|
}
|
|
}
|
|
|
|
|
|
STATIC PVOID
|
|
IopAllocateDirPool (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN ULONG Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates pool and links the allocation to the DIR_RESREQ_LIST structure so it will be freed
|
|
when the DIR_RESRES_LIST is freed.
|
|
|
|
WARNING: Just like ExAllocatePool this function needs to return memory aligned on 8 byte
|
|
boundaries.
|
|
|
|
--*/
|
|
{
|
|
PUSED_HEAP ph;
|
|
|
|
ph = (PUSED_HEAP) ExAllocatePool (PagedPool, Length+sizeof(USED_HEAP));
|
|
if (!ph) {
|
|
return NULL;
|
|
}
|
|
|
|
ph->FreeHeap = (PVOID) ph;
|
|
PushEntryList (&Dir->AllocatedHeap, &ph->FreeLink);
|
|
return (PVOID) (ph+1);
|
|
}
|
|
|
|
|
|
|
|
PIO_RESOURCE_REQUIREMENTS_LIST
|
|
IopGetResourceReqRegistryValue (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN HANDLE KeyHandle,
|
|
IN PWSTR ValueName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Looks up the setting for ValueKey in KeyHandle and returns the
|
|
data or NULL. If non-null, the memory was obtained via pool.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PKEY_VALUE_FULL_INFORMATION KeyInformation;
|
|
NTSTATUS status;
|
|
PUCHAR Data;
|
|
ULONG DataLength, Type;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST p;
|
|
|
|
for (; ;) {
|
|
status = IopGetRegistryValue (KeyHandle, ValueName, &KeyInformation);
|
|
if (!NT_SUCCESS(status)) {
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// Get pointer to data & length
|
|
|
|
|
|
Type = KeyInformation->Type;
|
|
Data = ((PUCHAR) KeyInformation + KeyInformation->DataOffset);
|
|
DataLength = KeyInformation->DataLength;
|
|
|
|
|
|
// Copy data to aligned paged pool buffer, and free non-paged pool
|
|
|
|
|
|
p = (PIO_RESOURCE_REQUIREMENTS_LIST) IopAllocateDirPool (Dir, DataLength + sizeof (WCHAR));
|
|
if (!p) {
|
|
ExFreePool (KeyInformation);
|
|
return NULL;
|
|
}
|
|
|
|
RtlCopyMemory (p, Data, DataLength);
|
|
ExFreePool (KeyInformation);
|
|
|
|
if (Type == REG_SZ) {
|
|
|
|
// Forward to different entry - Need to copy name in order to get
|
|
// space at the end to add the NULL terminator
|
|
|
|
|
|
ValueName = (PWSTR) p;
|
|
ValueName [DataLength / sizeof (WCHAR)] = 0;
|
|
continue;
|
|
}
|
|
|
|
// verify registry entry is of expected type
|
|
if (Type != REG_RESOURCE_REQUIREMENTS_LIST) {
|
|
return NULL;
|
|
}
|
|
|
|
p->ListSize = DataLength;
|
|
return p;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if 0
|
|
NTSTATUS
|
|
IopAssignResourcesPhase1 (
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources,
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST *pCopiedList
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Copies the callers supplied resource list and passes it to the HAL. The HAL
|
|
then adjusts the requested resource list to be within any bus/system requirements
|
|
the system may have.
|
|
Arguments:
|
|
IoResources - Callers requested resource list
|
|
*pCopiedList - Returned resource list (allocated from heap)
|
|
--*/
|
|
{
|
|
PIO_RESOURCE_LIST ResourceList;
|
|
NTSTATUS status;
|
|
ULONG cnt, length;
|
|
PUCHAR FirstAddress, LastAddress;
|
|
|
|
PAGED_CODE();
|
|
|
|
// Verify Version & Revision of data structure is set correctly
|
|
if (IoResources->AlternativeLists == 0 ||
|
|
IoResources->Reserved[0] != 0 ||
|
|
IoResources->Reserved[1] != 0 ||
|
|
IoResources->Reserved[2] != 0) {
|
|
DBGMSG ("IopAssignResourcesPhase1: Bad structure format\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Pass a copy of the list to the HAL for any adjustments
|
|
|
|
// Simple sanity check for size of callers RequestedResource list
|
|
|
|
ResourceList = IoResources->List;
|
|
FirstAddress = (PUCHAR) ResourceList;
|
|
LastAddress = (PUCHAR) IoResources + IoResources->ListSize;
|
|
|
|
for (cnt=0; cnt < IoResources->AlternativeLists; cnt++) {
|
|
if (ResourceList->Version != 1 || ResourceList->Revision < 1) {
|
|
DBGMSG ("IopAssignResourcesPhase1: Invalid version #\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ResourceList = (PIO_RESOURCE_LIST)(&ResourceList->Descriptors[ResourceList->Count]);
|
|
|
|
if ((PUCHAR) ResourceList < FirstAddress ||
|
|
(PUCHAR) ResourceList > LastAddress) {
|
|
DBGMSG ("IopAssignResourcesPhase1: IO_RESOURCE_LIST.ListSize too small\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
length = (ULONG) ((PUCHAR) ResourceList - (PUCHAR) IoResources);
|
|
|
|
|
|
// Copy user's passed in list
|
|
|
|
|
|
*pCopiedList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool (PagedPool, length);
|
|
if (!*pCopiedList) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory (*pCopiedList, IoResources, length);
|
|
(*pCopiedList)->ListSize = length;
|
|
|
|
// Let hal adjust the requested list
|
|
|
|
status = HalAdjustResourceList (pCopiedList);
|
|
if (!NT_SUCCESS(status)) {
|
|
DBGMSG ("IopAssignResourcesPhase1: HalAdjustResourceList failed\n");
|
|
ExFreePool (*pCopiedList);
|
|
return status;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IopAssignResourcesPhase2 (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PUNICODE_STRING DriverClassName,
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
/*
|
|
|
|
Routine Description:
|
|
|
|
Reads the ResourceMap in the registry and builds a canonical list of
|
|
all in use resources ranges by resource type.
|
|
|
|
Arguments:
|
|
|
|
Dir - InUseResources & InUseShareableResources are filled in by this call.
|
|
|
|
*/
|
|
{
|
|
HANDLE ResourceMap, ClassKeyHandle, DriverKeyHandle;
|
|
ULONG ClassKeyIndex, DriverKeyIndex, DriverValueIndex, Index;
|
|
POBJECT_NAME_INFORMATION ObNameInfo;
|
|
PCM_RESOURCE_LIST CmResList;
|
|
PCM_FULL_RESOURCE_DESCRIPTOR CmFResDesc;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc;
|
|
UNICODE_STRING unicodeString;
|
|
UNICODE_STRING KeyName, TranslatedName, DriverName, DClassName;
|
|
PVOID p2;
|
|
ULONG BufferSize;
|
|
union {
|
|
PVOID Buffer;
|
|
PKEY_BASIC_INFORMATION KeyBInf;
|
|
PKEY_FULL_INFORMATION KeyFInf;
|
|
PKEY_VALUE_FULL_INFORMATION VKeyFInf;
|
|
} U;
|
|
PUCHAR LastAddr;
|
|
ULONG junk, Length, i, j, TranslatedStrLen, BusTranslatedStrLen;
|
|
PWSTR pw;
|
|
NTSTATUS status;
|
|
BOOLEAN sameClass, sameDriver;
|
|
BOOLEAN flag;
|
|
POWNER Owner;
|
|
LONGLONG li;
|
|
|
|
PAGED_CODE();
|
|
|
|
|
|
// Allocate a scratch buffer. Use BUFFSERSIZE or the sizeof the largest
|
|
// value in SystemResources\ReservedResources
|
|
|
|
|
|
U.Buffer = Dir->Buffer;
|
|
U.KeyFInf->MaxValueNameLen = U.KeyFInf->MaxValueDataLen = 0;
|
|
ZwQueryKey( Dir->RegHandle[HRESERVEDRESOURCES],
|
|
KeyFullInformation,
|
|
U.KeyFInf,
|
|
BUFFERSIZE,
|
|
&junk );
|
|
|
|
Length = sizeof( KEY_VALUE_FULL_INFORMATION ) +
|
|
U.KeyFInf->MaxValueNameLen + U.KeyFInf->MaxValueDataLen + sizeof(UNICODE_NULL);
|
|
|
|
BufferSize = Length > BUFFERSIZE ? Length : BUFFERSIZE;
|
|
U.Buffer = ExAllocatePool (PagedPool, BufferSize);
|
|
if (!U.Buffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
|
|
// Build translated registry name to watch for
|
|
|
|
|
|
ObNameInfo = (POBJECT_NAME_INFORMATION) Dir->Buffer;
|
|
if (DeviceObject) {
|
|
status = ObQueryNameString (DeviceObject, ObNameInfo, BUFFERSIZE, &Length);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
} else {
|
|
ObNameInfo->Name.Length = 0;
|
|
ObNameInfo->Name.Buffer = (PVOID) ((PUCHAR) Dir->Buffer + sizeof(OBJECT_NAME_INFORMATION));
|
|
}
|
|
|
|
|
|
// Handle the case when the DeviceObject was created
|
|
// without a name
|
|
|
|
if (ObNameInfo->Name.Buffer == NULL) {
|
|
ObNameInfo->Name.Length = 0;
|
|
ObNameInfo->Name.Buffer = (PVOID) ((PUCHAR) Dir->Buffer + sizeof(OBJECT_NAME_INFORMATION));
|
|
}
|
|
|
|
ObNameInfo->Name.MaximumLength = BUFFERSIZE - sizeof(OBJECT_NAME_INFORMATION);
|
|
RtlAppendUnicodeToString (&ObNameInfo->Name, IopWstrTranslated);
|
|
|
|
TranslatedName.Length = ObNameInfo->Name.Length;
|
|
TranslatedName.MaximumLength = ObNameInfo->Name.Length;
|
|
TranslatedName.Buffer = IopAllocateDirPool (Dir, TranslatedName.Length);
|
|
if (!TranslatedName.Buffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlCopyMemory (TranslatedName.Buffer, ObNameInfo->Name.Buffer, TranslatedName.Length);
|
|
for (TranslatedStrLen=0; IopWstrTranslated[TranslatedStrLen]; TranslatedStrLen++) ;
|
|
for (BusTranslatedStrLen=0; IopWstrBusTranslated[BusTranslatedStrLen]; BusTranslatedStrLen++) ;
|
|
TranslatedStrLen *= sizeof (WCHAR);
|
|
BusTranslatedStrLen *= sizeof (WCHAR);
|
|
|
|
|
|
// Build driver name to watch for
|
|
|
|
|
|
status = ObQueryNameString (DriverObject, ObNameInfo, BUFFERSIZE, &Length);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
i = 0;
|
|
pw = ObNameInfo->Name.Buffer;
|
|
while (*pw) {
|
|
if (*pw++ == OBJ_NAME_PATH_SEPARATOR) {
|
|
i = pw - ObNameInfo->Name.Buffer;
|
|
}
|
|
}
|
|
|
|
Length = ObNameInfo->Name.Length - i * sizeof (WCHAR);
|
|
DriverName.Length = (USHORT) Length;
|
|
DriverName.MaximumLength = (USHORT) Length;
|
|
DriverName.Buffer = IopAllocateDirPool (Dir, Length);
|
|
if (!DriverName.Buffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlCopyMemory (DriverName.Buffer, ObNameInfo->Name.Buffer + i, Length);
|
|
|
|
|
|
// If no give driver class, use default
|
|
|
|
|
|
if (!DriverClassName) {
|
|
RtlInitUnicodeString( &DClassName, IopWstrOtherDrivers );
|
|
DriverClassName = &DClassName;
|
|
}
|
|
|
|
|
|
// Walk resource map and collect any inuse resources
|
|
|
|
|
|
ResourceMap = Dir->RegHandle[HRESOURCE_MAP];
|
|
ClassKeyIndex = 0;
|
|
|
|
ClassKeyHandle = INVALID_HANDLE;
|
|
DriverKeyHandle = INVALID_HANDLE;
|
|
|
|
while (NT_SUCCESS(status)) {
|
|
|
|
|
|
// Get the class information
|
|
|
|
|
|
status = ZwEnumerateKey( ResourceMap,
|
|
ClassKeyIndex++,
|
|
KeyBasicInformation,
|
|
U.KeyBInf,
|
|
BufferSize,
|
|
&junk );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
// Create a UNICODE_STRING using the counted string passed back to
|
|
// us in the information structure, and open the class key.
|
|
|
|
|
|
KeyName.Buffer = (PWSTR) U.KeyBInf->Name;
|
|
KeyName.Length = (USHORT) U.KeyBInf->NameLength;
|
|
KeyName.MaximumLength = (USHORT) U.KeyBInf->NameLength;
|
|
|
|
status = IopOpenRegistryKey( &ClassKeyHandle,
|
|
ResourceMap,
|
|
&KeyName,
|
|
KEY_READ,
|
|
FALSE );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
|
|
// Check if we are in the same call node.
|
|
|
|
|
|
sameClass = RtlEqualUnicodeString( DriverClassName, &KeyName, TRUE );
|
|
|
|
DriverKeyIndex = 0;
|
|
while (NT_SUCCESS (status)) {
|
|
|
|
|
|
// Get the class information
|
|
|
|
|
|
status = ZwEnumerateKey( ClassKeyHandle,
|
|
DriverKeyIndex++,
|
|
KeyBasicInformation,
|
|
U.KeyBInf,
|
|
BufferSize,
|
|
&junk );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
|
|
// Create a UNICODE_STRING using the counted string passed back to
|
|
// us in the information structure, and open the class key.
|
|
|
|
// This is read from the key we created, and the name
|
|
// was NULL terminated.
|
|
|
|
|
|
KeyName.Buffer = (PWSTR) IopAllocateDirPool (Dir, U.KeyBInf->NameLength);
|
|
if (!KeyName.Buffer) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
RtlCopyMemory (KeyName.Buffer, U.KeyBInf->Name, U.KeyBInf->NameLength);
|
|
KeyName.Length = (USHORT) U.KeyBInf->NameLength;
|
|
KeyName.MaximumLength = (USHORT) U.KeyBInf->NameLength;
|
|
|
|
status = IopOpenRegistryKey( &DriverKeyHandle,
|
|
ClassKeyHandle,
|
|
&KeyName,
|
|
KEY_READ,
|
|
FALSE );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
// Check if we are in the same call node.
|
|
|
|
|
|
sameDriver = sameClass && RtlEqualUnicodeString( &DriverName, &KeyName, TRUE );
|
|
|
|
|
|
// Get full information for that key so we can get the
|
|
// information about the data stored in the key.
|
|
|
|
|
|
status = ZwQueryKey( DriverKeyHandle,
|
|
KeyFullInformation,
|
|
U.KeyFInf,
|
|
BufferSize,
|
|
&junk );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
Length = sizeof( KEY_VALUE_FULL_INFORMATION ) +
|
|
U.KeyFInf->MaxValueNameLen + U.KeyFInf->MaxValueDataLen + sizeof(UNICODE_NULL);
|
|
|
|
if (Length > BufferSize) {
|
|
|
|
|
|
// Get a larger buffer
|
|
|
|
|
|
p2 = ExAllocatePool (PagedPool, Length);
|
|
if (!p2) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
ExFreePool (U.Buffer);
|
|
U.Buffer = p2;
|
|
BufferSize = Length;
|
|
}
|
|
|
|
DriverValueIndex = 0;
|
|
for (; ;) {
|
|
status = ZwEnumerateValueKey( DriverKeyHandle,
|
|
DriverValueIndex++,
|
|
KeyValueFullInformation,
|
|
U.VKeyFInf,
|
|
BufferSize,
|
|
&junk );
|
|
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
|
|
// If this is not a translated resource list, skip it.
|
|
|
|
|
|
i = U.VKeyFInf->NameLength;
|
|
if (i < TranslatedStrLen ||
|
|
RtlCompareMemory (
|
|
((PUCHAR) U.VKeyFInf->Name) + i - TranslatedStrLen,
|
|
IopWstrTranslated,
|
|
TranslatedStrLen
|
|
) != TranslatedStrLen
|
|
) {
|
|
// does not end in IopWstrTranslated
|
|
continue;
|
|
}
|
|
|
|
|
|
// If this is a bus translated resource list, ????
|
|
|
|
|
|
if (i >= BusTranslatedStrLen &&
|
|
RtlCompareMemory (
|
|
((PUCHAR) U.VKeyFInf->Name) + i - BusTranslatedStrLen,
|
|
IopWstrBusTranslated,
|
|
BusTranslatedStrLen
|
|
) == BusTranslatedStrLen
|
|
) {
|
|
|
|
// ends in IopWstrBusTranslated
|
|
continue;
|
|
}
|
|
|
|
|
|
// If these used resources are from the caller, then skip them
|
|
|
|
|
|
if (sameDriver) {
|
|
unicodeString.Buffer = (PWSTR) U.VKeyFInf->Name;
|
|
unicodeString.Length = (USHORT) U.VKeyFInf->NameLength;
|
|
unicodeString.MaximumLength = (USHORT) U.VKeyFInf->NameLength;
|
|
if (RtlEqualUnicodeString (&unicodeString, &TranslatedName, TRUE)) {
|
|
// it's the current allocated resources for this caller.
|
|
// skip this entry.
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
// Build Owner structure for TLIST entries
|
|
|
|
|
|
Owner = IopAllocateDirPool (Dir, sizeof (*Owner) + U.VKeyFInf->NameLength);
|
|
if (!Owner) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
Owner->InConflict.Flink = NULL;
|
|
Owner->DeviceName.Buffer = NULL;
|
|
|
|
Owner->KeyName.Buffer = KeyName.Buffer;
|
|
Owner->KeyName.Length = KeyName.Length;
|
|
Owner->KeyName.MaximumLength = KeyName.MaximumLength;
|
|
|
|
if (U.VKeyFInf->Name[0] != L'.') {
|
|
// strip off the .Translated part of the string
|
|
U.VKeyFInf->NameLength -= TranslatedStrLen;
|
|
|
|
Owner->DeviceName.Buffer = Owner->UnicodeBuffer;
|
|
Owner->DeviceName.Length = (USHORT) U.VKeyFInf->NameLength;
|
|
Owner->DeviceName.MaximumLength = (USHORT) U.VKeyFInf->NameLength;
|
|
RtlCopyMemory (Owner->UnicodeBuffer, U.VKeyFInf->Name, U.VKeyFInf->NameLength);
|
|
}
|
|
|
|
|
|
// Run the CmResourceList and save each InUse resource
|
|
|
|
|
|
CmResList = (PCM_RESOURCE_LIST) ( (PUCHAR) U.VKeyFInf + U.VKeyFInf->DataOffset);
|
|
LastAddr = (PUCHAR) CmResList + U.VKeyFInf->DataLength;
|
|
|
|
CmFResDesc = CmResList->List;
|
|
for (i=0; i < CmResList->Count && NT_SUCCESS(status) ; i++) {
|
|
CmDesc = CmFResDesc->PartialResourceList.PartialDescriptors;
|
|
if ((PUCHAR) (CmDesc+1) > LastAddr) {
|
|
if (i) {
|
|
DBGMSG ("IopAssignResourcesPhase2: a. CmResourceList in regitry too short\n");
|
|
}
|
|
break;
|
|
}
|
|
|
|
for (j=0; j < CmFResDesc->PartialResourceList.Count && NT_SUCCESS(status); j++) {
|
|
if ((PUCHAR) (CmDesc+1) > LastAddr) {
|
|
i = CmResList->Count;
|
|
DBGMSG ("IopAssignResourcesPhase2: b. CmResourceList in regitry too short\n");
|
|
break;
|
|
}
|
|
|
|
|
|
// Add this CmDesc to the InUse list
|
|
|
|
if (CmDesc->ShareDisposition == CmResourceShareShared) {
|
|
status = IopAddCmDescriptorToInUseList (Dir, &Dir->InUseSharableResources, CmDesc, Owner);
|
|
} else {
|
|
status = IopAddCmDescriptorToInUseList (Dir, &Dir->InUseResources, CmDesc, Owner);
|
|
}
|
|
CmDesc++;
|
|
}
|
|
|
|
CmFResDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) CmDesc;
|
|
}
|
|
|
|
} // next DriverValueIndex
|
|
|
|
if (DriverKeyHandle != INVALID_HANDLE) {
|
|
ZwClose (DriverKeyHandle);
|
|
DriverKeyHandle = INVALID_HANDLE;
|
|
}
|
|
|
|
if (status == STATUS_NO_MORE_ENTRIES) {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
} // next DriverKeyIndex
|
|
|
|
if (ClassKeyHandle != INVALID_HANDLE) {
|
|
ZwClose (ClassKeyHandle);
|
|
ClassKeyHandle = INVALID_HANDLE;
|
|
}
|
|
|
|
if (status == STATUS_NO_MORE_ENTRIES) {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
} // next ClassKeyIndex
|
|
|
|
if (status == STATUS_NO_MORE_ENTRIES) {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
// All reported resources are read in.
|
|
// Now read in ...SystemResources\ReservedResources
|
|
// (note: this infomration could easily be cached if needed)
|
|
|
|
|
|
|
|
// Build owner for all ResevedResources
|
|
|
|
|
|
Owner = IopAllocateDirPool (Dir, sizeof (*Owner) + U.VKeyFInf->NameLength);
|
|
if (Owner) {
|
|
Owner->InConflict.Flink = NULL;
|
|
Owner->DeviceName.Buffer = NULL;
|
|
RtlInitUnicodeString (&Owner->KeyName, IopWstrReservedResources);
|
|
}
|
|
|
|
Index = 0;
|
|
while (NT_SUCCESS (status)) {
|
|
status = ZwEnumerateValueKey( Dir->RegHandle[HRESERVEDRESOURCES],
|
|
Index++,
|
|
KeyValueFullInformation,
|
|
U.VKeyFInf,
|
|
BufferSize,
|
|
&junk );
|
|
if (!NT_SUCCESS( status )) {
|
|
break;
|
|
}
|
|
|
|
// Run the CmResourceList and save each InUse resource
|
|
|
|
CmResList = (PCM_RESOURCE_LIST) ( (PUCHAR) U.VKeyFInf + U.VKeyFInf->DataOffset);
|
|
LastAddr = (PUCHAR) CmResList + U.VKeyFInf->DataLength;
|
|
|
|
CmFResDesc = CmResList->List;
|
|
for (i=0; i < CmResList->Count && NT_SUCCESS(status) ; i++) {
|
|
CmDesc = CmFResDesc->PartialResourceList.PartialDescriptors;
|
|
if ((PUCHAR) (CmDesc+1) > LastAddr) {
|
|
DBGMSG ("IopAssignResourcesPhase2: c. CmResourceList in regitry too short\n");
|
|
break;
|
|
}
|
|
|
|
for (j=0; j < CmFResDesc->PartialResourceList.Count && NT_SUCCESS(status); j++) {
|
|
if ((PUCHAR) (CmDesc+1) > LastAddr) {
|
|
i = CmResList->Count;
|
|
DBGMSG ("IopAssignResourcesPhase2: d. CmResourceList in regitry too short\n");
|
|
break;
|
|
}
|
|
|
|
// Translate this descriptor to it's TRANSLATED values
|
|
|
|
switch (CmDesc->Type) {
|
|
case CmResourceTypePort:
|
|
case CmResourceTypeMemory:
|
|
junk = CmDesc->Type == CmResourceTypePort ? 1 : 0;
|
|
li = *((LONGLONG UNALIGNED *) &CmDesc->u.Port.Start);
|
|
flag = HalTranslateBusAddress (
|
|
CmFResDesc->InterfaceType,
|
|
CmFResDesc->BusNumber,
|
|
*((PPHYSICAL_ADDRESS) &li),
|
|
&junk,
|
|
(PPHYSICAL_ADDRESS) &li
|
|
);
|
|
*((LONGLONG UNALIGNED *) &CmDesc->u.Port.Start) = li;
|
|
CmDesc->Type = junk == 1 ? CmResourceTypePort : CmResourceTypeMemory;
|
|
break;
|
|
case CmResourceTypeInterrupt:
|
|
CmDesc->u.Interrupt.Vector = HalGetInterruptVector (
|
|
CmFResDesc->InterfaceType,
|
|
CmFResDesc->BusNumber,
|
|
CmDesc->u.Interrupt.Vector, // bus level
|
|
CmDesc->u.Interrupt.Vector, // bus vector
|
|
(PKIRQL) &junk, // translated level
|
|
&CmDesc->u.Interrupt.Affinity
|
|
);
|
|
flag = CmDesc->u.Interrupt.Affinity == 0 ? FALSE : TRUE;
|
|
break;
|
|
case CmResourceTypeDma:
|
|
// no translation
|
|
flag = TRUE;
|
|
break;
|
|
default:
|
|
flag = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (flag) {
|
|
// Add it to the appropiate tlist
|
|
if (CmDesc->ShareDisposition == CmResourceShareShared) {
|
|
status = IopAddCmDescriptorToInUseList (Dir, &Dir->ReservedSharableResources, CmDesc, Owner);
|
|
} else {
|
|
status = IopAddCmDescriptorToInUseList (Dir, &Dir->InUseResources, CmDesc, Owner);
|
|
}
|
|
}
|
|
|
|
CmDesc++;
|
|
}
|
|
|
|
CmFResDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) CmDesc;
|
|
}
|
|
} // Next ReservedResource
|
|
|
|
if (status == STATUS_NO_MORE_ENTRIES) {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
ExFreePool (U.Buffer);
|
|
return status;
|
|
}
|
|
|
|
|
|
#if 0
|
|
PDIR_RESOURCE_LIST IopAssignResourcesPhase3 (IN PDIR_RESREQ_LIST Dir)
|
|
/*++
|
|
Routine Description:
|
|
All the information to process the requested resource assignments has
|
|
been read in & parsed. Phase3 cranks out the resource assignments.
|
|
--*/
|
|
{
|
|
PDIR_RESOURCE_LIST CurList, BestList;
|
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|
ULONG level, i, j;
|
|
LONG BestPref, Pref;
|
|
|
|
|
|
// Run each list as pass 1
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) {
|
|
|
|
// set to pass 1
|
|
for (i=0; i < CurList->NoRequiredResources; i++) {
|
|
CurList->RequiredResource[i]->PassNo = 1;
|
|
}
|
|
|
|
// find resouce settings for this list
|
|
if (IopGenNextValidResourceList (0, CurList, Dir)) {
|
|
|
|
// found good settings, return them
|
|
return CurList;
|
|
}
|
|
}
|
|
|
|
|
|
// Try again - set last checked resource in any given list to pass2 to see if that will
|
|
// unclog the problem.
|
|
|
|
|
|
IDBGMSG ("First pass attempt at resource settings failed\n");
|
|
|
|
for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) {
|
|
for (; ;) {
|
|
// Reset last level tried to look for any settings
|
|
level = CurList->LastLevel;
|
|
ReqRes = CurList->RequiredResource[level];
|
|
if (ReqRes->PassNo != 1) {
|
|
// already trying pass 2 on this level
|
|
break;
|
|
}
|
|
|
|
ReqRes->PassNo = 2;
|
|
for (j=0; j < ReqRes->NoAlternatives; j++) {
|
|
ReqRes->IoResourceDescriptor[j]->Option &= ~IO_RESOURCE_PREFERRED;
|
|
}
|
|
|
|
|
|
// Back up to failed level and see if this list can now be satisfied
|
|
|
|
|
|
level = CurList->NoRequiredResources;
|
|
while (level > CurList->FailedLevel) {
|
|
level--;
|
|
CurList->RequiredResource[level]->CurLoc = 0;
|
|
CurList->RequiredResource[level]->RunLen = 0;
|
|
}
|
|
|
|
if (IopGenNextValidResourceList (level, CurList, Dir)) {
|
|
// found good settings, return them
|
|
return CurList;
|
|
}
|
|
|
|
} // loop and clear next failed level
|
|
} // loop and try next list
|
|
|
|
|
|
// Try again, this time allow for a complete search. Clear all preferred settings and
|
|
// move all levels to Pass2
|
|
|
|
|
|
IDBGMSG ("Pass 2 attempt at resource settings failed\n");
|
|
|
|
for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) {
|
|
for (i=0; i < CurList->NoRequiredResources; i++) {
|
|
ReqRes = CurList->RequiredResource[i];
|
|
ReqRes->CurLoc = 0;
|
|
ReqRes->RunLen = 0;
|
|
ReqRes->PassNo = 2;
|
|
|
|
for (j=0; j < ReqRes->NoAlternatives; j++) {
|
|
ReqRes->IoResourceDescriptor[j]->Option &= ~IO_RESOURCE_PREFERRED;
|
|
}
|
|
}
|
|
}
|
|
|
|
BestPref = -999999;
|
|
BestList = NULL;
|
|
CurList = Dir->Alternative;
|
|
level = 0;
|
|
|
|
while (CurList) {
|
|
// find resouce settings for this list
|
|
if (IopGenNextValidResourceList (level, CurList, Dir)) {
|
|
// We have useable settings, check to see how useable
|
|
if (CurList->CurPref >= 0) {
|
|
// Nothing wrong with these settings, go use them
|
|
IDBGMSG ("Pass3: Good hit\n");
|
|
return CurList;
|
|
}
|
|
|
|
if (CurList->CurPref > BestPref) {
|
|
// These are the best so far, remember them
|
|
BestPref = CurList->CurPref;
|
|
BestList = CurList;
|
|
|
|
for (i = 0; i < CurList->NoRequiredResources; i++) {
|
|
ReqRes = CurList->RequiredResource[i];
|
|
ReqRes->Pass2HoldCurLoc = ReqRes->CurBLoc;
|
|
ReqRes->Pass2HoldBAddr = ReqRes->CurBAddr;
|
|
}
|
|
}
|
|
|
|
// Determine which level to back up too to continue searching from
|
|
Pref = CurList->CurPref;
|
|
level = CurList->NoRequiredResources;
|
|
while (level && Pref <= BestPref) {
|
|
level--;
|
|
Pref -= CurList->RequiredResource[level]->CurPref;
|
|
CurList->RequiredResource[level]->CurLoc = 0;
|
|
CurList->RequiredResource[level]->RunLen = 0;
|
|
}
|
|
|
|
if (CurList->RequiredResource[level]->PrefCnt > 16) {
|
|
while (level && CurList->RequiredResource[level]->PrefCnt > 16) {
|
|
level--;
|
|
Pref -= CurList->RequiredResource[level]->CurPref;
|
|
CurList->RequiredResource[level]->CurLoc = 0;
|
|
CurList->RequiredResource[level]->RunLen = 0;
|
|
}
|
|
|
|
if (level == 0) {
|
|
// go with best setting so far
|
|
break;
|
|
}
|
|
}
|
|
|
|
CurList->RequiredResource[level]->PrefCnt++;
|
|
continue ;
|
|
}
|
|
|
|
// no (more) valid settings found on this list, try the next
|
|
CurList = CurList->Next;
|
|
level = 0;
|
|
}
|
|
|
|
if (!BestList) {
|
|
// failure
|
|
IDBGMSG ("Pass3: No settings found\n");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// Return best settings which were found
|
|
for (i = 0; i < BestList->NoRequiredResources; i++) {
|
|
ReqRes = BestList->RequiredResource[i];
|
|
ReqRes->CurBLoc = ReqRes->Pass2HoldCurLoc;
|
|
ReqRes->CurBAddr = ReqRes->Pass2HoldBAddr;
|
|
}
|
|
|
|
return BestList;
|
|
}
|
|
|
|
|
|
PCM_RESOURCE_LIST
|
|
IopAssignResourcesPhase4 (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PDIR_RESOURCE_LIST CurList,
|
|
OUT PULONG Length
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
The callers request for resources has been calculated. Phase 4 builds
|
|
a CM_RESOURCE_LIST of the allocated resources.
|
|
|
|
This functions need CurDesc->CurBLoc & CurDesc->CurBAddr as passed from Phase3.
|
|
--*/
|
|
{
|
|
PCM_RESOURCE_LIST CmRes;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc;
|
|
PDIR_REQUIRED_RESOURCE DirDesc, *pDirDesc;
|
|
PIO_RESOURCE_DESCRIPTOR IoDesc;
|
|
ULONG i, cnt, len;
|
|
|
|
PAGED_CODE();
|
|
|
|
cnt = CurList->NoRequiredResources;
|
|
len = sizeof (CM_RESOURCE_LIST) + cnt * sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|
*Length = len;
|
|
|
|
CmRes = (PCM_RESOURCE_LIST) ExAllocatePool (PagedPool, len);
|
|
if (!CmRes) {
|
|
return NULL;
|
|
}
|
|
|
|
RtlZeroMemory (CmRes, len);
|
|
|
|
CmRes->Count = 1;
|
|
CmRes->List[0].InterfaceType = Dir->IoResourceReq->InterfaceType;
|
|
CmRes->List[0].BusNumber = Dir->IoResourceReq->BusNumber;
|
|
CmRes->List[0].PartialResourceList.Count = CurList->NoRequiredResources;
|
|
|
|
CmDesc = CmRes->List[0].PartialResourceList.PartialDescriptors;
|
|
pDirDesc = CurList->RequiredResource; // return resources in same order they
|
|
// where requested
|
|
#if IDBG
|
|
DbgPrint ("Acquired Resourses - %d\n", CurList->NoRequiredResources);
|
|
#endif
|
|
|
|
for (i=0; i < cnt; i++, CmDesc++, pDirDesc++) {
|
|
DirDesc = *pDirDesc;
|
|
IoDesc = DirDesc->IoResourceDescriptor[DirDesc->CurBLoc];
|
|
|
|
CmDesc->Type = IoDesc->Type;
|
|
CmDesc->ShareDisposition = IoDesc->ShareDisposition;
|
|
CmDesc->Flags = IoDesc->Flags;
|
|
|
|
switch (CmDesc->Type) {
|
|
case CmResourceTypePort:
|
|
CmDesc->u.Port.Start.QuadPart = DirDesc->CurBAddr;
|
|
CmDesc->u.Port.Length = IoDesc->u.Port.Length;
|
|
#if IDBG
|
|
DbgPrint (" IO Start %x:%08x, Len %x\n",
|
|
CmDesc->u.Port.Start.HighPart, CmDesc->u.Port.Start.LowPart,
|
|
CmDesc->u.Port.Length );
|
|
#endif
|
|
break;
|
|
|
|
case CmResourceTypeMemory:
|
|
CmDesc->u.Memory.Start.QuadPart = DirDesc->CurBAddr;
|
|
CmDesc->u.Memory.Length = IoDesc->u.Memory.Length;
|
|
#if IDBG
|
|
DbgPrint (" MEM Start %x:%08x, Len %x\n",
|
|
CmDesc->u.Memory.Start.HighPart, CmDesc->u.Memory.Start.LowPart,
|
|
CmDesc->u.Memory.Length );
|
|
#endif
|
|
break;
|
|
case CmResourceTypeInterrupt:
|
|
CmDesc->u.Interrupt.Level = (ULONG) DirDesc->CurBAddr;
|
|
CmDesc->u.Interrupt.Vector = (ULONG) DirDesc->CurBAddr;
|
|
#if IDBG
|
|
DbgPrint (" INT Level %x, Vector %x\n", CmDesc->u.Interrupt.Level, CmDesc->u.Interrupt.Vector );
|
|
#endif
|
|
break;
|
|
case CmResourceTypeDma:
|
|
CmDesc->u.Dma.Channel = (ULONG) DirDesc->CurBAddr;
|
|
#if IDBG
|
|
DbgPrint (" DMA Channel %x\n", CmDesc->u.Dma.Channel);
|
|
#endif
|
|
break;
|
|
default:
|
|
ExFreePool (CmRes);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return CmRes;
|
|
}
|
|
|
|
|
|
STATIC VOID
|
|
IopLogConflict (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN NTSTATUS FinalStatus
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Resource settings could not be satisfied. Locate first resource
|
|
which can not be assigned and report the conflict.
|
|
--*/
|
|
{
|
|
PIO_ERROR_LOG_PACKET ErrLog;
|
|
PDIR_RESOURCE_LIST CurList;
|
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|
ULONG i, j;
|
|
ULONG len, ErrorLogNumber, ErrLogBufferLeft;
|
|
ULONG ConflictLevel;
|
|
UCHAR s[8];
|
|
PWCHAR pLog;
|
|
POWNER Owner;
|
|
|
|
PAGED_CODE();
|
|
|
|
IDBGMSG ("\n****\n");
|
|
IDBGMSG ("Failed to satisfy the following required resource\n");
|
|
|
|
ErrLog = NULL;
|
|
ErrorLogNumber = 0;
|
|
|
|
// There's a conflict in each alternative list
|
|
for (CurList = Dir->Alternative; CurList; CurList = CurList->Next) {
|
|
// Clear position (already on pass 2)
|
|
for (i=0; i < CurList->NoRequiredResources; i++) {
|
|
CurList->RequiredResource[i]->CurLoc = 0;
|
|
CurList->RequiredResource[i]->RunLen = 0;
|
|
CurList->RequiredResource[i]->PassNo = 2;
|
|
}
|
|
|
|
// Look for settings - set ConflictLevel to pass 3 to track where the problem is
|
|
|
|
ConflictLevel = CurList->FailedLevel;
|
|
CurList->RequiredResource[ConflictLevel]->PassNo = 3;
|
|
|
|
InitializeListHead (&CurList->Conflict.OtherConflicts);
|
|
|
|
if (IopGenNextValidResourceList (0, CurList, Dir)) {
|
|
IDBGMSG ("IopLogConflict: internal error\n");
|
|
continue ;
|
|
}
|
|
|
|
#if IDBG
|
|
if (CurList != Dir->Alternative) {
|
|
DbgPrint ("the following alternate resource also failed\n");
|
|
}
|
|
|
|
s[0] = s[1] = s[2] = s[3] = ' ';
|
|
s[4] = 0;
|
|
|
|
ReqRes = CurList->RequiredResource[ConflictLevel];
|
|
for (j=0; j < ReqRes->NoAlternatives; j++) {
|
|
IopDumpIoResourceDescriptor (s, ReqRes->IoResourceDescriptor[j]);
|
|
}
|
|
|
|
i = CurList->Conflict.NoConflicts;
|
|
if (i > SCONFLICT) {
|
|
i = SCONFLICT;
|
|
}
|
|
for (j=0; j < i; j++) {
|
|
DbgPrint (" Conflict # %d. ", j+1);
|
|
switch (CurList->Conflict.EasyConflict[j].Type) {
|
|
case CmResourceTypePort:
|
|
DbgPrint ("IO Base %08x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr);
|
|
break;
|
|
case CmResourceTypeMemory:
|
|
DbgPrint ("MEM Base %08x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr);
|
|
break;
|
|
case CmResourceTypeInterrupt:
|
|
DbgPrint ("INT Line %x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr);
|
|
break;
|
|
case CmResourceTypeDma:
|
|
DbgPrint ("DMA Channel %x", (ULONG) CurList->Conflict.EasyConflict[j].BAddr);
|
|
break;
|
|
}
|
|
|
|
DbgPrint (" with '%wZ' ", &CurList->Conflict.EasyConflict[j].Owner->KeyName);
|
|
if (CurList->Conflict.EasyConflict[j].Owner->DeviceName.Buffer) {
|
|
DbgPrint ("'%wZ'", &CurList->Conflict.EasyConflict[j].Owner->DeviceName);
|
|
}
|
|
DbgPrint ("\n");
|
|
}
|
|
|
|
if (CurList->Conflict.NoConflicts > SCONFLICT) {
|
|
DbgPrint (" ...\n");
|
|
DbgPrint ("Total Conflicts = %d\n", CurList->Conflict.NoConflicts);
|
|
}
|
|
|
|
if (!IsListEmpty (&CurList->Conflict.OtherConflicts)) {
|
|
DbgPrint ("Possible settings also conflicts with the following list\n");
|
|
// bugbug - not done
|
|
}
|
|
#endif
|
|
|
|
// Loop for each easy conflict
|
|
i = CurList->Conflict.NoConflicts;
|
|
if (i > SCONFLICT) {
|
|
i = SCONFLICT;
|
|
}
|
|
|
|
for (j=0; j < i; j++) {
|
|
if (ErrorLogNumber >= 3) {
|
|
// only add n logs for a given problem
|
|
break;
|
|
}
|
|
|
|
// Allocate a new error log structure
|
|
ErrorLogNumber += 1;
|
|
ErrLog = IoAllocateErrorLogEntry (DriverObject, ERROR_LOG_MAXIMUM_SIZE);
|
|
if (!ErrLog) {
|
|
break;
|
|
}
|
|
|
|
// Initialize errorlog field and counts to append strings
|
|
RtlZeroMemory (ErrLog, sizeof (*ErrLog));
|
|
ErrLog->FinalStatus = FinalStatus;
|
|
ErrLog->UniqueErrorValue = ErrorLogNumber;
|
|
ErrLog->NumberOfStrings = 2;
|
|
pLog = (PWCHAR) ErrLog->DumpData;
|
|
ErrLog->StringOffset = (USHORT) ( ((PUCHAR) pLog) - ((PUCHAR) ErrLog) );
|
|
ErrLogBufferLeft = (ERROR_LOG_MAXIMUM_SIZE - ErrLog->StringOffset) / sizeof(WCHAR);
|
|
|
|
switch (CurList->Conflict.EasyConflict[j].Type) {
|
|
case CmResourceTypePort:
|
|
ErrLog->ErrorCode = IO_ERR_PORT_RESOURCE_CONFLICT;
|
|
break;
|
|
case CmResourceTypeMemory:
|
|
ErrLog->ErrorCode = IO_ERR_MEMORY_RESOURCE_CONFLICT;
|
|
break;
|
|
case CmResourceTypeInterrupt:
|
|
ErrLog->ErrorCode = IO_ERR_INTERRUPT_RESOURCE_CONFLICT;
|
|
break;
|
|
case CmResourceTypeDma:
|
|
ErrLog->ErrorCode = IO_ERR_DMA_RESOURCE_CONFLICT;
|
|
break;
|
|
}
|
|
|
|
if (CurList->Conflict.EasyConflict[j].BAddr & 0xffffffff00000000) {
|
|
len = swprintf (pLog, L"%X:%08X",
|
|
(ULONG) (CurList->Conflict.EasyConflict[j].BAddr >> 32),
|
|
(ULONG) CurList->Conflict.EasyConflict[j].BAddr
|
|
);
|
|
} else {
|
|
len = swprintf (pLog, L"%X", (ULONG) CurList->Conflict.EasyConflict[j].BAddr);
|
|
}
|
|
|
|
len += 1; // include null
|
|
pLog += len;
|
|
ErrLogBufferLeft -= len;
|
|
|
|
Owner = CurList->Conflict.EasyConflict[j].Owner;
|
|
|
|
len = Owner->KeyName.Length / sizeof(WCHAR);
|
|
if (len > ErrLogBufferLeft) {
|
|
len = ErrLogBufferLeft;
|
|
}
|
|
|
|
RtlCopyMemory (pLog, Owner->KeyName.Buffer, len * sizeof(WCHAR) );
|
|
pLog += len;
|
|
ErrLogBufferLeft -= len;
|
|
|
|
if (Owner->DeviceName.Buffer && ErrLogBufferLeft > 11) {
|
|
len = Owner->DeviceName.Length / sizeof(WCHAR);
|
|
if (len > ErrLogBufferLeft) {
|
|
len = ErrLogBufferLeft;
|
|
}
|
|
|
|
*(pLog++) = ' ';
|
|
RtlCopyMemory (pLog, Owner->DeviceName.Buffer, len * sizeof(WCHAR));
|
|
pLog += len;
|
|
ErrLogBufferLeft -= len;
|
|
}
|
|
|
|
*(pLog++) = 0; // null terminate
|
|
|
|
IoWriteErrorLogEntry ( ErrLog );
|
|
}
|
|
}
|
|
|
|
IDBGMSG ("****\n");
|
|
}
|
|
#endif
|
|
|
|
|
|
STATIC PTENTRY
|
|
IopNewTransEntry (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PTENTRIESBYTYPE pTypes,
|
|
IN ULONG Type
|
|
)
|
|
{
|
|
PLTENTRY LEntry, NewTable;
|
|
|
|
LEntry = pTypes->ByType[Type];
|
|
|
|
if (!LEntry || LEntry->CurEntries == MAX_ENTRIES) {
|
|
// Build a new table
|
|
NewTable = IopAllocateDirPool (Dir, sizeof (LTENTRY));
|
|
if (!NewTable) {
|
|
return NULL;
|
|
}
|
|
|
|
pTypes->ByType[Type] = NewTable;
|
|
NewTable->Next = LEntry;
|
|
NewTable->CurEntries = 0;
|
|
|
|
LEntry = NewTable;
|
|
}
|
|
|
|
return LEntry->Table + (LEntry->CurEntries++);
|
|
}
|
|
|
|
|
|
STATIC NTSTATUS
|
|
IopAddCmDescriptorToInUseList (
|
|
IN PDIR_RESREQ_LIST Dir,
|
|
IN PTENTRIESBYTYPE pTypes,
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc,
|
|
IN POWNER Owner
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Adds Translated CmDescriptor to TLIST.
|
|
--*/
|
|
{
|
|
PTENTRY Trans;
|
|
LONGLONG li;
|
|
|
|
if ((CmDesc->Type == CmResourceTypePort && CmDesc->u.Port.Length == 0) ||
|
|
(CmDesc->Type == CmResourceTypeMemory && CmDesc->u.Memory.Length == 0)) {
|
|
// no length?
|
|
IDBGMSG ("IopAddCmDescriptor: Skipping zero length descriptor\n");
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
// Get a new Trans entry in the InUseResource list or the
|
|
// InUseSharableResource list
|
|
|
|
|
|
Trans = IopNewTransEntry (Dir, pTypes, CmDesc->Type);
|
|
if (!Trans) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
|
|
// Fill in the Trans structure
|
|
|
|
|
|
// NOTE: turning TEntries into a splay tree would speed up the collision
|
|
// detect process.
|
|
|
|
Trans->Owner = Owner;
|
|
switch (CmDesc->Type) {
|
|
case CmResourceTypePort:
|
|
li = CmDesc->u.Port.Length - 1;
|
|
Trans->BAddr = *((LONGLONG UNALIGNED *) &CmDesc->u.Port.Start);
|
|
Trans->EAddr = Trans->BAddr + li;
|
|
Trans->Affinity = (KAFFINITY) -1;
|
|
break;
|
|
case CmResourceTypeMemory:
|
|
li = CmDesc->u.Memory.Length - 1;
|
|
Trans->BAddr = *((LONGLONG UNALIGNED *) &CmDesc->u.Memory.Start);
|
|
Trans->EAddr = Trans->BAddr + li;
|
|
Trans->Affinity = (KAFFINITY) -1;
|
|
break;
|
|
case CmResourceTypeInterrupt:
|
|
Trans->BAddr = CmDesc->u.Interrupt.Vector;
|
|
Trans->EAddr = CmDesc->u.Interrupt.Vector;
|
|
Trans->Affinity = CmDesc->u.Interrupt.Affinity;
|
|
break;
|
|
case CmResourceTypeDma:
|
|
Trans->BAddr = CmDesc->u.Dma.Channel;
|
|
Trans->EAddr = CmDesc->u.Dma.Channel;
|
|
Trans->Affinity = (KAFFINITY) -1;
|
|
break;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IopBuildResourceDir (
|
|
IN PDIR_RESREQ_LIST ParentDir,
|
|
IN PDIR_RESREQ_LIST *pDir,
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResources
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
Takes an IO_RESOURCE_REQUIREMENTS list and builds a directory for it's contents.
|
|
--*/
|
|
{
|
|
PDIR_RESREQ_LIST Dir;
|
|
PIO_RESOURCE_LIST ResourceList;
|
|
PIO_RESOURCE_DESCRIPTOR Descriptor, ADescriptor;
|
|
PDIR_RESOURCE_LIST DirResourceList, *AltListTail;
|
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|
ULONG i, j, alt, cnt, acnt;
|
|
PUCHAR FirstAddress, LastAddress;
|
|
|
|
// Allocate and initialize DIR structure
|
|
Dir = (PDIR_RESREQ_LIST) ExAllocatePool (PagedPool, sizeof(DIR_RESREQ_LIST));
|
|
*pDir = Dir;
|
|
if (!Dir) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory (Dir, sizeof (DIR_RESREQ_LIST));
|
|
for (i=0; i < MAX_REG_HANDLES; i++) {
|
|
Dir->RegHandle[i] = INVALID_HANDLE;
|
|
}
|
|
|
|
if (ParentDir) {
|
|
Dir->FreeResReqList = ParentDir->FreeResReqList;
|
|
ParentDir->FreeResReqList = Dir;
|
|
}
|
|
|
|
// If no IoResources to process, the Dir structure is done
|
|
if (!IoResources) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// Verify ResourceList does not exceede ListSize
|
|
ResourceList = IoResources->List;
|
|
FirstAddress = (PUCHAR) ResourceList;
|
|
LastAddress = (PUCHAR) IoResources + IoResources->ListSize;
|
|
for (cnt=0; cnt < IoResources->AlternativeLists; cnt++) {
|
|
ResourceList = (PIO_RESOURCE_LIST)(&ResourceList->Descriptors[ResourceList->Count]);
|
|
|
|
if ((PUCHAR) ResourceList < FirstAddress || (PUCHAR) ResourceList > LastAddress) {
|
|
DBGMSG ("IopBuildResourceDir: IO_RESOURCE_LIST.ListSize too small\n");
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
// Build a directory of the block stlye structure IO_RESOURCE_REQUIREMENTS_LIST
|
|
Dir->IoResourceReq = IoResources;
|
|
AltListTail = &Dir->Alternative;
|
|
ResourceList = IoResources->List;
|
|
|
|
for (alt=0; alt < IoResources->AlternativeLists; alt++) {
|
|
// Count number of non-alternative descriptors on this
|
|
// alternative list
|
|
|
|
cnt = 0;
|
|
Descriptor = ResourceList->Descriptors;
|
|
for (i = ResourceList->Count; i; i--) {
|
|
if (!(Descriptor->Option & IO_RESOURCE_ALTERNATIVE)) {
|
|
cnt++;
|
|
}
|
|
Descriptor++;
|
|
}
|
|
|
|
|
|
// Build alternative list structure
|
|
i = sizeof (DIR_RESOURCE_LIST) + cnt * sizeof(PVOID) * 2;
|
|
DirResourceList = (PDIR_RESOURCE_LIST) IopAllocateDirPool (Dir, i);
|
|
if (!DirResourceList) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Initialize structure
|
|
RtlZeroMemory (DirResourceList, i);
|
|
DirResourceList->IoResourceList = ResourceList;
|
|
|
|
// add to tail of single linked list
|
|
*(AltListTail) = DirResourceList;
|
|
AltListTail = &DirResourceList->Next;
|
|
|
|
Descriptor = ResourceList->Descriptors;
|
|
for (i = ResourceList->Count; i; i--) {
|
|
if (!(Descriptor->Option & IO_RESOURCE_ALTERNATIVE)) {
|
|
// Count number of alternative descriptors
|
|
acnt = 1;
|
|
ADescriptor = Descriptor + 1;
|
|
while (acnt < i && ADescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
|
|
ADescriptor++;
|
|
acnt++;
|
|
}
|
|
|
|
// Allocate a required resource list
|
|
ReqRes = (PDIR_REQUIRED_RESOURCE) IopAllocateDirPool (Dir, sizeof (DIR_REQUIRED_RESOURCE) + acnt * sizeof(PVOID));
|
|
if (!ReqRes) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory (ReqRes, sizeof (DIR_REQUIRED_RESOURCE));
|
|
DirResourceList->RequiredResource[DirResourceList->NoRequiredResources] = ReqRes;
|
|
DirResourceList->NoRequiredResources++;
|
|
|
|
// Fill in all the alternatives for this required resource
|
|
ReqRes->NoAlternatives = acnt;
|
|
ADescriptor = Descriptor;
|
|
for (j=0; j < acnt; j++) {
|
|
ReqRes->IoResourceDescriptor[j] = ADescriptor;
|
|
if (ADescriptor->Option & IO_RESOURCE_PREFERRED) {
|
|
ReqRes->BestPref = 1;
|
|
}
|
|
ADescriptor++;
|
|
}
|
|
}
|
|
|
|
Descriptor++;// Next descriptor
|
|
}
|
|
|
|
// Next alternative resource list
|
|
ResourceList = (PIO_RESOURCE_LIST) Descriptor;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID IopFreeResourceDir (IN PDIR_RESREQ_LIST DirResourceList)
|
|
/*++
|
|
Routine Description:
|
|
Frees pool used to track a DIR_RESREQ_LIST and other assiocated
|
|
resources. Also free's all pool for DIR_RESREQ_LIST's on a free list.
|
|
--*/
|
|
{
|
|
PDIR_RESREQ_LIST NextResourceList;
|
|
ULONG i;
|
|
PSINGLE_LIST_ENTRY pe;
|
|
PUSED_HEAP ph;
|
|
|
|
// Free any allocated lists
|
|
while (DirResourceList) {
|
|
NextResourceList = DirResourceList->FreeResReqList;
|
|
|
|
// Free any allocated heap
|
|
while (DirResourceList->AllocatedHeap.Next) {
|
|
pe = PopEntryList (&DirResourceList->AllocatedHeap);
|
|
ph = CONTAINING_RECORD(pe, USED_HEAP, FreeLink);
|
|
ExFreePool (ph->FreeHeap);
|
|
}
|
|
|
|
// Close any opened handles
|
|
for (i=0; i< MAX_REG_HANDLES; i++) {
|
|
if (DirResourceList->RegHandle[i] != INVALID_HANDLE) {
|
|
ZwClose (DirResourceList->RegHandle[i]);
|
|
}
|
|
}
|
|
|
|
ExFreePool (DirResourceList);// Free header
|
|
DirResourceList = NextResourceList;// Next list
|
|
}
|
|
}
|
|
|
|
|
|
#if IDBG
|
|
VOID IopDumpIoResourceDir (IN PDIR_RESREQ_LIST Dir)
|
|
{
|
|
PDIR_RESOURCE_LIST ResourceList;
|
|
PIO_RESOURCE_DESCRIPTOR Desc;
|
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|
ULONG alt, i, j;
|
|
UCHAR s[10];
|
|
|
|
alt = 0;
|
|
for (ResourceList = Dir->Alternative; ResourceList; ResourceList = ResourceList->Next) {
|
|
DbgPrint ("Alternative #%d - %d required resources\n", alt++, ResourceList->NoRequiredResources );
|
|
|
|
for (i=0; i < ResourceList->NoRequiredResources; i++) {
|
|
ReqRes = ResourceList->RequiredResource[i];
|
|
for (j=0; j < ReqRes->NoAlternatives; j++) {
|
|
Desc = ReqRes->IoResourceDescriptor[j];
|
|
if (j == 0) {
|
|
s[0] = s[1] = s[2] = '*';
|
|
s[3] = ' ';
|
|
} else {
|
|
s[0] = s[1] = s[2] = s[3] = ' ';
|
|
}
|
|
|
|
s[4] = Desc->Option & IO_RESOURCE_PREFERRED ? 'P' : ' ';
|
|
s[5] = ' ';
|
|
s[6] = 0;
|
|
|
|
IopDumpIoResourceDescriptor (s, Desc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
IopDumpIoResourceDescriptor (
|
|
IN PUCHAR Indent,
|
|
IN PIO_RESOURCE_DESCRIPTOR Desc
|
|
)
|
|
{
|
|
switch (Desc->Type) {
|
|
case CmResourceTypePort:
|
|
DbgPrint ("%sIO Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
|
|
Indent,
|
|
Desc->u.Port.MinimumAddress.HighPart, Desc->u.Port.MinimumAddress.LowPart,
|
|
Desc->u.Port.MaximumAddress.HighPart, Desc->u.Port.MaximumAddress.LowPart,
|
|
Desc->u.Port.Alignment,
|
|
Desc->u.Port.Length
|
|
);
|
|
break;
|
|
case CmResourceTypeMemory:
|
|
DbgPrint ("%sMEM Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
|
|
Indent,
|
|
Desc->u.Memory.MinimumAddress.HighPart, Desc->u.Memory.MinimumAddress.LowPart,
|
|
Desc->u.Memory.MaximumAddress.HighPart, Desc->u.Memory.MaximumAddress.LowPart,
|
|
Desc->u.Memory.Alignment,
|
|
Desc->u.Memory.Length
|
|
);
|
|
break;
|
|
case CmResourceTypeInterrupt:
|
|
DbgPrint ("%sINT Min: %x, Max: %x\n", Indent, Desc->u.Interrupt.MinimumVector, Desc->u.Interrupt.MaximumVector);
|
|
break;
|
|
case CmResourceTypeDma:
|
|
DbgPrint ("%sDMA Min: %x, Max: %x\n", Indent, Desc->u.Dma.MinimumChannel, Desc->u.Dma.MaximumChannel);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
NTSTATUS IopCatagorizeDescriptors (IN OUT PDIR_RESREQ_LIST Dir)
|
|
/*++
|
|
Routine Description:
|
|
Takes a DIR_RESREQ_LIST and returns a list of resources by
|
|
catagory. It is assumed that such a directory has one list
|
|
of alternative descriptors per resource type.
|
|
--*/
|
|
{
|
|
PDIR_RESOURCE_LIST DirResourceList;
|
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|
ULONG i, j, acnt;
|
|
CM_RESOURCE_TYPE type;
|
|
|
|
if (!Dir->Alternative || Dir->Alternative->Next) {
|
|
// there can only be one list
|
|
DBGMSG ("IopCatagorizeDescriptors: too many altenative lists\n");
|
|
return STATUS_INVALID_PARAMETER_MIX;
|
|
}
|
|
|
|
DirResourceList = Dir->Alternative;
|
|
for (i=0; i < DirResourceList->NoRequiredResources; i++) {
|
|
ReqRes = DirResourceList->RequiredResource[i];
|
|
|
|
acnt = ReqRes->NoAlternatives;
|
|
if (!acnt) {
|
|
// shouldn't have a zero count
|
|
DBGMSG ("IopCatagorizeDescriptors: no entries\n");
|
|
return STATUS_INVALID_PARAMETER_MIX;
|
|
}
|
|
|
|
type = ReqRes->IoResourceDescriptor[0]->Type;
|
|
|
|
// verify all entries in this list are of the same type
|
|
for (j=1; j < acnt; j++) {
|
|
if (ReqRes->IoResourceDescriptor[j]->Type != type) {
|
|
DBGMSG ("IopCatagorizeDescriptors: mixed types in alternatives\n");
|
|
return STATUS_INVALID_PARAMETER_MIX;
|
|
}
|
|
}
|
|
|
|
if (type >= CmResourceTypeMaximum) {
|
|
// unkown catagory
|
|
continue;
|
|
}
|
|
|
|
if (DirResourceList->ResourceByType[type]) {
|
|
// should only have one list per type
|
|
DBGMSG ("IopCatagorizeDescriptors: multiple lists per resource type\n");
|
|
return STATUS_INVALID_PARAMETER_MIX;
|
|
}
|
|
|
|
DirResourceList->ResourceByType[type] = ReqRes;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
INLINE ULONG IopDescriptorSortingWeight (IN PIO_RESOURCE_DESCRIPTOR Descriptor)
|
|
/*++
|
|
Routine Description:
|
|
Used by IopSortDescriptors
|
|
--*/
|
|
{
|
|
ULONG w;
|
|
|
|
switch (Descriptor->Type) {
|
|
case CmResourceTypeMemory: w = 4; break;
|
|
case CmResourceTypeInterrupt: w = 3; break;
|
|
case CmResourceTypeDma: w = 2; break;
|
|
case CmResourceTypePort: w = 1; break;
|
|
default: w = 0; break;
|
|
}
|
|
|
|
return w;
|
|
}
|
|
|
|
|
|
VOID IopSortDescriptors (IN OUT PDIR_RESREQ_LIST Dir)
|
|
/*++
|
|
Routine Description:
|
|
Sorts the directory entries for each decsriptor such that they
|
|
descriptors are order by resource type.
|
|
--*/
|
|
{
|
|
PIO_RESOURCE_DESCRIPTOR Descriptor;
|
|
PDIR_RESOURCE_LIST DirResourceList;
|
|
PDIR_REQUIRED_RESOURCE ReqRes;
|
|
ULONG i, j, k, acnt;
|
|
ULONG w1, w2;
|
|
|
|
// Sort each require resource list by descriptor type
|
|
|
|
for (DirResourceList = Dir->Alternative; DirResourceList; DirResourceList = DirResourceList->Next) {
|
|
// Sort the descriptors by type
|
|
for (k=0; k < DirResourceList->NoRequiredResources; k++) {
|
|
ReqRes = DirResourceList->RequiredResource[k];
|
|
|
|
acnt = ReqRes->NoAlternatives;
|
|
for (i=0; i < acnt; i++) {
|
|
w1 = IopDescriptorSortingWeight (ReqRes->IoResourceDescriptor[i]);
|
|
|
|
for (j = i+1; j < acnt; j++) {
|
|
w2 = IopDescriptorSortingWeight (ReqRes->IoResourceDescriptor[j]);
|
|
|
|
if (w2 > w1) {
|
|
Descriptor = ReqRes->IoResourceDescriptor[i];
|
|
ReqRes->IoResourceDescriptor[i] = ReqRes->IoResourceDescriptor[j];
|
|
ReqRes->IoResourceDescriptor[j] = Descriptor;
|
|
w1 = w2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|