ReactOS 0.4.17-dev-923-g4c9a150
ecam.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS PCI Bus Driver
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Basic ECAM Handling
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include <pci.h>
11
12#define NDEBUG
13#include <debug.h>
14
15/* GLOBALS ********************************************************************/
16
17#define PCI_ECAM_BUS_COUNT (PCI_MAX_BRIDGE_NUMBER + 1)
18#define PCI_ECAM_BUS_SIZE (PCI_MAX_DEVICES * PCI_MAX_FUNCTION * PCI_EXTENDED_CONFIG_LENGTH)
19
21
27
28/* FUNCTIONS ******************************************************************/
29
30/* Takes the first window, which is segment 0 since the HAL writes them in segment order */
31static
36{
39 ULONGLONG Start, End, Buses;
40 PAGED_CODE();
41
43 (Value->DataLength < sizeof(IO_RESOURCE_REQUIREMENTS_LIST)))
44 {
45 return FALSE;
46 }
47
48 Requirements = (PIO_RESOURCE_REQUIREMENTS_LIST)Value->Data;
49 if (!(Requirements->AlternativeLists) || !(Requirements->List[0].Count)) return FALSE;
50
51 Window = &Requirements->List[0].Descriptors[0];
52 if ((Window->Type != CmResourceTypeMemory) &&
54 {
55 return FALSE;
56 }
57
58 Start = (ULONGLONG)Window->u.Memory.MinimumAddress.QuadPart;
59 End = (ULONGLONG)Window->u.Memory.MaximumAddress.QuadPart;
60 if (End < Start) return FALSE;
61
62 Buses = (End - Start + 1) / PCI_ECAM_BUS_SIZE;
63 if (!(Buses) || (Buses > PCI_ECAM_BUS_COUNT)) return FALSE;
64
67 return TRUE;
68}
69
70/* The HAL publishes the MCFG windows here so the arbiters keep them reserved */
71static
75{
80 ULONG Size;
81 PAGED_CODE();
82
83 if (!PciOpenKey(L"\\Registry\\Machine\\System\\CurrentControlSet"
84 L"\\Control\\Arbiters\\ReservedResources",
85 NULL,
87 &KeyHandle,
88 &Status))
89 {
90 return Status;
91 }
92
93 RtlInitUnicodeString(&ValueName, L"MmConfigRange");
94 Status = ZwQueryValueKey(KeyHandle,
95 &ValueName,
97 NULL,
98 0,
99 &Size);
101 {
104 }
105
107 if (!Value)
108 {
111 }
112
113 Status = ZwQueryValueKey(KeyHandle,
114 &ValueName,
116 Value,
117 Size,
118 &Size);
120
122 {
124 }
125
127 return Status;
128}
129
130#if defined(_M_IX86) || defined(_M_AMD64)
131/*
132 * K8 northbridge functions on bus 0 are not decoded by the chipset ECAM window.
133 * This really should be a hardware quirk so I'm marking this as TODO:
134 * However I want to be able to boot until we got a solid system for this!
135 */
136static
138NTAPI
139PciEcamIsAmdK8(VOID)
140{
141 INT CpuInfo[4];
142
143 /* "AuthenticAMD" */
144 __cpuid(CpuInfo, 0);
145 if ((CpuInfo[1] != 0x68747541) ||
146 (CpuInfo[3] != 0x69746E65) ||
147 (CpuInfo[2] != 0x444D4163))
148 {
149 return FALSE;
150 }
151
152 /* Family 0Fh with no extended family */
153 __cpuid(CpuInfo, 1);
154 return ((CpuInfo[0] & 0x0FF00F00) == 0x00000F00);
155}
156#endif
157
158/* Mappings are kept for the life of the driver since config access can happen at any IRQL */
159static
160PUCHAR
161NTAPI
163 _In_ ULONG Bus)
164{
166 PAGED_CODE();
167
168 if (Bus >= PciEcamWindowBuses) return NULL;
169 if (PciEcamBusView[Bus]) return PciEcamBusView[Bus];
170
173 if (!PciEcamBusView[Bus])
174 {
175 DPRINT1("PCI: Unable to map ECAM for bus 0x%lx\n", Bus);
176 }
177
178 return PciEcamBusView[Bus];
179}
180
181static
182VOID
183NTAPI
185{
186 ULONG Bus;
187 PAGED_CODE();
188
189 for (Bus = 0; Bus < PciEcamWindowBuses; Bus++)
190 {
191 if (!PciEcamBusView[Bus]) continue;
192
194 PciEcamBusView[Bus] = NULL;
195 }
196
198}
199
200static
201PUCHAR
202NTAPI
204 _In_ ULONG Bus,
206{
207 ULONG Index;
208
209 if ((Bus >= PciEcamWindowBuses) || !(PciEcamBusView[Bus])) return NULL;
210
212 (Bus == 0) &&
213 (Slot.u.bits.DeviceNumber >= 0x18))
214 {
215 return NULL;
216 }
217
218 Index = (Slot.u.bits.DeviceNumber * PCI_MAX_FUNCTION) + Slot.u.bits.FunctionNumber;
220}
221
222/* Picks the same access widths as the HAL does for the legacy mechanism */
223static
224VOID
225NTAPI
232{
234 ULONG Width;
235
236 while (Length)
237 {
239
240 if ((Offset & 1) || ((Length & 3) == 1))
241 {
242 Width = sizeof(UCHAR);
243 if (Read)
244 {
246 }
247 else
248 {
250 }
251 }
252 else if (!(Offset & 3) && !(Length & 3))
253 {
254 Width = sizeof(ULONG);
255 if (Read)
256 {
258 }
259 else
260 {
262 }
263 }
264 else
265 {
266 Width = sizeof(USHORT);
267 if (Read)
268 {
270 }
271 else
272 {
274 }
275 }
276
277 Buffer += Width;
278 Offset += Width;
279 Length -= Width;
280 }
281}
282
283/* The window is assumed to start at bus 0, so compare IDs through both mechanisms to prove it */
284static
286NTAPI
289{
290 PCI_SLOT_NUMBER Slot;
292 ULONG Device, LegacyIds, EcamIds, Matched;
293 PAGED_CODE();
294
295 Slot.u.AsULONG = 0;
296 Matched = 0;
297
298 for (Device = 0; Device < PCI_MAX_DEVICES; Device++)
299 {
300 Slot.u.bits.DeviceNumber = Device;
301
302 Function = PciEcamFunctionBase(FdoExtension->BaseBus, Slot);
303 if (!Function) continue;
304
305 LegacyIds = MAXULONG;
306 PciReadSlotConfig(FdoExtension, Slot, &LegacyIds, 0, sizeof(ULONG));
307 if (((USHORT)LegacyIds == PCI_INVALID_VENDORID) || !((USHORT)LegacyIds)) continue;
308
310 if (EcamIds != LegacyIds)
311 {
312 DPRINT1("PCI: ECAM mismatch at %02lx:%02lx.0, read %08lx expected %08lx\n",
313 FdoExtension->BaseBus,
314 Device,
315 EcamIds,
316 LegacyIds);
318 }
319
320 Matched++;
321 }
322
323 return Matched ? STATUS_SUCCESS : STATUS_NO_SUCH_DEVICE;
324}
325
334VOID
335NTAPI
338{
340 PAGED_CODE();
341
343 {
345
347 if (!NT_SUCCESS(Status))
348 {
349 DPRINT1("PCI: No ECAM window available (0x%lx)\n", Status);
350 return;
351 }
352
353#if defined(_M_IX86) || defined(_M_AMD64)
354 PciEcamSkipK8Northbridge = PciEcamIsAmdK8();
355#endif
356 DPRINT1("PCI: ECAM window at 0x%I64x for 0x%lx buses\n",
359 }
360
361 if (!PciEcamMapBus(FdoExtension->BaseBus) || PciEcamVerified) return;
362
363 /* An empty bus proves nothing, so leave it to the next one */
366 {
368 }
369 else if (NT_SUCCESS(Status))
370 {
372 DPRINT1("PCI: ECAM verified on bus 0x%lx\n", FdoExtension->BaseBus);
373 }
374}
375
385NTAPI
387 _In_ ULONG Bus,
393{
395
396 if (!PciEcamVerified) return FALSE;
397
400 {
401 return FALSE;
402 }
403
404 Function = PciEcamFunctionBase(Bus, Slot);
405 if (!Function) return FALSE;
406
408 return TRUE;
409}
410
411/* EOF */
#define PAGED_CODE()
static _Out_opt_ PULONGLONG Start
unsigned char BOOLEAN
Definition: actypes.h:127
#define WRITE_REGISTER_USHORT(r, v)
Definition: arm.h:14
#define READ_REGISTER_USHORT(r)
Definition: arm.h:13
#define WRITE_REGISTER_ULONG(r, v)
Definition: arm.h:11
#define READ_REGISTER_ULONG(r)
Definition: arm.h:10
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
_In_ CDROM_SCAN_FOR_SPECIAL_INFO _In_ PCDROM_SCAN_FOR_SPECIAL_HANDLER Function
Definition: cdrom.h:1156
Definition: bufpool.h:45
_Check_return_ _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS _Out_ UINT * Width
Definition: dispmprt.h:1444
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define L(x)
Definition: resources.c:13
VOID NTAPI PciReadSlotConfig(IN PPCI_FDO_EXTENSION DeviceExtension, IN PCI_SLOT_NUMBER Slot, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length)
Definition: config.c:165
BOOLEAN NTAPI PciOpenKey(IN PWCHAR KeyName, IN HANDLE RootKey, IN ACCESS_MASK DesiredAccess, OUT PHANDLE KeyHandle, OUT PNTSTATUS KeyStatus)
Definition: utils.c:165
#define PCI_POOL_TAG
Definition: pci.h:27
@ FdoExtension
Definition: precomp.h:48
static BOOLEAN NTAPI PciEcamParseWindow(_In_ PKEY_VALUE_PARTIAL_INFORMATION Value)
Definition: ecam.c:34
static PUCHAR PciEcamBusView[PCI_ECAM_BUS_COUNT]
Definition: ecam.c:26
static BOOLEAN PciEcamSkipK8Northbridge
Definition: ecam.c:23
static VOID NTAPI PciEcamDiscardWindow(VOID)
Definition: ecam.c:184
VOID NTAPI PciInitializeEcam(_In_ PPCI_FDO_EXTENSION FdoExtension)
Maps the bus an FDO decodes into the ECAM window and verifies the window the first time a bus with de...
Definition: ecam.c:336
#define PCI_ECAM_BUS_SIZE
Definition: ecam.c:18
#define PCI_ECAM_BUS_COUNT
Definition: ecam.c:17
static ULONG PciEcamWindowBuses
Definition: ecam.c:25
BOOLEAN PciEcamVerified
Definition: ecam.c:20
static PUCHAR NTAPI PciEcamMapBus(_In_ ULONG Bus)
Definition: ecam.c:162
static NTSTATUS NTAPI PciEcamQueryWindow(VOID)
Definition: ecam.c:74
BOOLEAN NTAPI PciEcamReadWriteConfig(_In_ ULONG Bus, _In_ PCI_SLOT_NUMBER Slot, _Inout_updates_bytes_(Length) PVOID Buffer, _In_ ULONG Offset, _In_ ULONG Length, _In_ BOOLEAN Read)
Performs a configuration space access through the ECAM window.
Definition: ecam.c:386
static ULONGLONG PciEcamWindowStart
Definition: ecam.c:24
static NTSTATUS NTAPI PciEcamVerifyBus(_In_ PPCI_FDO_EXTENSION FdoExtension)
Definition: ecam.c:287
static BOOLEAN PciEcamWindowQueried
Definition: ecam.c:22
static VOID NTAPI PciEcamTransfer(_In_ PUCHAR Function, _Inout_updates_bytes_(Length) PUCHAR Buffer, _In_ ULONG Offset, _In_ ULONG Length, _In_ BOOLEAN Read)
Definition: ecam.c:226
static PUCHAR NTAPI PciEcamFunctionBase(_In_ ULONG Bus, _In_ PCI_SLOT_NUMBER Slot)
Definition: ecam.c:203
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PagedPool
Definition: env_spec_w32.h:308
Status
Definition: gdiplustypes.h:24
PPC_QUAL void __cpuid(int CPUInfo[], const int InfoType)
Definition: intrin_ppc.h:682
VOID NTAPI MmUnmapIoSpace(IN PVOID BaseAddress, IN SIZE_T NumberOfBytes)
Definition: iosup.c:193
PVOID NTAPI MmMapIoSpace(IN PHYSICAL_ADDRESS PhysicalAddress, IN SIZE_T NumberOfBytes, IN MEMORY_CACHING_TYPE CacheType)
Definition: iosup.c:47
if(dx< 0)
Definition: linetemp.h:194
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4715
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
#define _In_
Definition: no_sal2.h:158
#define _Inout_updates_bytes_(s)
Definition: no_sal2.h:184
@ KeyValuePartialInformation
Definition: nt_native.h:1185
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define KEY_QUERY_VALUE
Definition: nt_native.h:1019
#define REG_RESOURCE_REQUIREMENTS_LIST
Definition: nt_native.h:1507
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define STATUS_DEVICE_CONFIGURATION_ERROR
Definition: ntstatus.h:713
unsigned short USHORT
Definition: pedump.c:61
static WCHAR Address[46]
Definition: ping.c:68
#define CmResourceTypeMemory
Definition: restypes.h:106
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
_In_ BOOLEAN Read
Definition: strmini.h:479
Definition: window.c:29
IO_RESOURCE_DESCRIPTOR Descriptors[1]
Definition: iotypes.h:2739
IO_RESOURCE_LIST List[1]
Definition: iotypes.h:2749
union _PCI_SLOT_NUMBER::@4969 u
struct _PCI_SLOT_NUMBER::@4969::@4970 bits
#define MAXULONG
Definition: typedefs.h:251
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char UCHAR
Definition: typedefs.h:53
int64_t LONGLONG
Definition: typedefs.h:68
#define NTAPI
Definition: typedefs.h:36
int32_t INT
Definition: typedefs.h:58
uint64_t ULONGLONG
Definition: typedefs.h:67
uint16_t * PUSHORT
Definition: typedefs.h:56
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_Must_inspect_result_ _In_ WDFDEVICE Device
Definition: wdfchildlist.h:474
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:243
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
#define CmResourceTypeMemoryLarge
Definition: cmtypes.h:231
NTKERNELAPI VOID NTAPI WRITE_REGISTER_UCHAR(IN PUCHAR Register, IN UCHAR Value)
NTKERNELAPI UCHAR NTAPI READ_REGISTER_UCHAR(IN PUCHAR Register)
#define PCI_INVALID_VENDORID
Definition: iotypes.h:3603
#define PCI_EXTENDED_CONFIG_LENGTH
Definition: iotypes.h:3598
#define PCI_MAX_FUNCTION
Definition: iotypes.h:3601
#define PCI_MAX_DEVICES
Definition: iotypes.h:3600
struct _IO_RESOURCE_REQUIREMENTS_LIST * PIO_RESOURCE_REQUIREMENTS_LIST
@ MmNonCached
Definition: mmtypes.h:129