You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2355 lines
62 KiB
2355 lines
62 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rangesup.c
|
|
|
|
Abstract:
|
|
|
|
This handles the subtraction of a set of CmResList from an IoResList
|
|
IoResList
|
|
|
|
Author:
|
|
|
|
Stephane Plante (splante)
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
Aug-05-97 - Initial Revision
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
|
|
NTSTATUS
|
|
ACPIRangeAdd(
|
|
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *GlobalList,
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST AddList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to add an Io List to another. This is not a
|
|
straightforward operation
|
|
|
|
Arguments:
|
|
|
|
IoList - The list that contains both lists
|
|
AddList - The list what will be added to the other. We are desctructive
|
|
to this list
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN proceed;
|
|
NTSTATUS status;
|
|
PIO_RESOURCE_DESCRIPTOR addDesc;
|
|
PIO_RESOURCE_DESCRIPTOR newDesc;
|
|
PIO_RESOURCE_LIST addList;
|
|
PIO_RESOURCE_LIST globalList;
|
|
PIO_RESOURCE_LIST newList;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST globalResList;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST newResList;
|
|
ULONG addCount = 0;
|
|
ULONG addIndex = 0;
|
|
ULONG ioCount = 0;
|
|
ULONG ioIndex = 0;
|
|
ULONG maxSize = 0;
|
|
ULONG size = 0;
|
|
|
|
if (GlobalList == NULL) {
|
|
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
|
|
}
|
|
globalResList = *GlobalList;
|
|
|
|
//
|
|
// Make sure that we have a list to add
|
|
//
|
|
if (AddList == NULL || AddList->AlternativeLists == 0) {
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Figure out how much space we need in the
|
|
//
|
|
addList = &(AddList->List[0]);
|
|
maxSize = addCount = addList->Count;
|
|
ACPIRangeSortIoList( addList );
|
|
|
|
//
|
|
// Worst case is that the new list is as big as both lists combined
|
|
//
|
|
size = AddList->ListSize;
|
|
|
|
//
|
|
// Do we have a global list to add to?
|
|
//
|
|
if (globalResList == NULL || globalResList->AlternativeLists == 0) {
|
|
|
|
//
|
|
// No? Then just copy the old list
|
|
//
|
|
newResList = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
size,
|
|
ACPI_RESOURCE_POOLTAG
|
|
);
|
|
if (newResList == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
RtlCopyMemory(
|
|
newResList,
|
|
AddList,
|
|
size
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Yes, so calculate how much space the first one will take
|
|
//
|
|
globalList = &(globalResList->List[0]);
|
|
ioCount = globalList->Count;
|
|
maxSize += ioCount;
|
|
size += (ioCount * sizeof(IO_RESOURCE_DESCRIPTOR) );
|
|
|
|
//
|
|
// Allocate the list
|
|
//
|
|
newResList = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
size,
|
|
ACPI_RESOURCE_POOLTAG
|
|
);
|
|
if (newResList == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
//
|
|
// Copy both lists into the new one
|
|
//
|
|
RtlZeroMemory( newResList, size );
|
|
RtlCopyMemory(
|
|
newResList,
|
|
AddList,
|
|
AddList->ListSize
|
|
);
|
|
RtlCopyMemory(
|
|
&(newResList->List[0].Descriptors[addCount]),
|
|
globalList->Descriptors,
|
|
(ioCount * sizeof(IO_RESOURCE_DESCRIPTOR) )
|
|
);
|
|
|
|
//
|
|
// We no longer need this list
|
|
//
|
|
ExFreePool( *GlobalList );
|
|
|
|
}
|
|
|
|
//
|
|
// Make sure that we update the list count
|
|
//
|
|
newResList->ListSize = size;
|
|
newList = &(newResList->List[0]);
|
|
newList->Count = ioCount = addCount = maxSize;
|
|
|
|
//
|
|
// Sort the new list
|
|
//
|
|
status = ACPIRangeSortIoList( newList );
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// We failed, so exit now
|
|
//
|
|
ExFreePool( newResList );
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// Add all the resource we can together
|
|
//
|
|
for (ioIndex = 0; ioIndex < maxSize; ioIndex++) {
|
|
|
|
//
|
|
// First step is to copy the current desc from the master list to
|
|
// the new list
|
|
//
|
|
newDesc = &(newList->Descriptors[ioIndex]);
|
|
|
|
//
|
|
// Is it interesting?
|
|
//
|
|
if (newDesc->Type == CmResourceTypeNull) {
|
|
|
|
//
|
|
// No
|
|
//
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we care about it?
|
|
//
|
|
if (newDesc->Type != CmResourceTypeMemory &&
|
|
newDesc->Type != CmResourceTypePort &&
|
|
newDesc->Type != CmResourceTypeDma &&
|
|
newDesc->Type != CmResourceTypeInterrupt) {
|
|
|
|
//
|
|
// We do not care
|
|
//
|
|
newDesc->Type = CmResourceTypeNull;
|
|
ioCount--;
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Try to get as far as possible
|
|
//
|
|
proceed = TRUE;
|
|
|
|
//
|
|
// Now we try to find any lists that we can merge in that location
|
|
//
|
|
for (addIndex = ioIndex + 1; addIndex < maxSize; addIndex++) {
|
|
|
|
addDesc = &(newList->Descriptors[addIndex]);
|
|
|
|
//
|
|
// If they are not the same type, then next
|
|
//
|
|
if (newDesc->Type != addDesc->Type) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// What we do next is dependent on the type
|
|
//
|
|
switch (newDesc->Type) {
|
|
case CmResourceTypePort:
|
|
case CmResourceTypeMemory:
|
|
|
|
//
|
|
// Does the new descriptor lie entirely before the add
|
|
// descriptor?
|
|
//
|
|
if (addDesc->u.Port.MinimumAddress.QuadPart >
|
|
newDesc->u.Port.MaximumAddress.QuadPart + 1) {
|
|
|
|
//
|
|
// Then we are done with this newDesc
|
|
//
|
|
proceed = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// does part of the current new descriptor lie in part
|
|
// of the add one?
|
|
//
|
|
if (newDesc->u.Port.MaximumAddress.QuadPart <=
|
|
addDesc->u.Port.MaximumAddress.QuadPart) {
|
|
|
|
//
|
|
// Update the current new descriptor to refect the
|
|
// correct range and length
|
|
//
|
|
newDesc->u.Port.MaximumAddress.QuadPart =
|
|
addDesc->u.Port.MaximumAddress.QuadPart;
|
|
newDesc->u.Port.Length = (ULONG)
|
|
(newDesc->u.Port.MaximumAddress.QuadPart -
|
|
newDesc->u.Port.MinimumAddress.QuadPart + 1);
|
|
newDesc->u.Port.Alignment = 1;
|
|
|
|
}
|
|
|
|
//
|
|
// Nuke the add descriptor since it has been swallowed up
|
|
//
|
|
ioCount--;
|
|
addDesc->Type = CmResourceTypeNull;
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
case CmResourceTypeInterrupt:
|
|
|
|
//
|
|
// Does the current new descriptor lie entirely before the
|
|
// one we are looking at now?
|
|
//
|
|
if (addDesc->u.Dma.MinimumChannel >
|
|
newDesc->u.Dma.MaximumChannel + 1) {
|
|
|
|
proceed = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// does part of the current new descriptor lie in part
|
|
// of the add one?
|
|
//
|
|
if (newDesc->u.Dma.MaximumChannel <=
|
|
addDesc->u.Dma.MaximumChannel ) {
|
|
|
|
//
|
|
// Update the current new descriptor to reflect the
|
|
// correct range
|
|
//
|
|
newDesc->u.Dma.MaximumChannel =
|
|
addDesc->u.Dma.MaximumChannel;
|
|
|
|
}
|
|
|
|
//
|
|
// Nuke the add descriptor since it has been swallowed up
|
|
//
|
|
ioCount--;
|
|
addDesc->Type = CmResourceTypeNull;
|
|
|
|
break;
|
|
} // switch
|
|
|
|
//
|
|
// Do we need to stop?
|
|
//
|
|
if (proceed == FALSE) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // for
|
|
|
|
//
|
|
// Do we have any items left that we care about?
|
|
//
|
|
if (ioCount == 0) {
|
|
|
|
//
|
|
// No then free everything and return an empty list
|
|
//
|
|
ExFreePool( newResList );
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Now we can build the proper list. See how many items we must allocate
|
|
//
|
|
size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + (ioCount - 1) *
|
|
sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
globalResList = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
size,
|
|
ACPI_RESOURCE_POOLTAG
|
|
);
|
|
if (globalResList == NULL) {
|
|
|
|
ExFreePool( newResList );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
//
|
|
// Initialize the new list by copying the header from the working list
|
|
//
|
|
RtlZeroMemory( globalResList, size );
|
|
RtlCopyMemory(
|
|
globalResList,
|
|
newResList,
|
|
sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
|
|
);
|
|
globalResList->ListSize = size;
|
|
globalList = &(globalResList->List[0]);
|
|
globalList->Count = ioCount;
|
|
|
|
//
|
|
// Copy all of the valid items into this new list
|
|
//
|
|
for (addIndex = 0, ioIndex = 0;
|
|
ioIndex < ioCount && addIndex < maxSize;
|
|
addIndex++) {
|
|
|
|
addDesc = &(newList->Descriptors[addIndex]);
|
|
|
|
//
|
|
// If the type is null, skip it
|
|
//
|
|
if (addDesc->Type == CmResourceTypeNull) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Copy the new list
|
|
//
|
|
RtlCopyMemory(
|
|
&(globalList->Descriptors[ioIndex]),
|
|
addDesc,
|
|
sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
);
|
|
ioIndex++;
|
|
|
|
}
|
|
|
|
//
|
|
// Free the old list
|
|
//
|
|
ExFreePool( newResList );
|
|
|
|
//
|
|
// Point the global to the new list
|
|
//
|
|
*GlobalList = globalResList;
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPIRangeAddCmList(
|
|
IN OUT PCM_RESOURCE_LIST *GlobalList,
|
|
IN PCM_RESOURCE_LIST AddList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to add an Cm List to another. This is not a
|
|
straightforward operation
|
|
|
|
Arguments:
|
|
|
|
CmList - The list that contains both lists
|
|
AddList - The list what will be added to the other. We are desctructive
|
|
to this list
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS:
|
|
|
|
--*/
|
|
{
|
|
|
|
BOOLEAN proceed;
|
|
NTSTATUS status;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR addDesc;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR newDesc;
|
|
PCM_PARTIAL_RESOURCE_LIST addPartialList;
|
|
PCM_PARTIAL_RESOURCE_LIST cmPartialList;
|
|
PCM_PARTIAL_RESOURCE_LIST newPartialList;
|
|
PCM_RESOURCE_LIST globalList;
|
|
PCM_RESOURCE_LIST newList;
|
|
ULONG addCount = 0;
|
|
ULONG addIndex = 0;
|
|
ULONG cmCount = 0;
|
|
ULONG cmIndex = 0;
|
|
ULONG maxSize = 0;
|
|
ULONG size = 0;
|
|
ULONGLONG maxAddr1;
|
|
ULONGLONG maxAddr2;
|
|
|
|
if (GlobalList == NULL) {
|
|
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
|
|
}
|
|
globalList = *GlobalList;
|
|
|
|
//
|
|
// Make sure that we have a list to add
|
|
//
|
|
if (AddList == NULL || AddList->Count == 0) {
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
addPartialList = &(AddList->List[0].PartialResourceList);
|
|
addCount = addPartialList->Count;
|
|
|
|
//
|
|
// If we have no global list, then we just copy over the other one
|
|
//
|
|
if (globalList == NULL || globalList->Count == 0) {
|
|
|
|
//
|
|
// Just copy over the original list
|
|
//
|
|
size = sizeof(CM_RESOURCE_LIST) + (addCount - 1) *
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|
maxSize = addCount;
|
|
newList = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
size,
|
|
ACPI_RESOURCE_POOLTAG
|
|
);
|
|
if (newList == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
RtlCopyMemory(
|
|
newList,
|
|
AddList,
|
|
size
|
|
);
|
|
|
|
} else {
|
|
|
|
cmPartialList = &( globalList->List[0].PartialResourceList);
|
|
cmCount = cmPartialList->Count;
|
|
maxSize = addCount + cmCount;
|
|
|
|
//
|
|
// Allocate space for both lists
|
|
//
|
|
size = sizeof(CM_RESOURCE_LIST) + (maxSize - 1) *
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|
newList = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
size,
|
|
ACPI_RESOURCE_POOLTAG
|
|
);
|
|
if (newList == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
//
|
|
// Merge both sets of descriptors into one list
|
|
//
|
|
RtlZeroMemory( newList, size );
|
|
RtlCopyMemory(
|
|
newList,
|
|
AddList,
|
|
size - (cmCount * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))
|
|
);
|
|
RtlCopyMemory(
|
|
( (PUCHAR) newList) +
|
|
(size - (cmCount * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR ) ) ),
|
|
&(cmPartialList->PartialDescriptors[0]),
|
|
cmCount * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
);
|
|
|
|
//
|
|
// Make sure to preserver the version id from the global list
|
|
//
|
|
newList->List->PartialResourceList.Version =
|
|
globalList->List->PartialResourceList.Version;
|
|
newList->List->PartialResourceList.Revision =
|
|
globalList->List->PartialResourceList.Revision;
|
|
|
|
ExFreePool( globalList );
|
|
|
|
}
|
|
|
|
//
|
|
// Obtain a pointer to the descriptors of the new list, and update the
|
|
// number of descriptors in the list
|
|
//
|
|
newPartialList = &(newList->List[0].PartialResourceList);
|
|
newPartialList->Count = cmCount = addCount = maxSize;
|
|
|
|
//
|
|
// Make sure to sort the combined list
|
|
//
|
|
status = ACPIRangeSortCmList( newList );
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ExFreePool( newList );
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// Add all the resource we can together
|
|
//
|
|
for (cmIndex = 0; cmIndex < maxSize; cmIndex++) {
|
|
|
|
//
|
|
// Grab a pointer to the current descriptor
|
|
//
|
|
newDesc = &(newPartialList->PartialDescriptors[cmIndex]);
|
|
|
|
//
|
|
// Is it interesting?
|
|
//
|
|
if (newDesc->Type == CmResourceTypeNull) {
|
|
|
|
//
|
|
// No
|
|
//
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we care about it?
|
|
//
|
|
if (newDesc->Type != CmResourceTypeMemory &&
|
|
newDesc->Type != CmResourceTypePort &&
|
|
newDesc->Type != CmResourceTypeDma &&
|
|
newDesc->Type != CmResourceTypeInterrupt) {
|
|
|
|
//
|
|
// We do not care
|
|
//
|
|
newDesc->Type = CmResourceTypeNull;
|
|
cmCount--;
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Try to get as far as possible
|
|
//
|
|
proceed = TRUE;
|
|
|
|
//
|
|
// Try to merge the following items
|
|
//
|
|
for (addIndex = cmIndex + 1; addIndex < maxSize; addIndex++) {
|
|
|
|
addDesc = &(newPartialList->PartialDescriptors[addIndex]);
|
|
|
|
//
|
|
// If they are not the same type, then we are done here
|
|
//
|
|
if (newDesc->Type != addDesc->Type) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
switch (newDesc->Type) {
|
|
case CmResourceTypePort:
|
|
case CmResourceTypeMemory:
|
|
//
|
|
// Obtain the max addresses
|
|
//
|
|
maxAddr1 = newDesc->u.Port.Start.QuadPart +
|
|
newDesc->u.Port.Length;
|
|
maxAddr2 = addDesc->u.Port.Start.QuadPart +
|
|
addDesc->u.Port.Length;
|
|
|
|
//
|
|
// does the current new descriptor lie entirely before the
|
|
// add one?
|
|
//
|
|
if (maxAddr1 < (ULONGLONG) addDesc->u.Port.Start.QuadPart ) {
|
|
|
|
//
|
|
// Yes, so we are done with this newDesc;
|
|
//
|
|
proceed = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// does part of the current new descriptor lie in part of the
|
|
// add one?
|
|
//
|
|
if (maxAddr1 <= maxAddr2) {
|
|
|
|
//
|
|
// Update the current new descriptor to reflect the
|
|
// correct length
|
|
//
|
|
newDesc->u.Port.Length = (ULONG) (maxAddr2 -
|
|
newDesc->u.Port.Start.QuadPart);
|
|
|
|
}
|
|
|
|
//
|
|
// Nuke the add descriptor since it has been swallowed up
|
|
//
|
|
cmCount--;
|
|
addDesc->Type = CmResourceTypeNull;
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
|
|
//
|
|
// Do the resource match?
|
|
//
|
|
if (addDesc->u.Dma.Channel != newDesc->u.Dma.Channel) {
|
|
|
|
//
|
|
// No, then stop
|
|
//
|
|
proceed = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// We can ignore the duplicate copy
|
|
//
|
|
addDesc->Type = CmResourceTypeNull;
|
|
cmCount--;
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
|
|
//
|
|
// Do the resource match?
|
|
//
|
|
if (addDesc->u.Interrupt.Vector !=
|
|
newDesc->u.Interrupt.Vector) {
|
|
|
|
//
|
|
// No, then stop
|
|
//
|
|
proceed = FALSE;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// We can ignore the duplicate copy
|
|
//
|
|
addDesc->Type = CmResourceTypeNull;
|
|
cmCount--;
|
|
break;
|
|
} // switch
|
|
|
|
//
|
|
// Do we have to stop?
|
|
//
|
|
if (proceed == FALSE) {
|
|
|
|
break;
|
|
}
|
|
|
|
} // for
|
|
|
|
} // for
|
|
|
|
//
|
|
// Do we have any items that we care about left?
|
|
//
|
|
if (cmCount == 0) {
|
|
|
|
//
|
|
// No, then free everything and return an empty list
|
|
//
|
|
ExFreePool( newList );
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Now we can build the proper list. See how many items we must
|
|
// allocate
|
|
//
|
|
size = sizeof(CM_RESOURCE_LIST) + (cmCount - 1) *
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|
globalList = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
size,
|
|
ACPI_RESOURCE_POOLTAG
|
|
);
|
|
if (globalList == NULL) {
|
|
|
|
ExFreePool( newList );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
//
|
|
// Initialize the list by copying the header from the AddList
|
|
//
|
|
RtlZeroMemory( globalList, size );
|
|
RtlCopyMemory(
|
|
globalList,
|
|
AddList,
|
|
sizeof(CM_RESOURCE_LIST)
|
|
);
|
|
cmPartialList = &(globalList->List[0].PartialResourceList);
|
|
cmPartialList->Count = cmCount;
|
|
|
|
//
|
|
// Copy all of the valid resources into this new list
|
|
//
|
|
for (cmIndex = 0, addIndex = 0;
|
|
cmIndex < maxSize && addIndex < cmCount;
|
|
cmIndex++) {
|
|
|
|
newDesc = &(newPartialList->PartialDescriptors[cmIndex]);
|
|
|
|
//
|
|
// If the type is null, skip it
|
|
//
|
|
if (newDesc->Type == CmResourceTypeNull) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Copy the new list
|
|
//
|
|
RtlCopyMemory(
|
|
&(cmPartialList->PartialDescriptors[addIndex]),
|
|
newDesc,
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
);
|
|
addIndex++;
|
|
|
|
}
|
|
|
|
//
|
|
// Free the old lists
|
|
//
|
|
ExFreePool( newList );
|
|
|
|
//
|
|
// Point the global to the new list
|
|
//
|
|
*GlobalList = globalList;
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPIRangeFilterPICInterrupt(
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to remove Interrupt #2 from the list of
|
|
resources that are returned by the PIC
|
|
|
|
Arguments:
|
|
|
|
IoResList - The IO Resource List to smash
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIO_RESOURCE_LIST ioList;
|
|
ULONG i;
|
|
ULONG j;
|
|
ULONG size;
|
|
|
|
//
|
|
// Sanity checks
|
|
//
|
|
if (IoResList == NULL) {
|
|
|
|
//
|
|
// No work to do
|
|
//
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Walk the resource requirements list
|
|
//
|
|
ioList = &(IoResList->List[0]);
|
|
for (i = 0; i < IoResList->AlternativeLists; i++) {
|
|
|
|
//
|
|
// Walk the IO list
|
|
//
|
|
for (j = 0; j < ioList->Count; j++) {
|
|
|
|
if (ioList->Descriptors[j].Type != CmResourceTypeInterrupt) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we have the case where the minimum starts on int 2?
|
|
//
|
|
if (ioList->Descriptors[j].u.Interrupt.MinimumVector == 2) {
|
|
|
|
//
|
|
// If the maximum is on 2, then we snuff out this
|
|
// descriptors, otherwise, we change the minimum
|
|
//
|
|
if (ioList->Descriptors[j].u.Interrupt.MaximumVector == 2) {
|
|
|
|
ioList->Descriptors[j].Type = CmResourceTypeNull;
|
|
|
|
} else {
|
|
|
|
ioList->Descriptors[j].u.Interrupt.MinimumVector++;
|
|
|
|
}
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we have the case where the maximum ends on int 2?
|
|
// Note that the minimum cannot be on 2...
|
|
//
|
|
if (ioList->Descriptors[j].u.Interrupt.MaximumVector == 2) {
|
|
|
|
ioList->Descriptors[j].u.Interrupt.MaximumVector--;
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// If INT2 is in the middle of the ranges, then prune them
|
|
// one way or the other...
|
|
//
|
|
if (ioList->Descriptors[j].u.Interrupt.MinimumVector < 2 &&
|
|
ioList->Descriptors[j].u.Interrupt.MaximumVector > 2) {
|
|
|
|
ioList->Descriptors[j].u.Interrupt.MinimumVector = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Next list
|
|
//
|
|
size = sizeof(IO_RESOURCE_LIST) +
|
|
( (ioList->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) );
|
|
ioList = (PIO_RESOURCE_LIST) ( ( (PUCHAR) ioList ) + size );
|
|
|
|
}
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPIRangeSortCmList(
|
|
IN PCM_RESOURCE_LIST CmResList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine ensures that the elements of a CmResList are sorted in
|
|
assending order (by type)
|
|
|
|
Arguments:
|
|
|
|
CmResList - The list to sort
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
CM_PARTIAL_RESOURCE_DESCRIPTOR tempDesc;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR curDesc;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR subDesc;
|
|
PCM_PARTIAL_RESOURCE_LIST cmList;
|
|
ULONG cmIndex;
|
|
ULONG cmSize;
|
|
ULONG cmSubLoop;
|
|
|
|
//
|
|
// Setup the pointer to the cmList
|
|
//
|
|
cmList = &(CmResList->List[0].PartialResourceList);
|
|
cmSize = cmList->Count;
|
|
|
|
for (cmIndex = 0; cmIndex < cmSize; cmIndex++) {
|
|
|
|
curDesc = &(cmList->PartialDescriptors[cmIndex]);
|
|
|
|
for (cmSubLoop = cmIndex + 1; cmSubLoop < cmSize; cmSubLoop++) {
|
|
|
|
subDesc = &(cmList->PartialDescriptors[cmSubLoop]);
|
|
|
|
//
|
|
// Is this a compatible descriptor?
|
|
//
|
|
if (curDesc->Type != subDesc->Type) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Test by type
|
|
//
|
|
if (curDesc->Type == CmResourceTypePort ||
|
|
curDesc->Type == CmResourceTypeMemory) {
|
|
|
|
if (subDesc->u.Port.Start.QuadPart <
|
|
curDesc->u.Port.Start.QuadPart) {
|
|
|
|
curDesc = subDesc;
|
|
|
|
}
|
|
|
|
} else if (curDesc->Type == CmResourceTypeInterrupt) {
|
|
|
|
if (subDesc->u.Interrupt.Vector < curDesc->u.Interrupt.Vector) {
|
|
|
|
curDesc = subDesc;
|
|
|
|
}
|
|
|
|
} else if (curDesc->Type == CmResourceTypeDma) {
|
|
|
|
if (subDesc->u.Dma.Channel < curDesc->u.Dma.Channel) {
|
|
|
|
curDesc = subDesc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Did we find a smaller element?
|
|
//
|
|
if (curDesc == &(cmList->PartialDescriptors[cmIndex])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// We have found the smallest element. Swap them
|
|
//
|
|
RtlCopyMemory(
|
|
&tempDesc,
|
|
&(cmList->PartialDescriptors[cmIndex]),
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
);
|
|
RtlCopyMemory(
|
|
&(cmList->PartialDescriptors[cmIndex]),
|
|
curDesc,
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
);
|
|
RtlCopyMemory(
|
|
curDesc,
|
|
&tempDesc,
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Success
|
|
//
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPIRangeSortIoList(
|
|
IN PIO_RESOURCE_LIST IoList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine ensures that the elements of a CmResList are sorted in
|
|
assending order (by type)
|
|
|
|
Arguments:
|
|
|
|
CmResList - The list to sort
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
IO_RESOURCE_DESCRIPTOR tempDesc;
|
|
PIO_RESOURCE_DESCRIPTOR curDesc;
|
|
PIO_RESOURCE_DESCRIPTOR subDesc;
|
|
ULONG ioIndex;
|
|
ULONG ioSize;
|
|
ULONG ioSubLoop;
|
|
|
|
//
|
|
// Count the number of element ioList
|
|
//
|
|
ioSize = IoList->Count;
|
|
|
|
for (ioIndex = 0; ioIndex < ioSize; ioIndex++) {
|
|
|
|
curDesc = &(IoList->Descriptors[ioIndex]);
|
|
|
|
for (ioSubLoop = ioIndex + 1; ioSubLoop < ioSize; ioSubLoop++) {
|
|
|
|
subDesc = &(IoList->Descriptors[ioSubLoop]);
|
|
|
|
//
|
|
// Is this a compatible descriptor?
|
|
//
|
|
if (curDesc->Type != subDesc->Type) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Test by type
|
|
//
|
|
if (curDesc->Type == CmResourceTypePort ||
|
|
curDesc->Type == CmResourceTypeMemory) {
|
|
|
|
if (subDesc->u.Port.MinimumAddress.QuadPart <
|
|
curDesc->u.Port.MinimumAddress.QuadPart) {
|
|
|
|
curDesc = subDesc;
|
|
|
|
}
|
|
|
|
} else if (curDesc->Type == CmResourceTypeInterrupt ||
|
|
curDesc->Type == CmResourceTypeDma) {
|
|
|
|
if (subDesc->u.Interrupt.MinimumVector <
|
|
curDesc->u.Interrupt.MinimumVector) {
|
|
|
|
curDesc = subDesc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Did we find a smaller element?
|
|
//
|
|
if (curDesc == &(IoList->Descriptors[ioIndex])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// We have found the smallest element. Swap them
|
|
//
|
|
RtlCopyMemory(
|
|
&tempDesc,
|
|
&(IoList->Descriptors[ioIndex]),
|
|
sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
);
|
|
RtlCopyMemory(
|
|
&(IoList->Descriptors[ioIndex]),
|
|
curDesc,
|
|
sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
);
|
|
RtlCopyMemory(
|
|
curDesc,
|
|
&tempDesc,
|
|
sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Success
|
|
//
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPIRangeSubtract(
|
|
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResReqList,
|
|
IN PCM_RESOURCE_LIST CmResList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine takes a IoResReqList, and subtracts the CmResList
|
|
from each one of the IoResList, and returns the new list
|
|
|
|
Arguments:
|
|
|
|
IoResReqList The original list and where to store the new one
|
|
CmResList What to subtract
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIO_RESOURCE_LIST curList;
|
|
PIO_RESOURCE_LIST *resourceArray;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST newList;
|
|
PUCHAR buffer;
|
|
ULONG listIndex;
|
|
ULONG listSize = (*IoResReqList)->AlternativeLists;
|
|
ULONG newSize;
|
|
ULONG size;
|
|
|
|
//
|
|
// Sort the CmResList
|
|
//
|
|
status = ACPIRangeSortCmList( CmResList );
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_FAILURE,
|
|
"ACPIRangeSubtract: AcpiRangeSortCmList 0x%08lx Failed 0x%08lx\n",
|
|
CmResList,
|
|
status
|
|
) );
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate an array to hold all the alternatives
|
|
//
|
|
resourceArray = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(PIO_RESOURCE_LIST) * listSize,
|
|
ACPI_RESOURCE_POOLTAG
|
|
);
|
|
if (resourceArray == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
RtlZeroMemory( resourceArray, sizeof(PIO_RESOURCE_LIST) * listSize );
|
|
|
|
//
|
|
// Get the first list to work on
|
|
//
|
|
curList = &( (*IoResReqList)->List[0]);
|
|
buffer = (PUCHAR) curList;
|
|
newSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) - sizeof(IO_RESOURCE_LIST);
|
|
|
|
//
|
|
// Sort the IoResList
|
|
//
|
|
status = ACPIRangeSortIoList( curList );
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_FAILURE,
|
|
"ACPIRangeSubtract: AcpiRangeSortIoList 0x%08lx Failed 0x%08lx\n",
|
|
*curList,
|
|
status
|
|
) );
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Process all the elements in the list
|
|
//
|
|
for (listIndex = 0; listIndex < listSize; listIndex++) {
|
|
|
|
//
|
|
// Process that list
|
|
//
|
|
status = ACPIRangeSubtractIoList(
|
|
curList,
|
|
CmResList,
|
|
&(resourceArray[listIndex])
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIRangeSubtract: Failed - 0x%08lx\n",
|
|
status
|
|
) );
|
|
while (listIndex) {
|
|
|
|
ExFreePool( resourceArray[listIndex] );
|
|
listIndex--;
|
|
|
|
}
|
|
ExFreePool( resourceArray );
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// Help calculate the size of the new res req descriptor
|
|
//
|
|
newSize += sizeof(IO_RESOURCE_LIST) +
|
|
( ( (resourceArray[listIndex])->Count - 1) *
|
|
sizeof(IO_RESOURCE_DESCRIPTOR) );
|
|
|
|
//
|
|
// Find the next list
|
|
//
|
|
size = sizeof(IO_RESOURCE_LIST) + (curList->Count - 1) *
|
|
sizeof(IO_RESOURCE_DESCRIPTOR);
|
|
buffer += size;
|
|
curList = (PIO_RESOURCE_LIST) buffer;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate the new list
|
|
//
|
|
newList = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
newSize,
|
|
ACPI_RESOURCE_POOLTAG
|
|
);
|
|
if (newList == NULL) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIRangeSubtract: Failed to allocate 0x%08lx bytes\n",
|
|
size
|
|
) );
|
|
do {
|
|
|
|
listSize--;
|
|
ExFreePool( resourceArray[listSize] );
|
|
|
|
} while (listSize);
|
|
ExFreePool( resourceArray );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
//
|
|
// Copy the head of the res req list
|
|
//
|
|
RtlZeroMemory( newList, newSize );
|
|
RtlCopyMemory(
|
|
newList,
|
|
*IoResReqList,
|
|
sizeof(IO_RESOURCE_REQUIREMENTS_LIST) -
|
|
sizeof(IO_RESOURCE_LIST)
|
|
);
|
|
newList->ListSize = newSize;
|
|
curList = &(newList->List[0]);
|
|
buffer = (PUCHAR) curList;
|
|
|
|
for (listIndex = 0; listIndex < listSize; listIndex++) {
|
|
|
|
//
|
|
// Determine the size to copy
|
|
//
|
|
size = sizeof(IO_RESOURCE_LIST) +
|
|
( ( ( (resourceArray[listIndex])->Count) - 1) *
|
|
sizeof(IO_RESOURCE_DESCRIPTOR) );
|
|
|
|
//
|
|
// Copy the new resource to the correct place
|
|
//
|
|
RtlCopyMemory(
|
|
curList,
|
|
resourceArray[ listIndex ],
|
|
size
|
|
);
|
|
|
|
//
|
|
// Find the next list
|
|
//
|
|
buffer += size;
|
|
curList = (PIO_RESOURCE_LIST) buffer;
|
|
|
|
//
|
|
// Done with this list
|
|
//
|
|
ExFreePool( resourceArray[listIndex] );
|
|
|
|
}
|
|
|
|
//
|
|
// Done with this area of memory
|
|
//
|
|
ExFreePool( resourceArray );
|
|
|
|
//
|
|
// Free Old list
|
|
//
|
|
ExFreePool( *IoResReqList );
|
|
|
|
//
|
|
// Return the new list
|
|
//
|
|
*IoResReqList = newList;
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPIRangeSubtractIoList(
|
|
IN PIO_RESOURCE_LIST IoResList,
|
|
IN PCM_RESOURCE_LIST CmResList,
|
|
OUT PIO_RESOURCE_LIST *Result
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is responsible for subtracting the elements of the
|
|
CmResList from the IoResList
|
|
|
|
Arguments:
|
|
|
|
IoResList - The list to subtract from
|
|
CmResList - The list to subtract
|
|
Result - The answer
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// The current CM descriptor
|
|
//
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc;
|
|
//
|
|
// The current CM resource list that we are processing
|
|
//
|
|
PCM_PARTIAL_RESOURCE_LIST cmList;
|
|
//
|
|
// The current IO descriptor
|
|
//
|
|
PIO_RESOURCE_DESCRIPTOR ioDesc;
|
|
//
|
|
// The working copy of the result list
|
|
//
|
|
PIO_RESOURCE_LIST workList;
|
|
//
|
|
// The current index into the cm res list
|
|
//
|
|
ULONG cmIndex;
|
|
//
|
|
// The number of elements there are in the cm res list
|
|
//
|
|
ULONG cmSize;
|
|
//
|
|
// The current index into the io res list
|
|
//
|
|
ULONG ioIndex;
|
|
//
|
|
// The number of elements there are in the io res list
|
|
//
|
|
ULONG ioSize;
|
|
//
|
|
// The current index into the result. This is where the 'next' resource
|
|
// descriptor goes into.
|
|
//
|
|
ULONG resultIndex = 0;
|
|
//
|
|
// How many elements there are in the result
|
|
//
|
|
ULONG resultSize;
|
|
//
|
|
// These are the max and min of the cm desc
|
|
//
|
|
ULONGLONG cmMax, cmMin;
|
|
//
|
|
// These are the max and min of the io desc
|
|
//
|
|
ULONGLONG ioMax, ioMin;
|
|
//
|
|
// The length of the resource
|
|
//
|
|
ULONGLONG length;
|
|
|
|
//
|
|
// Step one: Obtain the pointers we need to the start of the cm list
|
|
// and the size of the supplied lists
|
|
//
|
|
cmList = &(CmResList->List[0].PartialResourceList);
|
|
cmSize = cmList->Count;
|
|
ioSize = IoResList->Count;
|
|
|
|
//
|
|
// Step two: Calculate the number of Io descriptors needed in the
|
|
// worst case. That is 2x the number of cm descriptors plut the number
|
|
// of original io descriptors.
|
|
//
|
|
resultSize = cmSize * 2 + ioSize * 2;
|
|
|
|
//
|
|
// Step three: Allocate enough memory for those descriptors
|
|
//
|
|
workList = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(IO_RESOURCE_LIST) +
|
|
(sizeof(IO_RESOURCE_DESCRIPTOR) * (resultSize - 1) ),
|
|
ACPI_RESOURCE_POOLTAG
|
|
);
|
|
if (workList == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
RtlZeroMemory( workList, sizeof(IO_RESOURCE_LIST) +
|
|
(sizeof(IO_RESOURCE_DESCRIPTOR) * (resultSize - 1) ) );
|
|
RtlCopyMemory(
|
|
workList,
|
|
IoResList,
|
|
sizeof(IO_RESOURCE_LIST) - sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
);
|
|
|
|
//
|
|
// Step four: walk through the entire io res list
|
|
//
|
|
for (ioIndex = 0; ioIndex < ioSize; ioIndex++) {
|
|
|
|
//
|
|
// Step five: copy the current descriptor to the result, and
|
|
// keep a pointer to it. Remember where to store the next io
|
|
// descriptor.
|
|
//
|
|
RtlCopyMemory(
|
|
&(workList->Descriptors[resultIndex]),
|
|
&(IoResList->Descriptors[ioIndex]),
|
|
sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
);
|
|
ACPIPrint( (
|
|
ACPI_PRINT_RESOURCES_2,
|
|
"Copied Desc %d (0x%08lx) to Index %d (0x%08lx)\n",
|
|
ioIndex,
|
|
&(IoResList->Descriptors[ioIndex]),
|
|
resultIndex,
|
|
&(workList->Descriptors[resultIndex])
|
|
) );
|
|
ioDesc = &(workList->Descriptors[resultIndex]);
|
|
resultIndex += 1;
|
|
|
|
//
|
|
// Step six: Walk the Cm Res list, looking for resources to
|
|
// subtract from this descriptor
|
|
//
|
|
for (cmIndex = 0; cmIndex < cmSize; cmIndex++) {
|
|
|
|
//
|
|
// If we don't have a resource descriptor any more, then
|
|
// we stop looping
|
|
//
|
|
if (ioDesc == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Step seven: determine the current cm descriptor
|
|
//
|
|
cmDesc = &(cmList->PartialDescriptors[cmIndex]);
|
|
|
|
//
|
|
// Step eight: is the current cm descriptor of the same type
|
|
// as the io descriptor?
|
|
//
|
|
if (cmDesc->Type != ioDesc->Type) {
|
|
|
|
//
|
|
// No
|
|
//
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Step nine: we must handle each resource type indepently.
|
|
//
|
|
switch (ioDesc->Type) {
|
|
case CmResourceTypeMemory:
|
|
case CmResourceTypePort:
|
|
|
|
ioMin = ioDesc->u.Port.MinimumAddress.QuadPart;
|
|
ioMax = ioDesc->u.Port.MaximumAddress.QuadPart;
|
|
cmMin = cmDesc->u.Port.Start.QuadPart;
|
|
cmMax = cmDesc->u.Port.Start.QuadPart +
|
|
cmDesc->u.Port.Length - 1;
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_RESOURCES_2,
|
|
"ACPIRangeSubtractIoRange: ioMin 0x%lx ioMax 0x%lx "
|
|
"cmMin 0x%lx cmMax 0x%lx resultIndex 0x%lx\n",
|
|
(ULONG) ioMin,
|
|
(ULONG) ioMax,
|
|
(ULONG) cmMin,
|
|
(ULONG) cmMax,
|
|
resultIndex
|
|
) );
|
|
|
|
//
|
|
// Does the descriptors overlap?
|
|
//
|
|
if (ioMin > cmMax || ioMax < cmMin) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we need to remove the descriptor from the list?
|
|
//
|
|
if (ioMin >= cmMin && ioMax <= cmMax) {
|
|
|
|
resultIndex -= 1;
|
|
ioDesc = NULL;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we need to truncate the lowpart of the io desc?
|
|
//
|
|
if (ioMin >= cmMin && ioMax > cmMax) {
|
|
|
|
ioDesc->u.Port.MinimumAddress.QuadPart = (cmMax + 1);
|
|
length = ioMax - cmMax;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we need to truncate the highpart of the io desc?
|
|
//
|
|
if (ioMin < cmMin && ioMax <= cmMax) {
|
|
|
|
ioDesc->u.Port.MaximumAddress.QuadPart = (cmMin - 1);
|
|
length = cmMin - ioMin;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we need to split the descriptor into two parts
|
|
//
|
|
if (ioMin < cmMin && ioMax > cmMax) {
|
|
|
|
//
|
|
// Create a new descriptors
|
|
//
|
|
RtlCopyMemory(
|
|
&(workList->Descriptors[resultIndex]),
|
|
ioDesc,
|
|
sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
);
|
|
ACPIPrint( (
|
|
ACPI_PRINT_RESOURCES_2,
|
|
"Copied Desc (0x%08lx) to Index %d (0x%08lx)\n",
|
|
&(IoResList->Descriptors[ioIndex]),
|
|
resultIndex,
|
|
&(workList->Descriptors[resultIndex])
|
|
) );
|
|
ioDesc->u.Port.MaximumAddress.QuadPart = (cmMin - 1);
|
|
ioDesc->u.Port.Alignment = 1;
|
|
length = cmMin - ioMin;
|
|
if ( (ULONG) length < ioDesc->u.Port.Length) {
|
|
|
|
ioDesc->u.Port.Length = (ULONG) length;
|
|
|
|
}
|
|
|
|
//
|
|
// Next descriptor
|
|
//
|
|
ioDesc = &(workList->Descriptors[resultIndex]);
|
|
ioDesc->u.Port.MinimumAddress.QuadPart = (cmMax + 1);
|
|
ioDesc->u.Port.Alignment = 1;
|
|
length = ioMax - cmMax;
|
|
resultIndex += 1;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we need to update the length?
|
|
//
|
|
if ( (ULONG) length < ioDesc->u.Port.Length) {
|
|
|
|
ioDesc->u.Port.Length = (ULONG) length;
|
|
|
|
}
|
|
break;
|
|
|
|
case CmResourceTypeInterrupt:
|
|
|
|
//
|
|
// Do the descriptors overlap?
|
|
//
|
|
if (ioDesc->u.Interrupt.MinimumVector >
|
|
cmDesc->u.Interrupt.Vector ||
|
|
ioDesc->u.Interrupt.MaximumVector <
|
|
cmDesc->u.Interrupt.Vector) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we have to remove the descriptor
|
|
//
|
|
if (ioDesc->u.Interrupt.MinimumVector ==
|
|
cmDesc->u.Interrupt.Vector &&
|
|
ioDesc->u.Interrupt.MaximumVector ==
|
|
cmDesc->u.Interrupt.Vector) {
|
|
|
|
resultIndex =- 1;
|
|
ioDesc = NULL;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we clip the low part?
|
|
//
|
|
if (ioDesc->u.Interrupt.MinimumVector ==
|
|
cmDesc->u.Interrupt.Vector) {
|
|
|
|
ioDesc->u.Interrupt.MinimumVector++;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we clip the high part
|
|
//
|
|
if (ioDesc->u.Interrupt.MaximumVector ==
|
|
cmDesc->u.Interrupt.Vector) {
|
|
|
|
ioDesc->u.Interrupt.MaximumVector--;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Split the record
|
|
//
|
|
RtlCopyMemory(
|
|
&(workList->Descriptors[resultIndex]),
|
|
ioDesc,
|
|
sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
);
|
|
ACPIPrint( (
|
|
ACPI_PRINT_RESOURCES_2,
|
|
"Copied Desc (0x%08lx) to Index %d (0x%08lx)\n",
|
|
&(IoResList->Descriptors[ioIndex]),
|
|
resultIndex,
|
|
&(workList->Descriptors[resultIndex])
|
|
) );
|
|
ioDesc->u.Interrupt.MaximumVector =
|
|
cmDesc->u.Interrupt.Vector - 1;
|
|
ioDesc = &(workList->Descriptors[resultIndex]);
|
|
ioDesc->u.Interrupt.MinimumVector =
|
|
cmDesc->u.Interrupt.Vector + 1;
|
|
resultIndex += 1;
|
|
break;
|
|
|
|
case CmResourceTypeDma:
|
|
|
|
//
|
|
// Do the descriptors overlap?
|
|
//
|
|
if (ioDesc->u.Dma.MinimumChannel >
|
|
cmDesc->u.Dma.Channel ||
|
|
ioDesc->u.Dma.MaximumChannel <
|
|
cmDesc->u.Dma.Channel) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we have to remove the descriptor
|
|
//
|
|
if (ioDesc->u.Dma.MinimumChannel ==
|
|
cmDesc->u.Dma.Channel &&
|
|
ioDesc->u.Dma.MaximumChannel ==
|
|
cmDesc->u.Dma.Channel) {
|
|
|
|
resultIndex -= 1;
|
|
ioDesc = NULL;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we clip the low part?
|
|
//
|
|
if (ioDesc->u.Dma.MinimumChannel ==
|
|
cmDesc->u.Dma.Channel) {
|
|
|
|
ioDesc->u.Dma.MinimumChannel++;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Do we clip the high part
|
|
//
|
|
if (ioDesc->u.Dma.MaximumChannel ==
|
|
cmDesc->u.Dma.Channel) {
|
|
|
|
ioDesc->u.Dma.MaximumChannel--;
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Split the record
|
|
//
|
|
RtlCopyMemory(
|
|
&(workList->Descriptors[resultIndex]),
|
|
ioDesc,
|
|
sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
);
|
|
ACPIPrint( (
|
|
ACPI_PRINT_RESOURCES_2,
|
|
"Copied Desc (0x%08lx) to Index %d (0x%08lx)\n",
|
|
&(IoResList->Descriptors[ioIndex]),
|
|
resultIndex,
|
|
&(workList->Descriptors[resultIndex])
|
|
) );
|
|
ioDesc->u.Dma.MaximumChannel =
|
|
cmDesc->u.Dma.Channel - 1;
|
|
ioDesc = &(workList->Descriptors[resultIndex]);
|
|
ioDesc->u.Dma.MinimumChannel =
|
|
cmDesc->u.Dma.Channel + 1;
|
|
resultIndex += 1;
|
|
break;
|
|
} // switch
|
|
|
|
} // for
|
|
|
|
//
|
|
// Step ten, make a backup copy of the original descriptor, and
|
|
// mark it as a DeviceSpecific resource
|
|
//
|
|
RtlCopyMemory(
|
|
&(workList->Descriptors[resultIndex]),
|
|
&(IoResList->Descriptors[ioIndex]),
|
|
sizeof(IO_RESOURCE_DESCRIPTOR)
|
|
);
|
|
ACPIPrint( (
|
|
ACPI_PRINT_RESOURCES_2,
|
|
"Copied Desc %d (0x%08lx) to Index %d (0x%08lx) for backup\n",
|
|
ioIndex,
|
|
&(IoResList->Descriptors[ioIndex]),
|
|
resultIndex,
|
|
&(workList->Descriptors[resultIndex])
|
|
) );
|
|
|
|
ioDesc = &(workList->Descriptors[resultIndex]);
|
|
ioDesc->Type = CmResourceTypeDevicePrivate;
|
|
resultIndex += 1;
|
|
|
|
} // for
|
|
|
|
//
|
|
// Step 11: Calculate the number of resources in the new list
|
|
//
|
|
workList->Count = resultIndex;
|
|
|
|
//
|
|
// Step 12: Allocate the block for the return value. Don't waste
|
|
// any memory here
|
|
//
|
|
*Result = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(IO_RESOURCE_LIST) +
|
|
(sizeof(IO_RESOURCE_DESCRIPTOR) * (resultIndex - 1) ),
|
|
ACPI_RESOURCE_POOLTAG
|
|
);
|
|
if (*Result == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
//
|
|
// Step 13: Copy the result over and free the work buffer
|
|
//
|
|
RtlCopyMemory(
|
|
*Result,
|
|
workList,
|
|
sizeof(IO_RESOURCE_LIST) +
|
|
(sizeof(IO_RESOURCE_DESCRIPTOR) * (resultIndex - 1) )
|
|
);
|
|
|
|
//
|
|
// Step 14: Done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
ACPIRangeValidatePciMemoryResource(
|
|
IN PIO_RESOURCE_LIST IoList,
|
|
IN ULONG Index,
|
|
IN PACPI_BIOS_MULTI_NODE E820Info,
|
|
OUT ULONG *BugCheck
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks the specified descriptor in the resource list does
|
|
not in any way overlap or conflict with any of the descriptors in the
|
|
E820 information structure
|
|
|
|
Arguments:
|
|
|
|
IoResList - The IoResourceList to check
|
|
Index - The descript we are currently looking at
|
|
E820Info - The BIOS's memory description table (Chapter 14 of ACPI Spec)
|
|
BugCheck - The number of bugcheckable offences commited
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
ULONGLONG absMin;
|
|
ULONGLONG absMax;
|
|
|
|
ASSERT( IoList != NULL );
|
|
|
|
//
|
|
// Make sure that there is an E820 table before we look at it
|
|
//
|
|
if (E820Info == NULL) {
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Calculate the absolute maximum and minimum size of the memory window
|
|
//
|
|
absMin = IoList->Descriptors[Index].u.Memory.MinimumAddress.QuadPart;
|
|
absMax = IoList->Descriptors[Index].u.Memory.MaximumAddress.QuadPart;
|
|
|
|
//
|
|
// Look at all the entries in the E820Info and see if there is an
|
|
// overlap
|
|
//
|
|
for (i = 0; i < E820Info->Count; i++) {
|
|
|
|
//
|
|
// Hackhack --- if this is a "Reserved" address, then don't consider
|
|
// those a bugcheck
|
|
//
|
|
if (E820Info->E820Entry[i].Type == AcpiAddressRangeReserved) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// Do some fixups firsts
|
|
//
|
|
if (E820Info->E820Entry[i].Type == AcpiAddressRangeNVS ||
|
|
E820Info->E820Entry[i].Type == AcpiAddressRangeACPI) {
|
|
|
|
ASSERT( E820Info->E820Entry[i].Length.HighPart == 0);
|
|
if (E820Info->E820Entry[i].Length.HighPart != 0) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_WARNING,
|
|
"ACPI: E820 Entry #%d (type %d) Length = %016I64x > 32bit\n",
|
|
i,
|
|
E820Info->E820Entry[i].Type,
|
|
E820Info->E820Entry[i].Length.QuadPart
|
|
) );
|
|
E820Info->E820Entry[i].Length.HighPart = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Is the descriptor beyond what we are looking for?
|
|
//
|
|
if (absMax < (ULONGLONG) E820Info->E820Entry[i].Base.QuadPart) {
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Is it before what we are looking for?
|
|
//
|
|
if (absMin >= (ULONGLONG) (E820Info->E820Entry[i].Base.QuadPart + E820Info->E820Entry[i].Length.QuadPart) ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPI: E820 Entry %d (type %I64d) (%I64x-%I64x) overlaps\n"
|
|
"ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
|
|
i, E820Info->E820Entry[i].Type,
|
|
E820Info->E820Entry[i].Base.QuadPart,
|
|
(E820Info->E820Entry[i].Base.QuadPart + E820Info->E820Entry[i].Length.QuadPart),
|
|
Index,
|
|
IoList->Descriptors[Index].u.Memory.MinimumAddress.QuadPart,
|
|
IoList->Descriptors[Index].u.Memory.MaximumAddress.QuadPart,
|
|
IoList->Descriptors[Index].u.Memory.Length,
|
|
IoList->Descriptors[Index].u.Memory.Alignment
|
|
) );
|
|
|
|
//
|
|
// Is this an NVS area? Are we doing an override of this?
|
|
//
|
|
if ( (AcpiOverrideAttributes & ACPI_OVERRIDE_NVS_CHECK) &&
|
|
(E820Info->E820Entry[i].Type == AcpiAddressRangeNVS) ) {
|
|
|
|
if (absMax >= (ULONGLONG) E820Info->E820Entry[i].Base.QuadPart &&
|
|
absMin < (ULONGLONG) E820Info->E820Entry[i].Base.QuadPart) {
|
|
|
|
//
|
|
// We can attempt to do a helpfull fixup here
|
|
//
|
|
IoList->Descriptors[Index].u.Memory.MaximumAddress.QuadPart =
|
|
(ULONGLONG) E820Info->E820Entry[i].Base.QuadPart - 1;
|
|
IoList->Descriptors[Index].u.Memory.Length = (ULONG)
|
|
(IoList->Descriptors[Index].u.Memory.MaximumAddress.QuadPart -
|
|
IoList->Descriptors[Index].u.Memory.MinimumAddress.QuadPart + 1);
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPI: PCI Entry %d Changed to\n"
|
|
"ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
|
|
Index,
|
|
Index,
|
|
IoList->Descriptors[Index].u.Memory.MinimumAddress.QuadPart,
|
|
IoList->Descriptors[Index].u.Memory.MaximumAddress.QuadPart,
|
|
IoList->Descriptors[Index].u.Memory.Length,
|
|
IoList->Descriptors[Index].u.Memory.Alignment
|
|
) );
|
|
|
|
}
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPI: E820 Entry %d Overrides PCI Entry\n",
|
|
i
|
|
) );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
//
|
|
// If we got here, then there is an overlap, and we need to bugcheck
|
|
//
|
|
(*BugCheck)++;
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ACPIRangeValidatePciResources(
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to make sure that the resource that we will
|
|
hand of to PCI have a chance of making the system boot.
|
|
|
|
This is what the list will allow
|
|
MEM - A0000 - DFFFF,
|
|
<Physical Base> - 4GB
|
|
IO - Any
|
|
BUS - Any
|
|
|
|
The code checks to make sure that the Length = Max - Min + 1, and that
|
|
the Alignment value is correct
|
|
|
|
Arguments:
|
|
|
|
IoResList - The list to check
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PACPI_BIOS_MULTI_NODE e820Info;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartialDesc;
|
|
PCM_PARTIAL_RESOURCE_LIST cmPartialList;
|
|
PIO_RESOURCE_LIST ioList;
|
|
PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64 keyInfo;
|
|
ULONG bugCheck = 0;
|
|
ULONG i;
|
|
ULONG j;
|
|
ULONGLONG length;
|
|
ULONG size;
|
|
|
|
if (IoResList == NULL) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIRangeValidPciResources: No IoResList\n"
|
|
) );
|
|
|
|
KeBugCheckEx(
|
|
ACPI_BIOS_ERROR,
|
|
ACPI_ROOT_PCI_RESOURCE_FAILURE,
|
|
(ULONG_PTR) DeviceExtension,
|
|
2,
|
|
0
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Read the key for the AcpiConfigurationData
|
|
//
|
|
status = OSReadAcpiConfigurationData( &keyInfo );
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIRangeValidatePciResources: Cannot get Information %08lx\n",
|
|
status
|
|
) );
|
|
return;
|
|
|
|
}
|
|
|
|
//
|
|
// Crack the structure to get the E820Table entry
|
|
//
|
|
cmPartialList = (PCM_PARTIAL_RESOURCE_LIST) (keyInfo->Data);
|
|
cmPartialDesc = &(cmPartialList->PartialDescriptors[0]);
|
|
e820Info = (PACPI_BIOS_MULTI_NODE) ( (PUCHAR) cmPartialDesc +
|
|
sizeof(CM_PARTIAL_RESOURCE_LIST) );
|
|
|
|
//
|
|
// Walk the resource requirements list
|
|
//
|
|
ioList = &(IoResList->List[0]);
|
|
for (i = 0; i < IoResList->AlternativeLists; i++) {
|
|
|
|
//
|
|
// Walk the IO list
|
|
//
|
|
for (j = 0; j < ioList->Count; j++) {
|
|
|
|
if (ioList->Descriptors[j].Type == CmResourceTypePort ||
|
|
ioList->Descriptors[j].Type == CmResourceTypeMemory) {
|
|
|
|
length = ioList->Descriptors[j].u.Port.MaximumAddress.QuadPart -
|
|
ioList->Descriptors[j].u.Port.MinimumAddress.QuadPart + 1;
|
|
|
|
|
|
if (length > MAXULONG) {
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPI: Invalid IO/Mem Length > MAXULONG)\n"
|
|
"ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
|
|
j,
|
|
ioList->Descriptors[j].u.Memory.MinimumAddress.QuadPart,
|
|
ioList->Descriptors[j].u.Memory.MaximumAddress.QuadPart,
|
|
length,
|
|
ioList->Descriptors[j].u.Memory.Alignment
|
|
) );
|
|
bugCheck++;
|
|
}
|
|
//
|
|
// Does the length match?
|
|
//
|
|
if (length != ioList->Descriptors[j].u.Port.Length) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPI: Invalid IO/Mem Length - ( (Max - Min + 1) != Length)\n"
|
|
"ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
|
|
j,
|
|
ioList->Descriptors[j].u.Memory.MinimumAddress.QuadPart,
|
|
ioList->Descriptors[j].u.Memory.MaximumAddress.QuadPart,
|
|
ioList->Descriptors[j].u.Memory.Length,
|
|
ioList->Descriptors[j].u.Memory.Alignment
|
|
) );
|
|
bugCheck++;
|
|
|
|
}
|
|
|
|
//
|
|
// Is the alignment non-zero?
|
|
//
|
|
if (ioList->Descriptors[j].u.Port.Alignment == 0) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPI: Invalid IO/Mem Alignment"
|
|
"ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
|
|
j,
|
|
ioList->Descriptors[j].u.Memory.MinimumAddress.QuadPart,
|
|
ioList->Descriptors[j].u.Memory.MaximumAddress.QuadPart,
|
|
ioList->Descriptors[j].u.Memory.Length,
|
|
ioList->Descriptors[j].u.Memory.Alignment
|
|
) );
|
|
bugCheck++;
|
|
|
|
}
|
|
|
|
//
|
|
// The alignment cannot intersect with the min value
|
|
//
|
|
if (ioList->Descriptors[j].u.Port.MinimumAddress.LowPart &
|
|
(ioList->Descriptors[j].u.Port.Alignment - 1) ) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPI: Invalid IO/Mem Alignment - (Min & (Align - 1) )\n"
|
|
"ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
|
|
j,
|
|
ioList->Descriptors[j].u.Memory.MinimumAddress.QuadPart,
|
|
ioList->Descriptors[j].u.Memory.MaximumAddress.QuadPart,
|
|
ioList->Descriptors[j].u.Memory.Length,
|
|
ioList->Descriptors[j].u.Memory.Alignment
|
|
) );
|
|
bugCheck++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ioList->Descriptors[j].Type == CmResourceTypeBusNumber) {
|
|
|
|
length = ioList->Descriptors[j].u.BusNumber.MaxBusNumber -
|
|
ioList->Descriptors[j].u.BusNumber.MinBusNumber + 1;
|
|
|
|
//
|
|
// Does the length match?
|
|
//
|
|
if (length != ioList->Descriptors[j].u.BusNumber.Length) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPI: Invalid BusNumber Length - ( (Max - Min + 1) != Length)\n"
|
|
"ACPI: PCI Entry %d Min:%x Max:%x Length:%lx\n",
|
|
j,
|
|
ioList->Descriptors[j].u.BusNumber.MinBusNumber,
|
|
ioList->Descriptors[j].u.BusNumber.MaxBusNumber,
|
|
ioList->Descriptors[j].u.BusNumber.Length
|
|
) );
|
|
bugCheck++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ioList->Descriptors[j].Type == CmResourceTypeMemory) {
|
|
|
|
ACPIRangeValidatePciMemoryResource(
|
|
ioList,
|
|
j,
|
|
e820Info,
|
|
&bugCheck
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Next list
|
|
//
|
|
size = sizeof(IO_RESOURCE_LIST) +
|
|
( (ioList->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) );
|
|
ioList = (PIO_RESOURCE_LIST) ( ( (PUCHAR) ioList ) + size );
|
|
|
|
}
|
|
|
|
//
|
|
// Do we errors?
|
|
//
|
|
if (bugCheck) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPI:\n"
|
|
"ACPI: FATAL BIOS ERROR - Need new BIOS to fix PCI problems\n"
|
|
"ACPI:\n"
|
|
"ACPI: This machine will not boot after 8/26/98!!!!\n"
|
|
) );
|
|
|
|
//
|
|
// No, well, bugcheck
|
|
//
|
|
KeBugCheckEx(
|
|
ACPI_BIOS_ERROR,
|
|
ACPI_ROOT_PCI_RESOURCE_FAILURE,
|
|
(ULONG_PTR) DeviceExtension,
|
|
(ULONG_PTR) IoResList,
|
|
(ULONG_PTR) e820Info
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Free the E820 info
|
|
//
|
|
ExFreePool( keyInfo );
|
|
}
|