📄 pcicfg.c
字号:
ULONG BaseAddress;
ULONG Size;
ULONG Type;
DWORD Reg;
BOOL Placed = FALSE;
BOOL SizeFound;
DWORD IoIndex = 0;
DWORD MemIndex = 0;
DWORD Bus = pInfo->Bus;
DWORD Device = pInfo->Device;
DWORD Function = pInfo->Function;
PPCI_COMMON_CONFIG pCfg = pInfo->Cfg;
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCICfgCheckBARs+(Bus %d, Device %d, Function %d)\r\n",
Bus, Device, Function));
// Check to see if device/function already enabled
if (pCfg->Command & (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE)) {
// Either Memory or I/O access enabled
Placed = TRUE;
#ifdef DEBUG
if (!pInfo->Matched) {
DEBUGMSG(ZONE_WARNING, (L"PCIBUS!PCICfgCheckBARs: WARNING: No matching registry key was found for placed device %d/%d/%d.\r\n",
Bus, Device, Function));
DEBUGMSG(ZONE_WARNING, (L"PCIBUS!PCICfgCheckBARs: Problems can result if the device is being used while configuring PCIbus.\r\n"));
}
#endif
}
// Determine number of BARs to examine from header type
switch (pCfg->HeaderType & ~PCI_MULTIFUNCTION) {
case PCI_DEVICE_TYPE:
NumberOfRegs = PCI_TYPE0_ADDRESSES;
break;
case PCI_BRIDGE_TYPE:
NumberOfRegs = PCI_TYPE1_ADDRESSES;
break;
case PCI_CARDBUS_TYPE:
NumberOfRegs = PCI_TYPE2_ADDRESSES;
break;
default:
return FALSE;
}
for (i = 0, Offset = 0x10; i < NumberOfRegs; i++, Offset += 4) {
// Get base address register value
Reg = pCfg->u.type0.BaseAddresses[i];
Type = Reg & PCI_ADDRESS_IO_SPACE;
if (Placed && pInfo->Matched && (pInfo->IoLen.Num + pInfo->MemLen.Num) != 0) {
// Device already placed and has matching registry entry
if (Type) {
// I/O space
Size = pInfo->IoLen.Reg[IoIndex++];
Reg &= PCI_ADDRESS_IO_ADDRESS_MASK;
SizeFound = (IoIndex <= pInfo->IoLen.Num);
} else {
// Memory space
Size = pInfo->MemLen.Reg[MemIndex++];
Reg &= PCI_ADDRESS_MEMORY_ADDRESS_MASK;
SizeFound = (MemIndex <= pInfo->MemLen.Num);
}
} else {
// Device not placed or is placed and has no matching registry entry => Probe hardware for size
PCIConfig_Write(Bus,Device,Function,Offset,0xFFFFFFFF);
BaseAddress = PCIConfig_Read(Bus,Device,Function,Offset);
PCIConfig_Write(Bus, Device, Function, Offset, Reg);
if (Type) {
// IO space
// Re-adjust BaseAddress if upper 16-bits are 0 (allowable in PCI 2.2 spec)
if (((BaseAddress & PCI_ADDRESS_IO_ADDRESS_MASK) != 0) && ((BaseAddress & 0xFFFF0000) == 0)) {
BaseAddress |= 0xFFFF0000;
}
Size = ~(BaseAddress & PCI_ADDRESS_IO_ADDRESS_MASK);
Reg &= PCI_ADDRESS_IO_ADDRESS_MASK;
} else {
// Memory space
if ((Reg & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT) {
// PCI 2.2 spec no longer supports this type of memory addressing
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgCheckBARs: 20-bit addressing not supported\r\n"));
return FALSE;
}
// Re-adjust BaseAddress if upper 16-bits are 0 (allowed by PCI 2.2 spec)
if (((BaseAddress & PCI_ADDRESS_MEMORY_ADDRESS_MASK) != 0) && ((BaseAddress & 0xFFFF0000) == 0)) {
BaseAddress |= 0xFFFF0000;
}
Size = ~(BaseAddress & PCI_ADDRESS_MEMORY_ADDRESS_MASK);
Reg &= PCI_ADDRESS_MEMORY_ADDRESS_MASK;
}
// Check that the register has a valid format; it should have consecutive high 1's and consecutive low 0's
SizeFound = (BaseAddress != 0) && (BaseAddress != 0xFFFFFFFF) && (((Size + 1) & Size) == 0);
Size +=1;
}
if (SizeFound) {
PPCI_RSRC Rsrc = PCIRsrc_New(Bus, Device, Function, Offset, Reg, Size, FALSE, 0, Placed, NULL);
if (!Rsrc) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgCheckBARs: Failed local alloc of Rsrc\r\n"));
return FALSE;
}
if (Type == PCI_ADDRESS_IO_SPACE) {
*pIoSize += Size;
PCIRsrc_Add(g_IoHead, Rsrc);
} else {
*pMemSize += Size;
PCIRsrc_Add(g_MemHead, Rsrc);
}
DEBUGMSG(ZONE_INIT, (L"PCIBUS!PCICfgCheckBars: BAR(%d/%d/%d): Offset 0x%x, Type %s, Size 0x%X\r\n",
Bus, Device, Function, Offset, (Type == PCI_ADDRESS_IO_SPACE) ? TEXT("I/O") : TEXT("Memory"), Size));
} else {
// Some devices have invalid BARs before valid ones (allowed by PCI 2.2 spec). Skip invalid BARs.
continue;
}
// check for 64 bit device (memory only)
if ((Type == PCI_ADDRESS_MEMORY_SPACE) && ((Reg & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)) {
// 64 bit device - BAR is twice as wide - zero out high part
Offset += 4;
i++;
PCIConfig_Write(Bus, Device, Function, Offset, 0x0);
}
}
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCICfgCheckBars-\r\n", Bus, Device, Function));
return TRUE;
}
//
// For each I/O resource, allocate I/O space on PCIbus and assign address to BAR
//
static BOOL
PCICfgAllocateIoSpace(
DWORD Bus,
DWORD Base,
DWORD Size
)
{
PPCI_RSRC Rsrc, BusHead;
ULONG IoBase;
DWORD Reg;
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCICfgAllocateIoSpace+(Bus %d, Base 0x%X, Size 0x%X)\r\n", Bus, Base, Size));
// Create bus head node with available address range
if (!(BusHead = PCIRsrc_New(Bus, 0, 0, 0, Base, Size, TRUE, 0, TRUE, NULL))) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgAllocateIoSpace: Failed local alloc of BusHead\r\n"));
return FALSE;
}
while (Rsrc = PCIRsrc_GetNext(g_IoHead, Bus)) {
// Place resource
if (!PCIRsrc_Place(BusHead, Rsrc)) {
DEBUGMSG(ZONE_ERROR,
(L"PCIBUS!PCICfgAllocIoSpace: Failed to place %s resource: Bus %d, Device %d, Function %d\r\n",
(Rsrc->Bridge) ? L"Bridge" : L"Device", Rsrc->Bus, Rsrc->Device, Rsrc->Function));
continue;
}
DEBUGMSG(ZONE_INIT, (L"PCIBUS!PciIinitAllocIoSpace (%s): Bus %d, Device %d, Function %d, Offset 0x%X, IoBase 0x%X, IoSize 0x%X\r\n",
(Rsrc->Bridge) ? L"PCI-PCI Bridge" : L"Device", Rsrc->Bus, Rsrc->Device, Rsrc->Function, Rsrc->Offset, Rsrc->Base, Rsrc->Size));
if (Rsrc->Bridge) {
// PCI-PCI bridge
BOOL Use32bitIo;
// Allocate resources for bridge's secondary bus
PCICfgAllocateIoSpace(Rsrc->SecBus, Rsrc->Base, Rsrc->Size);
// Write I/O base and limit registers
IoBase = PCIConfig_Read(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCIBRIDGE_IO);
// Check to see if the bridge is using 16-bit I/O or 32-bit I/O
Use32bitIo = ((IoBase & 0xF) == PCI_SECONDARY_IO32);
// Set bridge's base and limit address registers
((PBRIDGE_IO)(&IoBase))->IoLimit.Address = (BYTE)(((Rsrc->Base + Rsrc->Size - 1) & 0xF000) >> 12);
((PBRIDGE_IO)(&IoBase))->IoBase.Address = (BYTE)(((Rsrc->Base) & 0xF000) >> 12);
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCIBRIDGE_IO, IoBase);
// If 32-bit I/O, set the I/O limit & base upper address registers.
if (Use32bitIo) {
DEBUGMSG(ZONE_INIT, (L"PCIBUS!PCI-PCI bridge %d/%d/%d supports 32-bit I/O\r\n", Rsrc->Bus, Rsrc->Device, Rsrc->Function));
DEBUGMSG(1, (L"IoBase = 0x%X, IoLimit = 0x%X\r\n", Rsrc->Base, Rsrc->Base + Rsrc->Size - 1));
IoBase = (Rsrc->Base + Rsrc->Size - 1) & 0xFFFF0000;
IoBase |= (Rsrc->Base) >> 16;
DEBUGMSG(1, (L"IoBase reg = 0x%X, offset 0x%X\r\n", IoBase, PCIBRIDGE_IO_UPPER16));
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCIBRIDGE_IO_UPPER16, IoBase);
}
// Enable device's I/O space (and bus mastering capability)
Reg = PCIConfig_Read(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCI_CONFIG_COMMAND_STATUS);
if ((Reg & (PCI_ENABLE_BUS_MASTER | PCI_ENABLE_IO_SPACE)) != ( PCI_ENABLE_BUS_MASTER | PCI_ENABLE_IO_SPACE)) {
Reg &= 0x3FF;
Reg |= PCI_ENABLE_BUS_MASTER | PCI_ENABLE_IO_SPACE;
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCI_CONFIG_COMMAND_STATUS, Reg);
}
} else if (!Rsrc->Placed) {
// Device
if (Rsrc->ConfigInfo) {
// This resource needs to be set by the device's ConfigEntry routine (if supported)
DWORD Status = ((PFN_CONFIGENTRY)Rsrc->ConfigInfo->ConfigEntryFn)(PCIBUS_CONFIG_SET, NULL, Rsrc, NULL, NULL, NULL);
if (Status != ERROR_SUCCESS) {
if (Status == ERROR_NOT_SUPPORTED) {
// ConfigEntry point doesn't support this type of call, so do it here
// Set device's base address register
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, Rsrc->Offset, Rsrc->Base);
} else {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgAllocIoSpace: Failed ConfigEntry call\r\n"));
return FALSE;
}
}
} else {
// Set device's base address register
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, Rsrc->Offset, Rsrc->Base);
}
// Enable device's I/O space (and bus mastering capability)
Reg = PCIConfig_Read(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCI_CONFIG_COMMAND_STATUS);
if ((Reg & (PCI_ENABLE_BUS_MASTER | PCI_ENABLE_IO_SPACE )) != (PCI_ENABLE_BUS_MASTER | PCI_ENABLE_IO_SPACE)) {
Reg &= 0x3FF;
Reg |= PCI_ENABLE_BUS_MASTER | PCI_ENABLE_IO_SPACE;
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCI_CONFIG_COMMAND_STATUS, Reg);
}
}
}
PCIRsrc_DelList(BusHead);
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCICfgAllocateIoSpace-(Bus %d)\r\n", Bus));
return TRUE;
}
//
// For each memory resource, allocate memory space on PCIbus and assign address to BAR
//
static BOOL
PCICfgAllocateMemSpace(
DWORD Bus,
DWORD Base,
DWORD Size
)
{
PPCI_RSRC Rsrc, BusHead;
ULONG MemBase;
DWORD Reg;
DEBUGMSG(ZONE_FUNCTION, (L"PCIBUS!PCICfgAllocateMemSpace+(Bus %d, Base 0x%X, Size 0x%X)\r\n", Bus, Base, Size));
// Create bus head node with available address range
if (!(BusHead = PCIRsrc_New(Bus, 0, 0, 0, Base, Size, TRUE, 0, TRUE, NULL))) {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgAllocateIoSpace: Failed local alloc of BusHead\r\n"));
return FALSE;
}
while (Rsrc = PCIRsrc_GetNext(g_MemHead, Bus)) {
// Place resource
if (!PCIRsrc_Place(BusHead, Rsrc)) {
DEBUGMSG(ZONE_ERROR,
(L"PCIBUS!PCICfgAllocMemSpace: Failed to place %s resource: Bus %d, Device %d, Function %d\r\n",
(Rsrc->Bridge) ? L"Bridge" : L"Device", Rsrc->Bus, Rsrc->Device, Rsrc->Function));
continue;
}
DEBUGMSG(ZONE_INIT, (L"PCIBUS!PCICfgAllocMemSpace (%s): Bus %d, Device %d, Function %d, Offset 0x%X, MemBase 0x%X, MemSize 0x%X\r\n",
(Rsrc->Bridge) ? L"PCI-PCI Bridge" : L"Device", Rsrc->Bus, Rsrc->Device, Rsrc->Function, Rsrc->Offset, Rsrc->Base, Rsrc->Size));
if (Rsrc->Bridge) {
// Allocate resources for bridge's secondary bus
PCICfgAllocateMemSpace(Rsrc->SecBus, Rsrc->Base, Rsrc->Size);
// Set bridge's base and limit address registers
((PBRIDGE_MEM)(&MemBase))->MemoryLimit.Address = (WORD)(((Rsrc->Base + Rsrc->Size - 1) & 0xFFF00000) >> 20);
((PBRIDGE_MEM)(&MemBase))->MemoryBase.Address = (WORD)(((Rsrc->Base) & 0xFFF00000) >> 20);
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCIBRIDGE_MEMORY, MemBase);
// Enable device's memory space (and bus mastering capability)
Reg = PCIConfig_Read(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCI_CONFIG_COMMAND_STATUS);
if ((Reg & (PCI_ENABLE_BUS_MASTER | PCI_ENABLE_MEMORY_SPACE )) != (PCI_ENABLE_BUS_MASTER | PCI_ENABLE_MEMORY_SPACE)) {
Reg &= 0x3FF;
Reg |= PCI_ENABLE_BUS_MASTER | PCI_ENABLE_MEMORY_SPACE;
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCI_CONFIG_COMMAND_STATUS, Reg);
}
} else if (!Rsrc->Placed) {
if (Rsrc->ConfigInfo) {
// This resource needs to be set by the device's ConfigEntry routine (if supported)
DWORD Status = ((PFN_CONFIGENTRY)Rsrc->ConfigInfo->ConfigEntryFn)(PCIBUS_CONFIG_SET, NULL, Rsrc, NULL, NULL, NULL);
if (Status != ERROR_SUCCESS) {
if (Status == ERROR_NOT_SUPPORTED) {
// ConfigEntry point doesn't support this type of call, so do it here
// Set device's base address register
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, Rsrc->Offset, Rsrc->Base);
} else {
DEBUGMSG(ZONE_ERROR, (L"PCIBUS!PCICfgAllocMemSpace: Failed ConfigEntry call\r\n"));
return FALSE;
}
}
} else {
// Set device's base address register
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, Rsrc->Offset, Rsrc->Base);
}
// Enable device's memory space (and bus mastering capability)
Reg = PCIConfig_Read(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCI_CONFIG_COMMAND_STATUS);
if ((Reg & (PCI_ENABLE_BUS_MASTER | PCI_ENABLE_MEMORY_SPACE)) != (PCI_ENABLE_BUS_MASTER | PCI_ENABLE_MEMORY_SPACE)) {
Reg &= 0x3FF;
Reg |= PCI_ENABLE_BUS_MASTER | PCI_ENABLE_MEMORY_SPACE;
PCIConfig_Write(Rsrc->Bus, Rsrc->Device, Rsrc->Function, PCI_CONFIG_COMMAND_STATUS, Reg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -