Add all pci bridge control function (PciBridgeIoBase, PciBridgeIoLimit, PciBridgeMemoryBase, PciBridgeMemoryLimit, PciBridgePrefetchMemoryBase, PciBridgePrefetchMemoryLimit, PciBridgeMemoryWorstCasealignment, PciBridgeIsPositiveDecode, PciBridgeIsSubtractiveDecode)

More support ICH0/1/2/3/4 hub
Add all PCI2PCI bridge limit/current resource codes (PPBridge_*), now is BAR setup okay, and Device_* must be implement
Support ISA+VGA legacy decode, 20+64-bit decode, ROM BAR, prefetch BAR

svn path=/trunk/; revision=48298
This commit is contained in:
evb 2010-07-27 03:24:24 +00:00
parent 8458508701
commit bf7de6528b
3 changed files with 735 additions and 10 deletions

View file

@ -1070,6 +1070,14 @@ PciExecuteCriticalSystemRoutine(
IN ULONG_PTR IpiContext
);
BOOLEAN
NTAPI
PciCreateIoDescriptorFromBarLimit(
PIO_RESOURCE_DESCRIPTOR ResourceDescriptor,
IN PULONG BarArray,
IN BOOLEAN Rom
);
BOOLEAN
NTAPI
PciIsSlotPresentInParentMethod(

View file

@ -16,36 +16,612 @@
/* FUNCTIONS ******************************************************************/
ULONG
NTAPI
PciBridgeIoBase(IN PPCI_COMMON_HEADER PciData)
{
BOOLEAN Is32Bit;
ULONG Base, IoBase;
ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
/* Get the base */
Base = PciData->u.type1.IOLimit;
/* Low bit specifies 32-bit address, top bits specify the base */
Is32Bit = (Base & 0xF) == 1;
IoBase = (Base & 0xF0) << 8;
/* Is it 32-bit? */
if (Is32Bit)
{
/* Read the upper 16-bits from the other register */
IoBase |= PciData->u.type1.IOBaseUpper16 << 16;
ASSERT(PciData->u.type1.IOLimit & 0x1);
}
/* Return the base address */
return IoBase;
}
ULONG
NTAPI
PciBridgeIoLimit(IN PPCI_COMMON_HEADER PciData)
{
BOOLEAN Is32Bit;
ULONG Limit, IoLimit;
ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
/* Get the limit */
Limit = PciData->u.type1.IOLimit;
/* Low bit specifies 32-bit address, top bits specify the limit */
Is32Bit = (Limit & 0xF) == 1;
IoLimit = (Limit & 0xF0) << 8;
/* Is it 32-bit? */
if (Is32Bit)
{
/* Read the upper 16-bits from the other register */
IoLimit |= PciData->u.type1.IOLimitUpper16 << 16;
ASSERT(PciData->u.type1.IOBase & 0x1);
}
/* Return the I/O limit */
return IoLimit | 0xFFF;
}
ULONG
NTAPI
PciBridgeMemoryBase(IN PPCI_COMMON_HEADER PciData)
{
ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
/* Return the memory base */
return (PciData->u.type1.MemoryBase << 16);
}
ULONG
NTAPI
PciBridgeMemoryLimit(IN PPCI_COMMON_HEADER PciData)
{
ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
/* Return the memory limit */
return (PciData->u.type1.MemoryLimit << 16) | 0xFFFFF;
}
PHYSICAL_ADDRESS
NTAPI
PciBridgePrefetchMemoryBase(IN PPCI_COMMON_HEADER PciData)
{
BOOLEAN Is64Bit;
LARGE_INTEGER Base;
USHORT PrefetchBase;
ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
/* Get the base */
PrefetchBase = PciData->u.type1.PrefetchBase;
/* Low bit specifies 64-bit address, top bits specify the base */
Is64Bit = (PrefetchBase & 0xF) == 1;
Base.LowPart = ((PrefetchBase & 0xFFF0) << 16);
/* Is it 64-bit? */
if (Is64Bit)
{
/* Read the upper 32-bits from the other register */
Base.HighPart = PciData->u.type1.PrefetchBaseUpper32;
}
/* Return the base */
return Base;
}
PHYSICAL_ADDRESS
NTAPI
PciBridgePrefetchMemoryLimit(IN PPCI_COMMON_HEADER PciData)
{
BOOLEAN Is64Bit;
LARGE_INTEGER Limit;
USHORT PrefetchLimit;
ASSERT(PCI_CONFIGURATION_TYPE(PciData) == PCI_BRIDGE_TYPE);
/* Get the base */
PrefetchLimit = PciData->u.type1.PrefetchLimit;
/* Low bit specifies 64-bit address, top bits specify the limit */
Is64Bit = (PrefetchLimit & 0xF) == 1;
Limit.LowPart = (PrefetchLimit << 16) | 0xFFFFF;
/* Is it 64-bit? */
if (Is64Bit)
{
/* Read the upper 32-bits from the other register */
Limit.HighPart = PciData->u.type1.PrefetchLimitUpper32;
}
/* Return the limit */
return Limit;
}
ULONG
NTAPI
PciBridgeMemoryWorstCaseAlignment(IN ULONG Length)
{
ULONG Alignment;
ASSERT(Length != 0);
/* Start with highest alignment (2^31) */
Alignment = 0x80000000;
/* Keep dividing until we reach the correct power of two */
while (!(Length & Alignment)) Alignment >>= 1;
/* Return the alignment */
return Alignment;
}
BOOLEAN
NTAPI
PciBridgeIsPositiveDecode(IN PPCI_PDO_EXTENSION PdoExtension)
{
/* Undocumented ACPI Method PDEC to get positive decode settings */
return PciIsSlotPresentInParentMethod(PdoExtension, 'CEDP');
}
BOOLEAN
NTAPI
PciBridgeIsSubtractiveDecode(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
PPCI_COMMON_HEADER Current, PciData;
PPCI_PDO_EXTENSION PdoExtension;
/* Get pointers from context */
Current = Context->Current;
PciData = Context->PciData;
PdoExtension = Context->PdoExtension;
/* Only valid for PCI-to-PCI bridges */
ASSERT((Current->BaseClass == PCI_CLASS_BRIDGE_DEV) &&
(Current->SubClass == PCI_SUBCLASS_BR_PCI_TO_PCI));
/* Check for hacks first, then check the ProgIf of the bridge */
if (!(PdoExtension->HackFlags & PCI_HACK_SUBTRACTIVE_DECODE) &&
(Current->ProgIf != 1) &&
((PciData->u.type1.IOLimit & 0xF0) == 0xF0))
{
/* A subtractive decode bridge would have a ProgIf 1, and no I/O limit */
DPRINT("Subtractive decode does not seem to be enabled\n");
return FALSE;
}
/*
* Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
* i820, i840, i845 Chipsets) that have subtractive decode broken.
*/
if (((PdoExtension->VendorId == 0x8086) &&
((PdoExtension->DeviceId == 0x2418) ||
(PdoExtension->DeviceId == 0x2428) ||
(PdoExtension->DeviceId == 0x244E) ||
(PdoExtension->DeviceId == 0x2448))) ||
(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
{
/* Check if the ACPI BIOS says positive decode should be enabled */
if (PciBridgeIsPositiveDecode(PdoExtension))
{
/* Obey ACPI */
DPRINT1("Putting bridge in positive decode because of PDEC\n");
return FALSE;
}
}
/* If we found subtractive decode, we'll need a resource update later */
DPRINT1("PCI : Subtractive decode on 0x%x\n", Current->u.type1.SecondaryBus);
PdoExtension->UpdateHardware = TRUE;
return TRUE;
}
VOID
NTAPI
PPBridge_SaveCurrentSettings(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
UNIMPLEMENTED;
while (TRUE);
NTSTATUS Status;
PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
PIO_RESOURCE_DESCRIPTOR IoDescriptor;
PPCI_FUNCTION_RESOURCES Resources;
PCI_COMMON_HEADER BiosData;
PPCI_COMMON_HEADER Current;
PPCI_COMMON_CONFIG SavedConfig;
ULONG i, Bar, BarMask;
PULONG BarArray;
PHYSICAL_ADDRESS Limit, Base, Length;
BOOLEAN HaveIoLimit, CheckAlignment;
PPCI_PDO_EXTENSION PdoExtension;
/* Get the pointers from the extension */
PdoExtension = Context->PdoExtension;
Resources = PdoExtension->Resources;
Current = Context->Current;
/* Check if decodes are disabled */
if (!(Context->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)))
{
/* Well, we're going to need them from somewhere, use the registry data */
Status = PciGetBiosConfig(PdoExtension, &BiosData);
if (NT_SUCCESS(Status)) Current = &BiosData;
}
/* Scan all current and limit descriptors for each BAR needed */
BarArray = Current->u.type1.BaseAddresses;
for (i = 0; i < 6; i++)
{
/* Get the current resource descriptor, and the limit requirement */
CmDescriptor = &Resources->Current[i];
IoDescriptor = &Resources->Limit[i];
/* Copy descriptor data, skipping null descriptors */
CmDescriptor->Type = IoDescriptor->Type;
if (CmDescriptor->Type == CmResourceTypeNull) continue;
CmDescriptor->Flags = IoDescriptor->Flags;
CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition;
/* Initialize the high-parts to zero, since most stuff is 32-bit only */
Base.QuadPart = Limit.QuadPart = Length.QuadPart = 0;
/* Check if we're handling PCI BARs, or the ROM BAR */
if ((i < PCI_TYPE1_ADDRESSES) || (i == 5))
{
/* Is this the ROM BAR? */
if (i == 5)
{
/* Read the correct bar, with the appropriate mask */
Bar = Current->u.type1.ROMBaseAddress;
BarMask = PCI_ADDRESS_ROM_ADDRESS_MASK;
/* Decode the base address, and write down the length */
Base.LowPart = Bar & BarMask;
DPRINT1("ROM BAR Base: %lx\n", Base.LowPart);
CmDescriptor->u.Memory.Length = IoDescriptor->u.Memory.Length;
}
else
{
/* Otherwise, get the BAR from the array */
Bar = BarArray[i];
/* Is this an I/O BAR? */
if (Bar & PCI_ADDRESS_IO_SPACE)
{
/* Set the correct mask */
ASSERT(CmDescriptor->Type == CmResourceTypePort);
BarMask = PCI_ADDRESS_IO_ADDRESS_MASK;
}
else
{
/* This is a memory BAR, set the correct base */
ASSERT(CmDescriptor->Type == CmResourceTypeMemory);
BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
/* IS this a 64-bit BAR? */
if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
{
/* Read the next 32-bits as well, ie, the next BAR */
Base.HighPart = BarArray[i + 1];
}
}
/* Decode the base address, and write down the length */
Base.LowPart = Bar & BarMask;
DPRINT1("BAR Base: %lx\n", Base.LowPart);
CmDescriptor->u.Generic.Length = IoDescriptor->u.Generic.Length;
}
}
else
{
/* Reset loop conditions */
HaveIoLimit = FALSE;
CheckAlignment = FALSE;
/* Check which descriptor is being parsed */
if (i == 2)
{
/* I/O Port Requirements */
Base.LowPart = PciBridgeIoBase(Current);
Limit.LowPart = PciBridgeIoLimit(Current);
DPRINT1("Bridge I/O Base and Limit: %lx %lx\n",
Base.LowPart, Limit.LowPart);
/* Do we have any I/O Port data? */
if (!(Base.LowPart) && (Current->u.type1.IOLimit))
{
/* There's a limit */
HaveIoLimit = TRUE;
}
}
else if (i == 3)
{
/* Memory requirements */
Base.LowPart = PciBridgeMemoryBase(Current);
Limit.LowPart = PciBridgeMemoryLimit(Current);
/* These should always be there, so check their alignment */
DPRINT1("Bridge MEM Base and Limit: %lx %lx\n",
Base.LowPart, Limit.LowPart);
CheckAlignment = TRUE;
}
else if (i == 4)
{
/* This should only be present for prefetch memory */
ASSERT(CmDescriptor->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE);
Base = PciBridgePrefetchMemoryBase(Current);
Limit = PciBridgePrefetchMemoryLimit(Current);
/* If it's there, check the alignment */
DPRINT1("Bridge Prefetch MEM Base and Limit: %I64x %I64x\n", Base, Limit);
CheckAlignment = TRUE;
}
/* Check for invalid base address */
if (Base.QuadPart >= Limit.QuadPart)
{
/* Assume the descriptor is bogus */
CmDescriptor->Type = CmResourceTypeNull;
IoDescriptor->Type = CmResourceTypeNull;
continue;
}
/* Check if there's no memory, and no I/O port either */
if (!(Base.LowPart) && !(HaveIoLimit))
{
/* This seems like a bogus requirement, ignore it */
CmDescriptor->Type = CmResourceTypeNull;
continue;
}
/* Set the length to be the limit - the base; should always be 32-bit */
Length.QuadPart = Limit.LowPart - Base.LowPart + 1;
ASSERT(Length.HighPart == 0);
CmDescriptor->u.Generic.Length = Length.LowPart;
/* Check if alignment should be set */
if (CheckAlignment)
{
/* Compute the required alignment for this length */
ASSERT(CmDescriptor->u.Memory.Length > 0);
IoDescriptor->u.Memory.Alignment =
PciBridgeMemoryWorstCaseAlignment(CmDescriptor->u.Memory.Length);
}
}
/* Now set the base address */
CmDescriptor->u.Generic.Start.LowPart = Base.LowPart;
}
/* Save PCI settings into the PDO extension for easy access later */
PdoExtension->Dependent.type1.PrimaryBus = Current->u.type1.PrimaryBus;
PdoExtension->Dependent.type1.SecondaryBus = Current->u.type1.SecondaryBus;
PdoExtension->Dependent.type1.SubordinateBus = Current->u.type1.SubordinateBus;
/* Check for subtractive decode bridges */
if (PdoExtension->Dependent.type1.SubtractiveDecode)
{
/* Check if legacy VGA decodes are enabled */
DPRINT1("Subtractive decode bridge\n");
if (Current->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA)
{
/* Save this setting for later */
DPRINT1("VGA Bridge\n");
PdoExtension->Dependent.type1.VgaBitSet = TRUE;
}
/* Legacy ISA decoding is not compatible with subtractive decode */
ASSERT(PdoExtension->Dependent.type1.IsaBitSet == FALSE);
}
else
{
/* Check if legacy VGA decodes are enabled */
if (Current->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA)
{
/* Save this setting for later */
DPRINT1("VGA Bridge\n");
PdoExtension->Dependent.type1.VgaBitSet = TRUE;
/* And on positive decode, we'll also need extra resources locked */
PdoExtension->AdditionalResourceCount = 4;
}
/* Check if legacy ISA decoding is enabled */
if (Current->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_ISA)
{
/* Save this setting for later */
DPRINT1("ISA Bridge\n");
PdoExtension->Dependent.type1.IsaBitSet = TRUE;
}
}
/*
* Check for Intel ICH PCI-to-PCI (i82801) bridges (used on the i810,
* i820, i840, i845 Chipsets) that have subtractive decode broken.
*/
if (((PdoExtension->VendorId == 0x8086) &&
((PdoExtension->DeviceId == 0x2418) ||
(PdoExtension->DeviceId == 0x2428) ||
(PdoExtension->DeviceId == 0x244E) ||
(PdoExtension->DeviceId == 0x2448))) ||
(PdoExtension->HackFlags & PCI_HACK_BROKEN_SUBTRACTIVE_DECODE))
{
/* Check if subtractive decode is actually enabled */
if (PdoExtension->Dependent.type1.SubtractiveDecode)
{
/* We're going to need a copy of the configuration for later use */
DPRINT1("apply config save hack to ICH subtractive decode\n");
SavedConfig = ExAllocatePoolWithTag(0, PCI_COMMON_HDR_LENGTH, 'PciP');
PdoExtension->ParentFdoExtension->PreservedConfig = SavedConfig;
if (SavedConfig) RtlCopyMemory(SavedConfig, Current, PCI_COMMON_HDR_LENGTH);
}
}
}
VOID
NTAPI
PPBridge_SaveLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
UNIMPLEMENTED;
while (TRUE);
PIO_RESOURCE_DESCRIPTOR Limit;
PULONG BarArray;
PHYSICAL_ADDRESS MemoryLimit;
ULONG i;
PPCI_COMMON_HEADER Working;
PPCI_PDO_EXTENSION PdoExtension;
/* Get the pointers from the context */
Working = Context->PciData;
PdoExtension = Context->PdoExtension;
/* Scan the BARs into the limit descriptors */
BarArray = Working->u.type1.BaseAddresses;
Limit = PdoExtension->Resources->Limit;
/* First of all, loop all the BARs */
for (i = 0; i < PCI_TYPE1_ADDRESSES; i++)
{
/* Create a descriptor for their limits */
if (PciCreateIoDescriptorFromBarLimit(&Limit[i], &BarArray[i], FALSE))
{
/* This was a 64-bit descriptor, make sure there's space */
ASSERT((i + 1) < PCI_TYPE1_ADDRESSES);
/* Skip the next descriptor since this one is double sized */
i++;
(&Limit[i])->Type == CmResourceTypeNull;
}
}
/* Check if this is a subtractive decode bridge */
if (PciBridgeIsSubtractiveDecode(Context))
{
/* This bridge is subtractive */
PdoExtension->Dependent.type1.SubtractiveDecode = TRUE;
/* Subtractive bridges cannot use legacy ISA or VGA functionality */
PdoExtension->Dependent.type1.IsaBitSet = FALSE;
PdoExtension->Dependent.type1.VgaBitSet = FALSE;
}
/* For normal decode bridges, we'll need to find the bridge limits too */
if (!PdoExtension->Dependent.type1.SubtractiveDecode)
{
/* Loop the descriptors that are left, to store the bridge limits */
for (i = PCI_TYPE1_ADDRESSES; i < 5; i++)
{
/* No 64-bit memory addresses, and set the address to 0 to begin */
MemoryLimit.HighPart = 0;
(&Limit[i])->u.Port.MinimumAddress.QuadPart = 0;
/* Are we getting the I/O limit? */
if (i == 2)
{
/* There should be one, get it */
ASSERT(Working->u.type1.IOLimit != 0);
ASSERT((Working->u.type1.IOLimit & 0x0E) == 0);
MemoryLimit.LowPart = PciBridgeIoLimit(Working);
/* Build a descriptor for this limit */
(&Limit[i])->Type = CmResourceTypePort;
(&Limit[i])->Flags = CM_RESOURCE_PORT_WINDOW_DECODE |
CM_RESOURCE_PORT_POSITIVE_DECODE;
(&Limit[i])->u.Port.Alignment = 0x1000;
(&Limit[i])->u.Port.MinimumAddress.QuadPart = 0;
(&Limit[i])->u.Port.MaximumAddress = MemoryLimit;
(&Limit[i])->u.Port.Length = 0;
}
else if (i == 3)
{
/* There should be a valid memory limit, get it */
ASSERT((Working->u.type1.MemoryLimit & 0xF) == 0);
MemoryLimit.LowPart = PciBridgeMemoryLimit(Working);
/* Build the descriptor for it */
(&Limit[i])->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
(&Limit[i])->Type = CmResourceTypeMemory;
(&Limit[i])->u.Memory.Alignment = 0x100000;
(&Limit[i])->u.Memory.MinimumAddress.QuadPart = 0;
(&Limit[i])->u.Memory.MaximumAddress = MemoryLimit;
(&Limit[i])->u.Memory.Length = 0;
}
else if (Working->u.type1.PrefetchLimit)
{
/* Get the prefetch memory limit, if there is one */
MemoryLimit = PciBridgePrefetchMemoryLimit(Working);
/* Write out the descriptor for it */
(&Limit[i])->Flags = CM_RESOURCE_MEMORY_PREFETCHABLE;
(&Limit[i])->Type = CmResourceTypeMemory;
(&Limit[i])->u.Memory.Alignment = 0x100000;
(&Limit[i])->u.Memory.MinimumAddress.QuadPart = 0;
(&Limit[i])->u.Memory.MaximumAddress = MemoryLimit;
(&Limit[i])->u.Memory.Length = 0;
}
else
{
/* Blank descriptor */
(&Limit[i])->Type = CmResourceTypeNull;
}
}
}
/* Does the ROM have its own BAR? */
if (Working->u.type1.ROMBaseAddress & PCI_ROMADDRESS_ENABLED)
{
/* Build a limit for it as well */
PciCreateIoDescriptorFromBarLimit(&Limit[i],
&Working->u.type1.ROMBaseAddress,
TRUE);
}
}
VOID
NTAPI
PPBridge_MassageHeaderForLimitsDetermination(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
UNIMPLEMENTED;
while (TRUE);
PPCI_COMMON_HEADER PciData, Current;
/* Get pointers from context */
PciData = Context->PciData;
Current = Context->Current;
/*
* Write FFh everywhere so that the PCI bridge ignores what it can't handle.
* Based on the bits that were ignored (still 0), this is how we can tell
* what the limit is.
*/
RtlFillMemory(PciData->u.type1.BaseAddresses,
FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.CapabilitiesPtr) -
FIELD_OFFSET(PCI_COMMON_HEADER, u.type1.BaseAddresses),
0xFF);
/* Copy the saved settings from the current context into the PCI header */
PciData->u.type1.PrimaryBus = Current->u.type1.PrimaryBus;
PciData->u.type1.SecondaryBus = Current->u.type1.SecondaryBus;
PciData->u.type1.SubordinateBus = Current->u.type1.SubordinateBus;
PciData->u.type1.SecondaryLatency = Current->u.type1.SecondaryLatency;
/* No I/O limit or base. The bottom base bit specifies that FIXME */
PciData->u.type1.IOBaseUpper16 = 0xFFFE;
PciData->u.type1.IOLimitUpper16 = 0xFFFF;
/* Save secondary status before it gets cleared */
Context->SecondaryStatus = Current->u.type1.SecondaryStatus;
/* Clear secondary status */
Current->u.type1.SecondaryStatus = 0;
PciData->u.type1.SecondaryStatus = 0;
}
VOID
NTAPI
PPBridge_RestoreCurrent(IN PPCI_CONFIGURATOR_CONTEXT Context)
{
UNIMPLEMENTED;
while (TRUE);
/* Copy back the secondary status register */
Context->Current->u.type1.SecondaryStatus = Context->SecondaryStatus;
}
VOID
@ -54,8 +630,40 @@ PPBridge_GetAdditionalResourceDescriptors(IN PPCI_CONFIGURATOR_CONTEXT Context,
IN PPCI_COMMON_HEADER PciData,
IN PIO_RESOURCE_DESCRIPTOR IoDescriptor)
{
UNIMPLEMENTED;
while (TRUE);
/* Does this bridge have VGA decodes on it? */
if (PciData->u.type1.BridgeControl & PCI_ENABLE_BRIDGE_VGA)
{
/* Build a private descriptor with 3 entries */
IoDescriptor->Type = CmResourceTypeDevicePrivate;
IoDescriptor->u.DevicePrivate.Data[0] = 3;
IoDescriptor->u.DevicePrivate.Data[1] = 3;
/* First, the VGA range at 0xA0000 */
IoDescriptor[1].Type = CmResourceTypeMemory;
IoDescriptor[1].Flags = CM_RESOURCE_MEMORY_READ_WRITE;
IoDescriptor[1].u.Port.Length = 0x20000;
IoDescriptor[1].u.Port.Alignment = 1;
IoDescriptor[1].u.Port.MinimumAddress.QuadPart = 0xA0000;
IoDescriptor[1].u.Port.MaximumAddress.QuadPart = 0xBFFFF;
/* Then, the VGA registers at 0x3B0 */
IoDescriptor[2].Type = CmResourceTypePort;
IoDescriptor[2].Flags = CM_RESOURCE_PORT_POSITIVE_DECODE |
CM_RESOURCE_PORT_10_BIT_DECODE;
IoDescriptor[2].u.Port.Length = 12;
IoDescriptor[2].u.Port.Alignment = 1;
IoDescriptor[2].u.Port.MinimumAddress.QuadPart = 0x3B0;
IoDescriptor[2].u.Port.MaximumAddress.QuadPart = 0x3BB;
/* And finally the VGA registers at 0x3C0 */
IoDescriptor[3].Type = CmResourceTypePort;
IoDescriptor[3].Flags = CM_RESOURCE_PORT_POSITIVE_DECODE |
CM_RESOURCE_PORT_10_BIT_DECODE;
IoDescriptor[3].u.Port.Length = 32;
IoDescriptor[3].u.Port.Alignment = 1;
IoDescriptor[3].u.Port.MinimumAddress.QuadPart = 0x3C0;
IoDescriptor[3].u.Port.MaximumAddress.QuadPart = 0x3DF;
}
}
VOID

View file

@ -1130,6 +1130,115 @@ PciIsSlotPresentInParentMethod(IN PPCI_PDO_EXTENSION PdoExtension,
return FoundSlot;
}
ULONG
NTAPI
PciGetLengthFromBar(IN ULONG Bar)
{
ULONG Length;
/* I/O addresses vs. memory addresses start differently due to alignment */
Length = 1 << ((Bar & PCI_ADDRESS_IO_SPACE) ? 2 : 4);
/* Keep going until a set bit */
while (!(Length & Bar) && (Length)) Length <<= 1;
/* Return the length (might be 0 on 64-bit because it's the low-word) */
if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) != PCI_TYPE_64BIT) ASSERT(Length);
return Length;
}
BOOLEAN
NTAPI
PciCreateIoDescriptorFromBarLimit(PIO_RESOURCE_DESCRIPTOR ResourceDescriptor,
IN PULONG BarArray,
IN BOOLEAN Rom)
{
ULONG CurrentBar, BarLength, BarMask;
BOOLEAN Is64BitBar = FALSE;
/* Check if the BAR is nor I/O nor memory */
CurrentBar = BarArray[0];
if (!(CurrentBar & ~PCI_ADDRESS_IO_SPACE))
{
/* Fail this descriptor */
ResourceDescriptor->Type = CmResourceTypeNull;
return FALSE;
}
/* Set default flag and clear high words */
ResourceDescriptor->Flags = 0;
ResourceDescriptor->u.Generic.MaximumAddress.HighPart = 0;
ResourceDescriptor->u.Generic.MinimumAddress.LowPart = 0;
ResourceDescriptor->u.Generic.MinimumAddress.HighPart = 0;
/* Check for ROM Address */
if (Rom)
{
/* Clean up the BAR to get just the address */
CurrentBar &= PCI_ADDRESS_ROM_ADDRESS_MASK;
if (!CurrentBar)
{
/* Invalid ar, fail this descriptor */
ResourceDescriptor->Type = CmResourceTypeNull;
return FALSE;
}
/* ROM Addresses are always read only */
ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
}
/* Compute the length, assume it's the alignment for now */
BarLength = PciGetLengthFromBar(CurrentBar);
ResourceDescriptor->u.Generic.Length = BarLength;
ResourceDescriptor->u.Generic.Alignment = BarLength;
/* Check what kind of BAR this is */
if (CurrentBar & PCI_ADDRESS_IO_SPACE)
{
/* Use correct mask to decode the address */
BarMask = PCI_ADDRESS_IO_ADDRESS_MASK;
/* Set this as an I/O Port descriptor */
ResourceDescriptor->Type = CmResourceTypePort;
ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
}
else
{
/* Use correct mask to decode the address */
BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK;
/* Set this as a memory descriptor */
ResourceDescriptor->Type = CmResourceTypeMemory;
/* Check if it's 64-bit or 20-bit decode */
if ((CurrentBar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)
{
/* The next BAR has the high word, read it */
ResourceDescriptor->u.Port.MaximumAddress.HighPart = BarArray[1];
Is64BitBar = TRUE;
}
else if ((CurrentBar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT)
{
/* Use the correct mask to decode the address */
BarMask = ~0xFFF0000F;
}
/* Check if the BAR is listed as prefetchable memory */
if (CurrentBar & PCI_ADDRESS_MEMORY_PREFETCHABLE)
{
/* Mark the descriptor in the same way */
ResourceDescriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
}
}
/* Now write down the maximum address based on the base + length */
ResourceDescriptor->u.Port.MaximumAddress.QuadPart = (CurrentBar & BarMask) +
BarLength - 1;
/* Return if this is a 64-bit BAR, so the loop code knows to skip the next one */
return Is64BitBar;
}
VOID
NTAPI
PciDecodeEnable(IN PPCI_PDO_EXTENSION PdoExtension,