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