xref: /reactos/hal/halx86/legacy/bus/pcibus.c (revision c8d07514)
1 /*
2  * PROJECT:         ReactOS HAL
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            hal/halx86/legacy/bus/pcibus.c
5  * PURPOSE:         PCI Bus Support (Configuration Space, Resource Allocation)
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS *******************************************************************/
16 
17 extern BOOLEAN HalpPciLockSettings;
18 ULONG HalpBusType;
19 
20 PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice[2] = {{{{0}}}};
21 
22 BOOLEAN HalpPCIConfigInitialized;
23 ULONG HalpMinPciBus, HalpMaxPciBus;
24 KSPIN_LOCK HalpPCIConfigLock;
25 PCI_CONFIG_HANDLER PCIConfigHandler;
26 
27 /* PCI Operation Matrix */
28 UCHAR PCIDeref[4][4] =
29 {
30     {0, 1, 2, 2},   // ULONG-aligned offset
31     {1, 1, 1, 1},   // UCHAR-aligned offset
32     {2, 1, 2, 2},   // USHORT-aligned offset
33     {1, 1, 1, 1}    // UCHAR-aligned offset
34 };
35 
36 /* Type 1 PCI Bus */
37 PCI_CONFIG_HANDLER PCIConfigHandlerType1 =
38 {
39     /* Synchronization */
40     (FncSync)HalpPCISynchronizeType1,
41     (FncReleaseSync)HalpPCIReleaseSynchronzationType1,
42 
43     /* Read */
44     {
45         (FncConfigIO)HalpPCIReadUlongType1,
46         (FncConfigIO)HalpPCIReadUcharType1,
47         (FncConfigIO)HalpPCIReadUshortType1
48     },
49 
50     /* Write */
51     {
52         (FncConfigIO)HalpPCIWriteUlongType1,
53         (FncConfigIO)HalpPCIWriteUcharType1,
54         (FncConfigIO)HalpPCIWriteUshortType1
55     }
56 };
57 
58 /* Type 2 PCI Bus */
59 PCI_CONFIG_HANDLER PCIConfigHandlerType2 =
60 {
61     /* Synchronization */
62     (FncSync)HalpPCISynchronizeType2,
63     (FncReleaseSync)HalpPCIReleaseSynchronizationType2,
64 
65     /* Read */
66     {
67         (FncConfigIO)HalpPCIReadUlongType2,
68         (FncConfigIO)HalpPCIReadUcharType2,
69         (FncConfigIO)HalpPCIReadUshortType2
70     },
71 
72     /* Write */
73     {
74         (FncConfigIO)HalpPCIWriteUlongType2,
75         (FncConfigIO)HalpPCIWriteUcharType2,
76         (FncConfigIO)HalpPCIWriteUshortType2
77     }
78 };
79 
80 PCIPBUSDATA HalpFakePciBusData =
81 {
82     {
83         PCI_DATA_TAG,
84         PCI_DATA_VERSION,
85         HalpReadPCIConfig,
86         HalpWritePCIConfig,
87         NULL,
88         NULL,
89         {{{0, 0, 0}}},
90         {0, 0, 0, 0}
91     },
92     {{0, 0}},
93     32,
94 };
95 
96 BUS_HANDLER HalpFakePciBusHandler =
97 {
98     1,
99     PCIBus,
100     PCIConfiguration,
101     0,
102     NULL,
103     NULL,
104     &HalpFakePciBusData,
105     0,
106     NULL,
107     {0, 0, 0, 0},
108     (PGETSETBUSDATA)HalpGetPCIData,
109     (PGETSETBUSDATA)HalpSetPCIData,
110     NULL,
111     HalpAssignPCISlotResources,
112     NULL,
113     NULL
114 };
115 
116 /* TYPE 1 FUNCTIONS **********************************************************/
117 
118 VOID
119 NTAPI
120 HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler,
121                         IN PCI_SLOT_NUMBER Slot,
122                         IN PKIRQL Irql,
123                         IN PPCI_TYPE1_CFG_BITS PciCfg1)
124 {
125     /* Setup the PCI Configuration Register */
126     PciCfg1->u.AsULONG = 0;
127     PciCfg1->u.bits.BusNumber = BusHandler->BusNumber;
128     PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber;
129     PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber;
130     PciCfg1->u.bits.Enable = TRUE;
131 
132     /* Acquire the lock */
133     KeRaiseIrql(HIGH_LEVEL, Irql);
134     KiAcquireSpinLock(&HalpPCIConfigLock);
135 }
136 
137 VOID
138 NTAPI
139 HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler,
140                                   IN KIRQL Irql)
141 {
142     PCI_TYPE1_CFG_BITS PciCfg1;
143 
144     /* Clear the PCI Configuration Register */
145     PciCfg1.u.AsULONG = 0;
146     WRITE_PORT_ULONG(((PPCIPBUSDATA)BusHandler->BusData)->Config.Type1.Address,
147                      PciCfg1.u.AsULONG);
148 
149     /* Release the lock */
150     KiReleaseSpinLock(&HalpPCIConfigLock);
151     KeLowerIrql(Irql);
152 }
153 
154 TYPE1_READ(HalpPCIReadUcharType1, UCHAR)
155 TYPE1_READ(HalpPCIReadUshortType1, USHORT)
156 TYPE1_READ(HalpPCIReadUlongType1, ULONG)
157 TYPE1_WRITE(HalpPCIWriteUcharType1, UCHAR)
158 TYPE1_WRITE(HalpPCIWriteUshortType1, USHORT)
159 TYPE1_WRITE(HalpPCIWriteUlongType1, ULONG)
160 
161 /* TYPE 2 FUNCTIONS **********************************************************/
162 
163 VOID
164 NTAPI
165 HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler,
166                         IN PCI_SLOT_NUMBER Slot,
167                         IN PKIRQL Irql,
168                         IN PPCI_TYPE2_ADDRESS_BITS PciCfg)
169 {
170     PCI_TYPE2_CSE_BITS PciCfg2Cse;
171     PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
172 
173     /* Setup the configuration register */
174     PciCfg->u.AsUSHORT = 0;
175     PciCfg->u.bits.Agent = (USHORT)Slot.u.bits.DeviceNumber;
176     PciCfg->u.bits.AddressBase = (USHORT)BusData->Config.Type2.Base;
177 
178     /* Acquire the lock */
179     KeRaiseIrql(HIGH_LEVEL, Irql);
180     KiAcquireSpinLock(&HalpPCIConfigLock);
181 
182     /* Setup the CSE Register */
183     PciCfg2Cse.u.AsUCHAR = 0;
184     PciCfg2Cse.u.bits.Enable = TRUE;
185     PciCfg2Cse.u.bits.FunctionNumber = (UCHAR)Slot.u.bits.FunctionNumber;
186     PciCfg2Cse.u.bits.Key = -1;
187 
188     /* Write the bus number and CSE */
189     WRITE_PORT_UCHAR(BusData->Config.Type2.Forward,
190                      (UCHAR)BusHandler->BusNumber);
191     WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
192 }
193 
194 VOID
195 NTAPI
196 HalpPCIReleaseSynchronizationType2(IN PBUS_HANDLER BusHandler,
197                                    IN KIRQL Irql)
198 {
199     PCI_TYPE2_CSE_BITS PciCfg2Cse;
200     PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
201 
202     /* Clear CSE and bus number */
203     PciCfg2Cse.u.AsUCHAR = 0;
204     WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR);
205     WRITE_PORT_UCHAR(BusData->Config.Type2.Forward, 0);
206 
207     /* Release the lock */
208     KiReleaseSpinLock(&HalpPCIConfigLock);
209     KeLowerIrql(Irql);
210 }
211 
212 TYPE2_READ(HalpPCIReadUcharType2, UCHAR)
213 TYPE2_READ(HalpPCIReadUshortType2, USHORT)
214 TYPE2_READ(HalpPCIReadUlongType2, ULONG)
215 TYPE2_WRITE(HalpPCIWriteUcharType2, UCHAR)
216 TYPE2_WRITE(HalpPCIWriteUshortType2, USHORT)
217 TYPE2_WRITE(HalpPCIWriteUlongType2, ULONG)
218 
219 /* PCI CONFIGURATION SPACE ***************************************************/
220 
221 VOID
222 NTAPI
223 HalpPCIConfig(IN PBUS_HANDLER BusHandler,
224               IN PCI_SLOT_NUMBER Slot,
225               IN PUCHAR Buffer,
226               IN ULONG Offset,
227               IN ULONG Length,
228               IN FncConfigIO *ConfigIO)
229 {
230     KIRQL OldIrql;
231     ULONG i;
232     UCHAR State[20];
233 
234     /* Synchronize the operation */
235     PCIConfigHandler.Synchronize(BusHandler, Slot, &OldIrql, State);
236 
237     /* Loop every increment */
238     while (Length)
239     {
240         /* Find out the type of read/write we need to do */
241         i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
242 
243         /* Do the read/write and return the number of bytes */
244         i = ConfigIO[i]((PPCIPBUSDATA)BusHandler->BusData,
245                         State,
246                         Buffer,
247                         Offset);
248 
249         /* Increment the buffer position and offset, and decrease the length */
250         Offset += i;
251         Buffer += i;
252         Length -= i;
253     }
254 
255     /* Release the lock and PCI bus */
256     PCIConfigHandler.ReleaseSynchronzation(BusHandler, OldIrql);
257 }
258 
259 VOID
260 NTAPI
261 HalpReadPCIConfig(IN PBUS_HANDLER BusHandler,
262                   IN PCI_SLOT_NUMBER Slot,
263                   IN PVOID Buffer,
264                   IN ULONG Offset,
265                   IN ULONG Length)
266 {
267     /* Validate the PCI Slot */
268     if (!HalpValidPCISlot(BusHandler, Slot))
269     {
270         /* Fill the buffer with invalid data */
271         RtlFillMemory(Buffer, Length, -1);
272     }
273     else
274     {
275         /* Send the request */
276         HalpPCIConfig(BusHandler,
277                       Slot,
278                       Buffer,
279                       Offset,
280                       Length,
281                       PCIConfigHandler.ConfigRead);
282     }
283 }
284 
285 VOID
286 NTAPI
287 HalpWritePCIConfig(IN PBUS_HANDLER BusHandler,
288                    IN PCI_SLOT_NUMBER Slot,
289                    IN PVOID Buffer,
290                    IN ULONG Offset,
291                    IN ULONG Length)
292 {
293     /* Validate the PCI Slot */
294     if (HalpValidPCISlot(BusHandler, Slot))
295     {
296         /* Send the request */
297         HalpPCIConfig(BusHandler,
298                       Slot,
299                       Buffer,
300                       Offset,
301                       Length,
302                       PCIConfigHandler.ConfigWrite);
303     }
304 }
305 
306 #ifdef SARCH_XBOX
307 BOOLEAN
308 NTAPI
309 HalpXboxBlacklistedPCISlot(IN PBUS_HANDLER BusHandler,
310                            IN PCI_SLOT_NUMBER Slot)
311 {
312     /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely
313      * hang the Xbox. Also, the device number doesn't seem to be decoded for the
314      * video card, so it appears to be present on 1:0:0 - 1:31:0.
315      * We hack around these problems by indicating "device not present" for devices
316      * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */
317     if ((BusHandler->BusNumber == 0 && Slot.u.bits.DeviceNumber == 0 &&
318         (Slot.u.bits.FunctionNumber == 1 || Slot.u.bits.FunctionNumber == 2)) ||
319         (BusHandler->BusNumber == 1 && Slot.u.bits.DeviceNumber != 0))
320     {
321         DPRINT("Blacklisted PCI slot (%d:%d:%d)\n", BusHandler->BusNumber, Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
322         return TRUE;
323     }
324 
325     /* Temporary hack to avoid stack overflow in kernel, see CORE-16319 */
326     if (BusHandler->BusNumber == 0 && Slot.u.bits.DeviceNumber == 8 && Slot.u.bits.FunctionNumber == 0)
327     {
328         DPRINT("Blacklisted PCI-to-PCI bridge (00:08.0 - PCI\\VEN_10DE&DEV_01B8, see CORE-16319)\n");
329         return TRUE;
330     }
331 
332     return FALSE;
333 }
334 #endif
335 
336 BOOLEAN
337 NTAPI
338 HalpValidPCISlot(IN PBUS_HANDLER BusHandler,
339                  IN PCI_SLOT_NUMBER Slot)
340 {
341     PCI_SLOT_NUMBER MultiSlot;
342     PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData;
343     UCHAR HeaderType;
344     //ULONG Device;
345 
346     /* Simple validation */
347     if (Slot.u.bits.Reserved) return FALSE;
348     if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) return FALSE;
349 
350 #ifdef SARCH_XBOX
351     if (HalpXboxBlacklistedPCISlot(BusHandler, Slot)) return FALSE;
352 #endif
353 
354     /* Function 0 doesn't need checking */
355     if (!Slot.u.bits.FunctionNumber) return TRUE;
356 
357     /* Functions 0+ need Multi-Function support, so check the slot */
358     //Device = Slot.u.bits.DeviceNumber;
359     MultiSlot = Slot;
360     MultiSlot.u.bits.FunctionNumber = 0;
361 
362     /* Send function 0 request to get the header back */
363     HalpReadPCIConfig(BusHandler,
364                       MultiSlot,
365                       &HeaderType,
366                       FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType),
367                       sizeof(UCHAR));
368 
369     /* Now make sure the header is multi-function */
370     if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) return FALSE;
371     return TRUE;
372 }
373 
374 /* HAL PCI CALLBACKS *********************************************************/
375 
376 ULONG
377 NTAPI
378 HalpGetPCIData(IN PBUS_HANDLER BusHandler,
379                IN PBUS_HANDLER RootHandler,
380                IN ULONG SlotNumber,
381                IN PVOID Buffer,
382                IN ULONG Offset,
383                IN ULONG Length)
384 {
385     PCI_SLOT_NUMBER Slot;
386     UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH];
387     PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer;
388     ULONG Len = 0;
389 
390     Slot.u.AsULONG = SlotNumber;
391 #ifdef SARCH_XBOX
392     if (HalpXboxBlacklistedPCISlot(BusHandler, Slot))
393     {
394         if (Offset == 0 && Length >= sizeof(USHORT))
395         {
396             *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
397             return sizeof(USHORT);
398         }
399         return 0;
400     }
401 #endif
402 
403     /* Normalize the length */
404     if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG);
405 
406     /* Check if this is a vendor-specific read */
407     if (Offset >= PCI_COMMON_HDR_LENGTH)
408     {
409         /* Read the header */
410         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG));
411 
412         /* Make sure the vendor is valid */
413         if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
414     }
415     else
416     {
417         /* Read the entire header */
418         Len = PCI_COMMON_HDR_LENGTH;
419         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len);
420 
421         /* Validate the vendor ID */
422         if (PciConfig->VendorID == PCI_INVALID_VENDORID)
423         {
424             /* It's invalid, but we want to return this much */
425             Len = sizeof(USHORT);
426         }
427 
428         /* Now check if there's space left */
429         if (Len < Offset) return 0;
430 
431         /* There is, so return what's after the offset and normalize */
432         Len -= Offset;
433         if (Len > Length) Len = Length;
434 
435         /* Copy the data into the caller's buffer */
436         RtlMoveMemory(Buffer, PciBuffer + Offset, Len);
437 
438         /* Update buffer and offset, decrement total length */
439         Offset += Len;
440         Buffer = (PVOID)((ULONG_PTR)Buffer + Len);
441         Length -= Len;
442     }
443 
444     /* Now we still have something to copy */
445     if (Length)
446     {
447         /* Check if it's vendor-specific data */
448         if (Offset >= PCI_COMMON_HDR_LENGTH)
449         {
450             /* Read it now */
451             HalpReadPCIConfig(BusHandler, Slot, Buffer, Offset, Length);
452             Len += Length;
453         }
454     }
455 
456     /* Update the total length read */
457     return Len;
458 }
459 
460 ULONG
461 NTAPI
462 HalpSetPCIData(IN PBUS_HANDLER BusHandler,
463                IN PBUS_HANDLER RootHandler,
464                IN ULONG SlotNumber,
465                IN PVOID Buffer,
466                IN ULONG Offset,
467                IN ULONG Length)
468 {
469     PCI_SLOT_NUMBER Slot;
470     UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH];
471     PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer;
472     ULONG Len = 0;
473 
474     Slot.u.AsULONG = SlotNumber;
475 #ifdef SARCH_XBOX
476     if (HalpXboxBlacklistedPCISlot(BusHandler, Slot)) return 0;
477 #endif
478 
479     /* Normalize the length */
480     if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG);
481 
482     /* Check if this is a vendor-specific read */
483     if (Offset >= PCI_COMMON_HDR_LENGTH)
484     {
485         /* Read the header */
486         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG));
487 
488         /* Make sure the vendor is valid */
489         if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
490     }
491     else
492     {
493         /* Read the entire header and validate the vendor ID */
494         Len = PCI_COMMON_HDR_LENGTH;
495         HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len);
496         if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0;
497 
498         /* Return what's after the offset and normalize */
499         Len -= Offset;
500         if (Len > Length) Len = Length;
501 
502         /* Copy the specific caller data */
503         RtlMoveMemory(PciBuffer + Offset, Buffer, Len);
504 
505         /* Write the actual configuration data */
506         HalpWritePCIConfig(BusHandler, Slot, PciBuffer + Offset, Offset, Len);
507 
508         /* Update buffer and offset, decrement total length */
509         Offset += Len;
510         Buffer = (PVOID)((ULONG_PTR)Buffer + Len);
511         Length -= Len;
512     }
513 
514     /* Now we still have something to copy */
515     if (Length)
516     {
517         /* Check if it's vendor-specific data */
518         if (Offset >= PCI_COMMON_HDR_LENGTH)
519         {
520             /* Read it now */
521             HalpWritePCIConfig(BusHandler, Slot, Buffer, Offset, Length);
522             Len += Length;
523         }
524     }
525 
526     /* Update the total length read */
527     return Len;
528 }
529 
530 ULONG
531 NTAPI
532 HalpGetPCIIntOnISABus(IN PBUS_HANDLER BusHandler,
533                       IN PBUS_HANDLER RootHandler,
534                       IN ULONG BusInterruptLevel,
535                       IN ULONG BusInterruptVector,
536                       OUT PKIRQL Irql,
537                       OUT PKAFFINITY Affinity)
538 {
539     /* Validate the level first */
540     if (BusInterruptLevel < 1) return 0;
541 
542     /* PCI has its IRQs on top of ISA IRQs, so pass it on to the ISA handler */
543     return HalGetInterruptVector(Isa,
544                                  0,
545                                  BusInterruptLevel,
546                                  0,
547                                  Irql,
548                                  Affinity);
549 }
550 
551 VOID
552 NTAPI
553 HalpPCIPin2ISALine(IN PBUS_HANDLER BusHandler,
554                    IN PBUS_HANDLER RootHandler,
555                    IN PCI_SLOT_NUMBER SlotNumber,
556                    IN PPCI_COMMON_CONFIG PciData)
557 {
558     UNIMPLEMENTED_DBGBREAK();
559 }
560 
561 VOID
562 NTAPI
563 HalpPCIISALine2Pin(IN PBUS_HANDLER BusHandler,
564                    IN PBUS_HANDLER RootHandler,
565                    IN PCI_SLOT_NUMBER SlotNumber,
566                    IN PPCI_COMMON_CONFIG PciNewData,
567                    IN PPCI_COMMON_CONFIG PciOldData)
568 {
569     UNIMPLEMENTED_DBGBREAK();
570 }
571 
572 NTSTATUS
573 NTAPI
574 HalpGetISAFixedPCIIrq(IN PBUS_HANDLER BusHandler,
575                       IN PBUS_HANDLER RootHandler,
576                       IN PCI_SLOT_NUMBER PciSlot,
577                       OUT PSUPPORTED_RANGE *Range)
578 {
579     PCI_COMMON_HEADER PciData;
580 
581     /* Read PCI configuration data */
582     HalGetBusData(PCIConfiguration,
583                   BusHandler->BusNumber,
584                   PciSlot.u.AsULONG,
585                   &PciData,
586                   PCI_COMMON_HDR_LENGTH);
587 
588     /* Make sure it's a real device */
589     if (PciData.VendorID == PCI_INVALID_VENDORID) return STATUS_UNSUCCESSFUL;
590 
591     /* Allocate the supported range structure */
592     *Range = ExAllocatePoolWithTag(PagedPool, sizeof(SUPPORTED_RANGE), TAG_HAL);
593     if (!*Range) return STATUS_INSUFFICIENT_RESOURCES;
594 
595     /* Set it up */
596     RtlZeroMemory(*Range, sizeof(SUPPORTED_RANGE));
597     (*Range)->Base = 1;
598 
599     /* If the PCI device has no IRQ, nothing to do */
600     if (!PciData.u.type0.InterruptPin) return STATUS_SUCCESS;
601 
602     /* FIXME: The PCI IRQ Routing Miniport should be called */
603 
604     /* Also if the INT# seems bogus, nothing to do either */
605     if ((PciData.u.type0.InterruptLine == 0) ||
606         (PciData.u.type0.InterruptLine == 255))
607     {
608         /* Fake success */
609         return STATUS_SUCCESS;
610     }
611 
612     /* Otherwise, the INT# should be valid, return it to the caller */
613     (*Range)->Base = PciData.u.type0.InterruptLine;
614     (*Range)->Limit = PciData.u.type0.InterruptLine;
615     return STATUS_SUCCESS;
616 }
617 
618 CODE_SEG("INIT")
619 NTSTATUS
620 NTAPI
621 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock,
622                                IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice)
623 {
624     DPRINT1("Unimplemented!\n");
625     return STATUS_NOT_IMPLEMENTED;
626 }
627 
628 CODE_SEG("INIT")
629 NTSTATUS
630 NTAPI
631 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice)
632 {
633     DPRINT1("Unimplemented!\n");
634     return STATUS_NOT_IMPLEMENTED;
635 }
636 
637 CODE_SEG("INIT")
638 VOID
639 NTAPI
640 HalpRegisterPciDebuggingDeviceInfo(VOID)
641 {
642     BOOLEAN Found = FALSE;
643     ULONG i;
644     PAGED_CODE();
645 
646     /* Loop PCI debugging devices */
647     for (i = 0; i < 2; i++)
648     {
649         /* Reserved bit is set if we found one */
650         if (HalpPciDebuggingDevice[i].u.bits.Reserved1)
651         {
652             Found = TRUE;
653             break;
654         }
655     }
656 
657     /* Bail out if there aren't any */
658     if (!Found) return;
659 
660     /* FIXME: TODO */
661     UNIMPLEMENTED_DBGBREAK("You have implemented the KD routines for searching PCI debugger"
662                            "devices, but you have forgotten to implement this routine\n");
663 }
664 
665 static ULONG NTAPI
666 PciSize(ULONG Base, ULONG Mask)
667 {
668     ULONG Size = Mask & Base; /* Find the significant bits */
669     Size = Size & ~(Size - 1); /* Get the lowest of them to find the decode size */
670     return Size;
671 }
672 
673 NTSTATUS
674 NTAPI
675 HalpAdjustPCIResourceList(IN PBUS_HANDLER BusHandler,
676                           IN PBUS_HANDLER RootHandler,
677                           IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList)
678 {
679     PPCIPBUSDATA BusData;
680     PCI_SLOT_NUMBER SlotNumber;
681     PSUPPORTED_RANGE Interrupt;
682     NTSTATUS Status;
683 
684     /* Get PCI bus data */
685     BusData = BusHandler->BusData;
686     SlotNumber.u.AsULONG = (*pResourceList)->SlotNumber;
687 
688     /* Get the IRQ supported range */
689     Status = BusData->GetIrqRange(BusHandler, RootHandler, SlotNumber, &Interrupt);
690     if (!NT_SUCCESS(Status)) return Status;
691 #ifndef _MINIHAL_
692     /* Handle the /PCILOCK feature */
693     if (HalpPciLockSettings)
694     {
695         /* /PCILOCK is not yet supported */
696         UNIMPLEMENTED_DBGBREAK("/PCILOCK boot switch is not yet supported.");
697     }
698 #endif
699     /* Now create the correct resource list based on the supported bus ranges */
700 #if 0
701     Status = HaliAdjustResourceListRange(BusHandler->BusAddresses,
702                                          Interrupt,
703                                          pResourceList);
704 #else
705     DPRINT1("HAL: No PCI Resource Adjustment done! Hardware may malfunction\n");
706     Status = STATUS_SUCCESS;
707 #endif
708 
709     /* Return to caller */
710     ExFreePool(Interrupt);
711     return Status;
712 }
713 
714 NTSTATUS
715 NTAPI
716 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler,
717                            IN PBUS_HANDLER RootHandler,
718                            IN PUNICODE_STRING RegistryPath,
719                            IN PUNICODE_STRING DriverClassName OPTIONAL,
720                            IN PDRIVER_OBJECT DriverObject,
721                            IN PDEVICE_OBJECT DeviceObject OPTIONAL,
722                            IN ULONG Slot,
723                            IN OUT PCM_RESOURCE_LIST *AllocatedResources)
724 {
725     PCI_COMMON_CONFIG PciConfig;
726     SIZE_T Address;
727     ULONG ResourceCount;
728     ULONG Size[PCI_TYPE0_ADDRESSES];
729     NTSTATUS Status = STATUS_SUCCESS;
730     UCHAR Offset;
731     PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
732     PCI_SLOT_NUMBER SlotNumber;
733     ULONG WriteBuffer;
734     DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n");
735 
736     /* FIXME: Should handle 64-bit addresses */
737 
738     /* Read configuration data */
739     SlotNumber.u.AsULONG = Slot;
740     HalpReadPCIConfig(BusHandler, SlotNumber, &PciConfig, 0, PCI_COMMON_HDR_LENGTH);
741 
742     /* Check if we read it correctly */
743     if (PciConfig.VendorID == PCI_INVALID_VENDORID)
744         return STATUS_NO_SUCH_DEVICE;
745 
746     /* Read the PCI configuration space for the device and store base address and
747     size information in temporary storage. Count the number of valid base addresses */
748     ResourceCount = 0;
749     for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++)
750     {
751         if (0xffffffff == PciConfig.u.type0.BaseAddresses[Address])
752             PciConfig.u.type0.BaseAddresses[Address] = 0;
753 
754         /* Memory resource */
755         if (0 != PciConfig.u.type0.BaseAddresses[Address])
756         {
757             ResourceCount++;
758 
759             Offset = (UCHAR)FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.BaseAddresses[Address]);
760 
761             /* Write 0xFFFFFFFF there */
762             WriteBuffer = 0xffffffff;
763             HalpWritePCIConfig(BusHandler, SlotNumber, &WriteBuffer, Offset, sizeof(ULONG));
764 
765             /* Read that figure back from the config space */
766             HalpReadPCIConfig(BusHandler, SlotNumber, &Size[Address], Offset, sizeof(ULONG));
767 
768             /* Write back initial value */
769             HalpWritePCIConfig(BusHandler, SlotNumber, &PciConfig.u.type0.BaseAddresses[Address], Offset, sizeof(ULONG));
770         }
771     }
772 
773     /* Interrupt resource */
774     if (0 != PciConfig.u.type0.InterruptPin &&
775         0 != PciConfig.u.type0.InterruptLine &&
776         0xFF != PciConfig.u.type0.InterruptLine)
777         ResourceCount++;
778 
779     /* Allocate output buffer and initialize */
780     *AllocatedResources = ExAllocatePoolWithTag(
781         PagedPool,
782         sizeof(CM_RESOURCE_LIST) +
783         (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
784         TAG_HAL);
785 
786     if (NULL == *AllocatedResources)
787         return STATUS_NO_MEMORY;
788 
789     (*AllocatedResources)->Count = 1;
790     (*AllocatedResources)->List[0].InterfaceType = PCIBus;
791     (*AllocatedResources)->List[0].BusNumber = BusHandler->BusNumber;
792     (*AllocatedResources)->List[0].PartialResourceList.Version = 1;
793     (*AllocatedResources)->List[0].PartialResourceList.Revision = 1;
794     (*AllocatedResources)->List[0].PartialResourceList.Count = ResourceCount;
795     Descriptor = (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors;
796 
797     /* Store configuration information */
798     for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++)
799     {
800         if (0 != PciConfig.u.type0.BaseAddresses[Address])
801         {
802             if (PCI_ADDRESS_MEMORY_SPACE ==
803                 (PciConfig.u.type0.BaseAddresses[Address] & 0x1))
804             {
805                 Descriptor->Type = CmResourceTypeMemory;
806                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */
807                 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;             /* FIXME Just a guess */
808                 Descriptor->u.Memory.Start.QuadPart = (PciConfig.u.type0.BaseAddresses[Address] & PCI_ADDRESS_MEMORY_ADDRESS_MASK);
809                 Descriptor->u.Memory.Length = PciSize(Size[Address], PCI_ADDRESS_MEMORY_ADDRESS_MASK);
810             }
811             else if (PCI_ADDRESS_IO_SPACE ==
812                 (PciConfig.u.type0.BaseAddresses[Address] & 0x1))
813             {
814                 Descriptor->Type = CmResourceTypePort;
815                 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */
816                 Descriptor->Flags = CM_RESOURCE_PORT_IO;                       /* FIXME Just a guess */
817                 Descriptor->u.Port.Start.QuadPart = PciConfig.u.type0.BaseAddresses[Address] &= PCI_ADDRESS_IO_ADDRESS_MASK;
818                 Descriptor->u.Port.Length = PciSize(Size[Address], PCI_ADDRESS_IO_ADDRESS_MASK & 0xffff);
819             }
820             else
821             {
822                 ASSERT(FALSE);
823                 return STATUS_UNSUCCESSFUL;
824             }
825             Descriptor++;
826         }
827     }
828 
829     if (0 != PciConfig.u.type0.InterruptPin &&
830         0 != PciConfig.u.type0.InterruptLine &&
831         0xFF != PciConfig.u.type0.InterruptLine)
832     {
833         Descriptor->Type = CmResourceTypeInterrupt;
834         Descriptor->ShareDisposition = CmResourceShareShared;          /* FIXME Just a guess */
835         Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;     /* FIXME Just a guess */
836         Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine;
837         Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine;
838         Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
839 
840         Descriptor++;
841     }
842 
843     ASSERT(Descriptor == (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors + ResourceCount);
844 
845     /* FIXME: Should store the resources in the registry resource map */
846 
847     return Status;
848 }
849 
850 ULONG
851 NTAPI
852 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler,
853                            IN ULONG BusNumber,
854                            IN PCI_SLOT_NUMBER SlotNumber,
855                            IN PVOID Buffer,
856                            IN ULONG Offset,
857                            IN ULONG Length)
858 {
859     BUS_HANDLER BusHandler;
860 
861     /* Setup fake PCI Bus handler */
862     RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
863     BusHandler.BusNumber = BusNumber;
864 
865     /* Read configuration data */
866     HalpReadPCIConfig(&BusHandler, SlotNumber, Buffer, Offset, Length);
867 
868     /* Return length */
869     return Length;
870 }
871 
872 CODE_SEG("INIT")
873 PPCI_REGISTRY_INFO_INTERNAL
874 NTAPI
875 HalpQueryPciRegistryInfo(VOID)
876 {
877 #ifndef _MINIHAL_
878     WCHAR NameBuffer[8];
879     OBJECT_ATTRIBUTES  ObjectAttributes;
880     UNICODE_STRING KeyName, ConfigName, IdentName;
881     HANDLE KeyHandle, BusKeyHandle, CardListHandle;
882     NTSTATUS Status;
883     UCHAR KeyBuffer[sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + 100];
884     PKEY_VALUE_FULL_INFORMATION ValueInfo = (PVOID)KeyBuffer;
885     UCHAR PartialKeyBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
886                            sizeof(PCI_CARD_DESCRIPTOR)];
887     PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo = (PVOID)PartialKeyBuffer;
888     KEY_FULL_INFORMATION KeyInformation;
889     ULONG ResultLength;
890     PWSTR Tag;
891     ULONG i, ElementCount;
892     PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
893     PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
894     PPCI_REGISTRY_INFO PciRegInfo;
895     PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
896     PPCI_CARD_DESCRIPTOR CardDescriptor;
897 
898     /* Setup the object attributes for the key */
899     RtlInitUnicodeString(&KeyName,
900                          L"\\Registry\\Machine\\Hardware\\Description\\"
901                          L"System\\MultiFunctionAdapter");
902     InitializeObjectAttributes(&ObjectAttributes,
903                                &KeyName,
904                                OBJ_CASE_INSENSITIVE,
905                                NULL,
906                                NULL);
907 
908     /* Open the key */
909     Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
910     if (!NT_SUCCESS(Status)) return NULL;
911 
912     /* Setup the receiving string */
913     KeyName.Buffer = NameBuffer;
914     KeyName.MaximumLength = sizeof(NameBuffer);
915 
916     /* Setup the configuration and identifier key names */
917     RtlInitUnicodeString(&ConfigName, L"Configuration Data");
918     RtlInitUnicodeString(&IdentName, L"Identifier");
919 
920     /* Keep looping for each ID */
921     for (i = 0; TRUE; i++)
922     {
923         /* Setup the key name */
924         RtlIntegerToUnicodeString(i, 10, &KeyName);
925         InitializeObjectAttributes(&ObjectAttributes,
926                                    &KeyName,
927                                    OBJ_CASE_INSENSITIVE,
928                                    KeyHandle,
929                                    NULL);
930 
931         /* Open it */
932         Status = ZwOpenKey(&BusKeyHandle, KEY_READ, &ObjectAttributes);
933         if (!NT_SUCCESS(Status))
934         {
935             /* None left, fail */
936             ZwClose(KeyHandle);
937             return NULL;
938         }
939 
940         /* Read the registry data */
941         Status = ZwQueryValueKey(BusKeyHandle,
942                                  &IdentName,
943                                  KeyValueFullInformation,
944                                  ValueInfo,
945                                  sizeof(KeyBuffer),
946                                  &ResultLength);
947         if (!NT_SUCCESS(Status))
948         {
949             /* Failed, try the next one */
950             ZwClose(BusKeyHandle);
951             continue;
952         }
953 
954         /* Get the PCI Tag and validate it */
955         Tag = (PWSTR)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
956         if ((Tag[0] != L'P') ||
957             (Tag[1] != L'C') ||
958             (Tag[2] != L'I') ||
959             (Tag[3]))
960         {
961             /* Not a valid PCI entry, skip it */
962             ZwClose(BusKeyHandle);
963             continue;
964         }
965 
966         /* Now read our PCI structure */
967         Status = ZwQueryValueKey(BusKeyHandle,
968                                  &ConfigName,
969                                  KeyValueFullInformation,
970                                  ValueInfo,
971                                  sizeof(KeyBuffer),
972                                  &ResultLength);
973         ZwClose(BusKeyHandle);
974         if (!NT_SUCCESS(Status)) continue;
975 
976         /* We read it OK! Get the actual resource descriptors */
977         FullDescriptor  = (PCM_FULL_RESOURCE_DESCRIPTOR)
978                           ((ULONG_PTR)ValueInfo + ValueInfo->DataOffset);
979         PartialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
980                             ((ULONG_PTR)FullDescriptor->
981                                         PartialResourceList.PartialDescriptors);
982 
983         /* Check if this is our PCI Registry Information */
984         if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
985         {
986             /* It is, stop searching */
987             break;
988         }
989     }
990 
991     /* Close the key */
992     ZwClose(KeyHandle);
993 
994     /* Save the PCI information for later */
995     PciRegInfo = (PPCI_REGISTRY_INFO)(PartialDescriptor + 1);
996 
997     /* Assume no Card List entries */
998     ElementCount = 0;
999 
1000     /* Set up for checking the PCI Card List key */
1001     RtlInitUnicodeString(&KeyName,
1002                          L"\\Registry\\Machine\\System\\CurrentControlSet\\"
1003                          L"Control\\PnP\\PCI\\CardList");
1004     InitializeObjectAttributes(&ObjectAttributes,
1005                                &KeyName,
1006                                OBJ_CASE_INSENSITIVE,
1007                                NULL,
1008                                NULL);
1009 
1010     /* Attempt to open it */
1011     Status = ZwOpenKey(&CardListHandle, KEY_READ, &ObjectAttributes);
1012     if (NT_SUCCESS(Status))
1013     {
1014         /* It exists, so let's query it */
1015         Status = ZwQueryKey(CardListHandle,
1016                             KeyFullInformation,
1017                             &KeyInformation,
1018                             sizeof(KEY_FULL_INFORMATION),
1019                             &ResultLength);
1020         if (!NT_SUCCESS(Status))
1021         {
1022             /* Failed to query, so no info */
1023             PciRegistryInfo = NULL;
1024         }
1025         else
1026         {
1027             /* Allocate the full structure */
1028             PciRegistryInfo =
1029                 ExAllocatePoolWithTag(NonPagedPool,
1030                                       sizeof(PCI_REGISTRY_INFO_INTERNAL) +
1031                                       (KeyInformation.Values *
1032                                        sizeof(PCI_CARD_DESCRIPTOR)),
1033                                        TAG_HAL);
1034             if (PciRegistryInfo)
1035             {
1036                 /* Get the first card descriptor entry */
1037                 CardDescriptor = (PPCI_CARD_DESCRIPTOR)(PciRegistryInfo + 1);
1038 
1039                 /* Loop all the values */
1040                 for (i = 0; i < KeyInformation.Values; i++)
1041                 {
1042                     /* Attempt to get the value */
1043                     Status = ZwEnumerateValueKey(CardListHandle,
1044                                                  i,
1045                                                  KeyValuePartialInformation,
1046                                                  PartialValueInfo,
1047                                                  sizeof(PartialKeyBuffer),
1048                                                  &ResultLength);
1049                     if (!NT_SUCCESS(Status))
1050                     {
1051                         /* Something went wrong, stop the search */
1052                         break;
1053                     }
1054 
1055                     /* Make sure it is correctly sized */
1056                     if (PartialValueInfo->DataLength == sizeof(PCI_CARD_DESCRIPTOR))
1057                     {
1058                         /* Sure is, copy it over */
1059                         *CardDescriptor = *(PPCI_CARD_DESCRIPTOR)
1060                                            PartialValueInfo->Data;
1061 
1062                         /* One more Card List entry */
1063                         ElementCount++;
1064 
1065                         /* Move to the next descriptor */
1066                         CardDescriptor = (CardDescriptor + 1);
1067                     }
1068                 }
1069             }
1070         }
1071 
1072         /* Close the Card List key */
1073         ZwClose(CardListHandle);
1074     }
1075     else
1076     {
1077        /* No key, no Card List */
1078        PciRegistryInfo = NULL;
1079     }
1080 
1081     /* Check if we failed to get the full structure */
1082     if (!PciRegistryInfo)
1083     {
1084         /* Just allocate the basic structure then */
1085         PciRegistryInfo = ExAllocatePoolWithTag(NonPagedPool,
1086                                                 sizeof(PCI_REGISTRY_INFO_INTERNAL),
1087                                                 TAG_HAL);
1088         if (!PciRegistryInfo) return NULL;
1089     }
1090 
1091     /* Save the info we got */
1092     PciRegistryInfo->MajorRevision = PciRegInfo->MajorRevision;
1093     PciRegistryInfo->MinorRevision = PciRegInfo->MinorRevision;
1094     PciRegistryInfo->NoBuses = PciRegInfo->NoBuses;
1095     PciRegistryInfo->HardwareMechanism = PciRegInfo->HardwareMechanism;
1096     PciRegistryInfo->ElementCount = ElementCount;
1097 
1098     /* Return it */
1099     return PciRegistryInfo;
1100 #else
1101     return NULL;
1102 #endif
1103 }
1104 
1105 CODE_SEG("INIT")
1106 VOID
1107 NTAPI
1108 HalpInitializePciStubs(VOID)
1109 {
1110     PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo;
1111     UCHAR PciType;
1112     PPCIPBUSDATA BusData = (PPCIPBUSDATA)HalpFakePciBusHandler.BusData;
1113     ULONG i;
1114     PCI_SLOT_NUMBER j;
1115     ULONG VendorId = 0;
1116     ULONG MaxPciBusNumber;
1117 
1118     /* Query registry information */
1119     PciRegistryInfo = HalpQueryPciRegistryInfo();
1120     if (!PciRegistryInfo)
1121     {
1122         /* Assume type 1 */
1123         PciType = 1;
1124 
1125         /* Force a manual bus scan later */
1126         MaxPciBusNumber = MAXULONG;
1127     }
1128     else
1129     {
1130         /* Get the PCI type */
1131         PciType = PciRegistryInfo->HardwareMechanism & 0xF;
1132 
1133         /* Get MaxPciBusNumber and make it 0-based */
1134         MaxPciBusNumber = PciRegistryInfo->NoBuses - 1;
1135 
1136         /* Free the info structure */
1137         ExFreePoolWithTag(PciRegistryInfo, TAG_HAL);
1138     }
1139 
1140     /* Initialize the PCI lock */
1141     KeInitializeSpinLock(&HalpPCIConfigLock);
1142 
1143     /* Check the type of PCI bus */
1144     switch (PciType)
1145     {
1146         /* Type 1 PCI Bus */
1147         case 1:
1148 
1149             /* Copy the Type 1 handler data */
1150             RtlCopyMemory(&PCIConfigHandler,
1151                           &PCIConfigHandlerType1,
1152                           sizeof(PCIConfigHandler));
1153 
1154             /* Set correct I/O Ports */
1155             BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT;
1156             BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT;
1157             break;
1158 
1159         /* Type 2 PCI Bus */
1160         case 2:
1161 
1162             /* Copy the Type 2 handler data */
1163             RtlCopyMemory(&PCIConfigHandler,
1164                           &PCIConfigHandlerType2,
1165                           sizeof (PCIConfigHandler));
1166 
1167             /* Set correct I/O Ports */
1168             BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT;
1169             BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT;
1170             BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE;
1171 
1172             /* Only 16 devices supported, not 32 */
1173             BusData->MaxDevice = 16;
1174             break;
1175 
1176         default:
1177 
1178             /* Invalid type */
1179             DbgPrint("HAL: Unknown PCI type\n");
1180     }
1181 
1182     /* Run a forced bus scan if needed */
1183     if (MaxPciBusNumber == MAXULONG)
1184     {
1185         /* Initialize the max bus number to 0xFF */
1186         HalpMaxPciBus = 0xFF;
1187 
1188         /* Initialize the counter */
1189         MaxPciBusNumber = 0;
1190 
1191         /* Loop all possible buses */
1192         for (i = 0; i < HalpMaxPciBus; i++)
1193         {
1194             /* Loop all devices */
1195             for (j.u.AsULONG = 0; j.u.AsULONG < BusData->MaxDevice; j.u.AsULONG++)
1196             {
1197                 /* Query the interface */
1198                 if (HaliPciInterfaceReadConfig(NULL,
1199                                                i,
1200                                                j,
1201                                                &VendorId,
1202                                                0,
1203                                                sizeof(ULONG)))
1204                 {
1205                     /* Validate the vendor ID */
1206                     if ((VendorId & 0xFFFF) != PCI_INVALID_VENDORID)
1207                     {
1208                         /* Set this as the maximum ID */
1209                         MaxPciBusNumber = i;
1210                         break;
1211                     }
1212                 }
1213             }
1214         }
1215     }
1216 
1217     /* Set the real max bus number */
1218     HalpMaxPciBus = MaxPciBusNumber;
1219 
1220     /* We're done */
1221     HalpPCIConfigInitialized = TRUE;
1222 }
1223 
1224 /* EOF */
1225 
1226