xref: /reactos/drivers/bus/pcix/init.c (revision 40462c92)
1 /*
2  * PROJECT:         ReactOS PCI Bus Driver
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            drivers/bus/pci/init.c
5  * PURPOSE:         Driver Initialization
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <pci.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
18 BOOLEAN PciRunningDatacenter;
19 PDRIVER_OBJECT PciDriverObject;
20 KEVENT PciGlobalLock;
21 KEVENT PciBusLock;
22 KEVENT PciLegacyDescriptionLock;
23 BOOLEAN PciLockDeviceResources;
24 BOOLEAN PciEnableNativeModeATA;
25 ULONG PciSystemWideHackFlags;
26 PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable;
27 PWATCHDOG_TABLE WdTable;
28 PPCI_HACK_ENTRY PciHackTable;
29 
30 /* FUNCTIONS ******************************************************************/
31 
32 NTSTATUS
33 NTAPI
34 PciAcpiFindRsdt(OUT PACPI_BIOS_MULTI_NODE *AcpiMultiNode)
35 {
36     BOOLEAN Result;
37     NTSTATUS Status;
38     HANDLE KeyHandle, SubKey;
39     ULONG NumberOfBytes, i, Length;
40     PKEY_FULL_INFORMATION FullInfo;
41     PKEY_BASIC_INFORMATION KeyInfo;
42     PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
43     PACPI_BIOS_MULTI_NODE NodeData;
44     UNICODE_STRING ValueName;
45     struct
46     {
47         CM_FULL_RESOURCE_DESCRIPTOR Descriptor;
48         ACPI_BIOS_MULTI_NODE Node;
49     } *Package;
50 
51     /* So we know what to free at the end of the body */
52     ValueInfo = NULL;
53     KeyInfo = NULL;
54     KeyHandle = NULL;
55     FullInfo = NULL;
56     Package = NULL;
57     do
58     {
59         /* Open the ACPI BIOS key */
60         Result = PciOpenKey(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\"
61                             L"System\\MultiFunctionAdapter",
62                             NULL,
63                             KEY_QUERY_VALUE,
64                             &KeyHandle,
65                             &Status);
66         if (!Result) break;
67 
68         /* Query how much space should be allocated for the key information */
69         Status = ZwQueryKey(KeyHandle,
70                             KeyFullInformation,
71                             NULL,
72                             sizeof(ULONG),
73                             &NumberOfBytes);
74         if (Status != STATUS_BUFFER_TOO_SMALL) break;
75 
76         /* Allocate the space required */
77         Status = STATUS_INSUFFICIENT_RESOURCES;
78         FullInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, PCI_POOL_TAG);
79         if ( !FullInfo ) break;
80 
81         /* Now query the key information that's needed */
82         Status = ZwQueryKey(KeyHandle,
83                             KeyFullInformation,
84                             FullInfo,
85                             NumberOfBytes,
86                             &NumberOfBytes);
87         if (!NT_SUCCESS(Status)) break;
88 
89         /* Allocate enough space to hold the value information plus the name */
90         Status = STATUS_INSUFFICIENT_RESOURCES;
91         Length = FullInfo->MaxNameLen + 26;
92         KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
93         if ( !KeyInfo ) break;
94 
95         /* Allocate the value information and name we expect to find */
96         ValueInfo = ExAllocatePoolWithTag(PagedPool,
97                                           sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
98                                           sizeof(L"ACPI BIOS"),
99                                           PCI_POOL_TAG);
100         if (!ValueInfo) break;
101 
102         /* Loop each sub-key */
103         i = 0;
104         while (TRUE)
105         {
106             /* Query each sub-key */
107             Status = ZwEnumerateKey(KeyHandle,
108                                     i++,
109                                     KeyBasicInformation,
110                                     KeyInfo,
111                                     Length,
112                                     &NumberOfBytes);
113             if (Status == STATUS_NO_MORE_ENTRIES) break;
114 
115             /* Null-terminate the keyname, because the kernel does not */
116             KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
117 
118             /* Open this subkey */
119             Result = PciOpenKey(KeyInfo->Name,
120                                 KeyHandle,
121                                 KEY_QUERY_VALUE,
122                                 &SubKey,
123                                 &Status);
124             if (Result)
125             {
126                 /* Query the identifier value for this subkey */
127                 RtlInitUnicodeString(&ValueName, L"Identifier");
128                 Status = ZwQueryValueKey(SubKey,
129                                          &ValueName,
130                                          KeyValuePartialInformation,
131                                          ValueInfo,
132                                          sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
133                                          sizeof(L"ACPI BIOS"),
134                                          &NumberOfBytes);
135                 if (NT_SUCCESS(Status))
136                 {
137                     /* Check if this is the PCI BIOS subkey */
138                     if (!wcsncmp((PWCHAR)ValueInfo->Data,
139                                  L"ACPI BIOS",
140                                  ValueInfo->DataLength))
141                     {
142                         /* It is, proceed to query the PCI IRQ routing table */
143                         Status = PciGetRegistryValue(L"Configuration Data",
144                                                      KeyInfo->Name,
145                                                      KeyHandle,
146                                                      REG_FULL_RESOURCE_DESCRIPTOR,
147                                                      (PVOID*)&Package,
148                                                      &NumberOfBytes);
149                         ZwClose(SubKey);
150                         break;
151                     }
152                 }
153 
154                 /* Close the subkey and try the next one */
155                 ZwClose(SubKey);
156             }
157         }
158 
159         /* Check if we got here because the routing table was found */
160         if (!NT_SUCCESS(Status))
161         {
162             /* This should only fail if we're out of entries */
163             ASSERT(Status == STATUS_NO_MORE_ENTRIES);
164             break;
165         }
166 
167         /* Check if a descriptor was found */
168         if (!Package) break;
169 
170         /* The configuration data is a resource list, and the BIOS node follows */
171         NodeData = &Package->Node;
172 
173         /* How many E820 memory entries are there? */
174         Length = sizeof(ACPI_BIOS_MULTI_NODE) +
175                  (NodeData->Count - 1) * sizeof(ACPI_E820_ENTRY);
176 
177         /* Allocate the buffer needed to copy the information */
178         Status = STATUS_INSUFFICIENT_RESOURCES;
179         *AcpiMultiNode = ExAllocatePoolWithTag(NonPagedPool, Length, PCI_POOL_TAG);
180         if (!*AcpiMultiNode) break;
181 
182         /* Copy the data */
183         RtlCopyMemory(*AcpiMultiNode, NodeData, Length);
184         Status = STATUS_SUCCESS;
185     } while (FALSE);
186 
187     /* Close any opened keys, free temporary allocations, and return status */
188     if (Package) ExFreePoolWithTag(Package, 0);
189     if (ValueInfo) ExFreePoolWithTag(ValueInfo, 0);
190     if (KeyInfo) ExFreePoolWithTag(KeyInfo, 0);
191     if (FullInfo) ExFreePoolWithTag(FullInfo, 0);
192     if (KeyHandle) ZwClose(KeyHandle);
193     return Status;
194 }
195 
196 PVOID
197 NTAPI
198 PciGetAcpiTable(IN ULONG TableCode)
199 {
200     PDESCRIPTION_HEADER Header;
201     PACPI_BIOS_MULTI_NODE AcpiMultiNode;
202     PRSDT Rsdt;
203     PXSDT Xsdt;
204     ULONG EntryCount, TableLength, Offset, CurrentEntry;
205     PVOID TableBuffer, MappedAddress;
206     PHYSICAL_ADDRESS PhysicalAddress;
207     NTSTATUS Status;
208 
209     /* Try to find the RSDT or XSDT */
210     Status = PciAcpiFindRsdt(&AcpiMultiNode);
211     if (!NT_SUCCESS(Status))
212     {
213         /* No ACPI on the machine */
214         DPRINT1("AcpiFindRsdt() Failed!\n");
215         return NULL;
216     }
217 
218     /* Map the RSDT with the minimum size allowed */
219     MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress,
220                                  sizeof(DESCRIPTION_HEADER),
221                                  MmNonCached);
222     Header = MappedAddress;
223     if (!Header) return NULL;
224 
225     /* Check how big the table really is and get rid of the temporary header */
226     TableLength = Header->Length;
227     MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER));
228     Header = NULL;
229 
230     /* Map its true size */
231     MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress,
232                                  TableLength,
233                                  MmNonCached);
234     Rsdt = MappedAddress;
235     Xsdt = MappedAddress;
236     ExFreePoolWithTag(AcpiMultiNode, 0);
237     if (!Rsdt) return NULL;
238 
239     /* Validate the table's signature */
240     if ((Rsdt->Header.Signature != RSDT_SIGNATURE) &&
241         (Rsdt->Header.Signature != XSDT_SIGNATURE))
242     {
243         /* Very bad: crash */
244         HalDisplayString("RSDT table contains invalid signature\r\n");
245         MmUnmapIoSpace(Rsdt, TableLength);
246         return NULL;
247     }
248 
249     /* Smallest RSDT/XSDT is one without table entries */
250     Offset = FIELD_OFFSET(RSDT, Tables);
251     if (Rsdt->Header.Signature == XSDT_SIGNATURE)
252     {
253         /* Figure out total size of table and the offset */
254         TableLength = Xsdt->Header.Length;
255         if (TableLength < Offset) Offset = Xsdt->Header.Length;
256 
257         /* The entries are each 64-bits, so count them */
258         EntryCount = (TableLength - Offset) / sizeof(PHYSICAL_ADDRESS);
259     }
260     else
261     {
262         /* Figure out total size of table and the offset */
263         TableLength = Rsdt->Header.Length;
264         if (TableLength < Offset) Offset = Rsdt->Header.Length;
265 
266         /* The entries are each 32-bits, so count them */
267         EntryCount = (TableLength - Offset) / sizeof(ULONG);
268     }
269 
270     /* Start at the beginning of the array and loop it */
271     for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++)
272     {
273         /* Are we using the XSDT? */
274         if (Rsdt->Header.Signature != XSDT_SIGNATURE)
275         {
276             /* Read the 32-bit physical address */
277             PhysicalAddress.QuadPart = Rsdt->Tables[CurrentEntry];
278         }
279         else
280         {
281             /* Read the 64-bit physical address */
282             PhysicalAddress = Xsdt->Tables[CurrentEntry];
283         }
284 
285         /* Map this table */
286         Header = MmMapIoSpace(PhysicalAddress,
287                               sizeof(DESCRIPTION_HEADER),
288                               MmNonCached);
289         if (!Header) break;
290 
291         /* Check if this is the table that's being asked for */
292         if (Header->Signature == TableCode)
293         {
294             /* Allocate a buffer for it */
295             TableBuffer = ExAllocatePoolWithTag(PagedPool,
296                                                 Header->Length,
297                                                 PCI_POOL_TAG);
298             if (!TableBuffer) break;
299 
300             /* Copy the table into the buffer */
301             RtlCopyMemory(TableBuffer, Header, Header->Length);
302         }
303 
304         /* Done with this table, keep going */
305         MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER));
306     }
307 
308     if (Header) MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER));
309     return NULL;
310 }
311 
312 NTSTATUS
313 NTAPI
314 PciGetIrqRoutingTableFromRegistry(OUT PPCI_IRQ_ROUTING_TABLE *PciRoutingTable)
315 {
316     BOOLEAN Result;
317     NTSTATUS Status;
318     HANDLE KeyHandle, SubKey;
319     ULONG NumberOfBytes, i, Length;
320     PKEY_FULL_INFORMATION FullInfo;
321     PKEY_BASIC_INFORMATION KeyInfo;
322     PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
323     UNICODE_STRING ValueName;
324     struct
325     {
326         CM_FULL_RESOURCE_DESCRIPTOR Descriptor;
327         PCI_IRQ_ROUTING_TABLE Table;
328     } *Package;
329 
330     /* So we know what to free at the end of the body */
331     Package = NULL;
332     ValueInfo = NULL;
333     KeyInfo = NULL;
334     KeyHandle = NULL;
335     FullInfo = NULL;
336     do
337     {
338         /* Open the BIOS key */
339         Result = PciOpenKey(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\"
340                             L"System\\MultiFunctionAdapter",
341                             NULL,
342                             KEY_QUERY_VALUE,
343                             &KeyHandle,
344                             &Status);
345         if (!Result) break;
346 
347         /* Query how much space should be allocated for the key information */
348         Status = ZwQueryKey(KeyHandle,
349                             KeyFullInformation,
350                             NULL,
351                             sizeof(ULONG),
352                             &NumberOfBytes);
353         if (Status != STATUS_BUFFER_TOO_SMALL) break;
354 
355         /* Allocate the space required */
356         Status = STATUS_INSUFFICIENT_RESOURCES;
357         FullInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, PCI_POOL_TAG);
358         if ( !FullInfo ) break;
359 
360         /* Now query the key information that's needed */
361         Status = ZwQueryKey(KeyHandle,
362                             KeyFullInformation,
363                             FullInfo,
364                             NumberOfBytes,
365                             &NumberOfBytes);
366         if (!NT_SUCCESS(Status)) break;
367 
368         /* Allocate enough space to hold the value information plus the name */
369         Status = STATUS_INSUFFICIENT_RESOURCES;
370         Length = FullInfo->MaxNameLen + 26;
371         KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG);
372         if (!KeyInfo) break;
373 
374         /* Allocate the value information and name we expect to find */
375         ValueInfo = ExAllocatePoolWithTag(PagedPool,
376                                           sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
377                                           sizeof(L"PCI BIOS"),
378                                           PCI_POOL_TAG);
379         if (!ValueInfo) break;
380 
381         /* Loop each sub-key */
382         i = 0;
383         while (TRUE)
384         {
385             /* Query each sub-key */
386             Status = ZwEnumerateKey(KeyHandle,
387                                     i++,
388                                     KeyBasicInformation,
389                                     KeyInfo,
390                                     Length,
391                                     &NumberOfBytes);
392             if (Status == STATUS_NO_MORE_ENTRIES) break;
393 
394             /* Null-terminate the keyname, because the kernel does not */
395             KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
396 
397             /* Open this subkey */
398             Result = PciOpenKey(KeyInfo->Name,
399                                 KeyHandle,
400                                 KEY_QUERY_VALUE,
401                                 &SubKey,
402                                 &Status);
403             if (Result)
404             {
405                 /* Query the identifier value for this subkey */
406                 RtlInitUnicodeString(&ValueName, L"Identifier");
407                 Status = ZwQueryValueKey(SubKey,
408                                          &ValueName,
409                                          KeyValuePartialInformation,
410                                          ValueInfo,
411                                          sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
412                                          sizeof(L"PCI BIOS"),
413                                          &NumberOfBytes);
414                 if (NT_SUCCESS(Status))
415                 {
416                     /* Check if this is the PCI BIOS subkey */
417                     if (!wcsncmp((PWCHAR)ValueInfo->Data,
418                                  L"PCI BIOS",
419                                  ValueInfo->DataLength))
420                     {
421                         /* It is, proceed to query the PCI IRQ routing table */
422                         Status = PciGetRegistryValue(L"Configuration Data",
423                                                      L"RealModeIrqRoutingTable"
424                                                      L"\\0",
425                                                      SubKey,
426                                                      REG_FULL_RESOURCE_DESCRIPTOR,
427                                                      (PVOID*)&Package,
428                                                      &NumberOfBytes);
429                         ZwClose(SubKey);
430                         break;
431                     }
432                 }
433 
434                 /* Close the subkey and try the next one */
435                 ZwClose(SubKey);
436             }
437         }
438 
439         /* Check if we got here because the routing table was found */
440         if (!NT_SUCCESS(Status)) break;
441 
442         /* Check if a descriptor was found */
443         if (!Package) break;
444 
445         /* Make sure the buffer is large enough to hold the table */
446         if ((NumberOfBytes < sizeof(*Package)) ||
447             (Package->Table.TableSize >
448              (NumberOfBytes - sizeof(CM_FULL_RESOURCE_DESCRIPTOR))))
449         {
450             /* Invalid package size */
451             Status = STATUS_UNSUCCESSFUL;
452             break;
453         }
454 
455         /* Allocate space for the table */
456         Status = STATUS_INSUFFICIENT_RESOURCES;
457         *PciRoutingTable = ExAllocatePoolWithTag(PagedPool,
458                                                  NumberOfBytes,
459                                                  PCI_POOL_TAG);
460         if (!*PciRoutingTable) break;
461 
462         /* Copy the registry data */
463         RtlCopyMemory(*PciRoutingTable,
464                       &Package->Table,
465                       NumberOfBytes - sizeof(CM_FULL_RESOURCE_DESCRIPTOR));
466         Status = STATUS_SUCCESS;
467     } while (FALSE);
468 
469     /* Close any opened keys, free temporary allocations, and return status */
470     if (Package) ExFreePoolWithTag(Package, 0);
471     if (ValueInfo) ExFreePoolWithTag(ValueInfo, 0);
472     if (KeyInfo) ExFreePoolWithTag(KeyInfo, 0);
473     if (FullInfo) ExFreePoolWithTag(FullInfo, 0);
474     if (KeyHandle) ZwClose(KeyHandle);
475     return Status;
476 }
477 
478 NTSTATUS
479 NTAPI
480 PciBuildHackTable(IN HANDLE KeyHandle)
481 {
482     PKEY_FULL_INFORMATION FullInfo;
483     ULONG i, HackCount;
484     PKEY_VALUE_FULL_INFORMATION ValueInfo;
485     PPCI_HACK_ENTRY Entry;
486     NTSTATUS Status;
487     ULONG NameLength, ResultLength;
488     ULONGLONG HackFlags;
489 
490     /* So we know what to free at the end of the body */
491     FullInfo = NULL;
492     ValueInfo = NULL;
493     do
494     {
495         /* Query the size required for full key information */
496         Status = ZwQueryKey(KeyHandle,
497                             KeyFullInformation,
498                             NULL,
499                             0,
500                             &ResultLength);
501         if (Status != STATUS_BUFFER_TOO_SMALL) break;
502 
503         /* Allocate the space required to hold the full key information */
504         Status = STATUS_INSUFFICIENT_RESOURCES;
505         ASSERT(ResultLength > 0);
506         FullInfo = ExAllocatePoolWithTag(PagedPool, ResultLength, PCI_POOL_TAG);
507         if (!FullInfo) break;
508 
509         /* Go ahead and query the key information */
510         Status = ZwQueryKey(KeyHandle,
511                             KeyFullInformation,
512                             FullInfo,
513                             ResultLength,
514                             &ResultLength);
515         if (!NT_SUCCESS(Status)) break;
516 
517         /* The only piece of information that's needed is the count of values */
518         HackCount = FullInfo->Values;
519 
520         /* Free the structure now */
521         ExFreePoolWithTag(FullInfo, 0);
522         FullInfo = NULL;
523 
524         /* Allocate the hack table, now that the number of entries is known */
525         Status = STATUS_INSUFFICIENT_RESOURCES;
526         ResultLength = sizeof(PCI_HACK_ENTRY) * HackCount;
527         PciHackTable = ExAllocatePoolWithTag(NonPagedPool,
528                                              ResultLength +
529                                              sizeof(PCI_HACK_ENTRY),
530                                              PCI_POOL_TAG);
531         if (!PciHackTable) break;
532 
533         /* Allocate the space needed to hold the full value information */
534         ValueInfo = ExAllocatePoolWithTag(NonPagedPool,
535                                           sizeof(KEY_VALUE_FULL_INFORMATION) +
536                                           PCI_HACK_ENTRY_FULL_SIZE,
537                                           PCI_POOL_TAG);
538         if (!PciHackTable) break;
539 
540         /* Loop each value in the registry */
541         Entry = &PciHackTable[0];
542         for (i = 0; i < HackCount; i++)
543         {
544             /* Get the entry for this value */
545             Entry = &PciHackTable[i];
546 
547             /* Query the value in the key */
548             Status = ZwEnumerateValueKey(KeyHandle,
549                                          i,
550                                          KeyValueFullInformation,
551                                          ValueInfo,
552                                          sizeof(KEY_VALUE_FULL_INFORMATION) +
553                                          PCI_HACK_ENTRY_FULL_SIZE,
554                                          &ResultLength);
555             if (!NT_SUCCESS(Status))
556             {
557                 /* Check why the call failed */
558                 if ((Status != STATUS_BUFFER_OVERFLOW) &&
559                     (Status != STATUS_BUFFER_TOO_SMALL))
560                 {
561                     /* The call failed due to an unknown error, bail out */
562                     break;
563                 }
564 
565                 /* The data seems to mismatch, try the next key in the list */
566                 continue;
567             }
568 
569             /* Check if the value data matches what's expected */
570             if ((ValueInfo->Type != REG_BINARY) ||
571                 (ValueInfo->DataLength != sizeof(ULONGLONG)))
572             {
573                 /* It doesn't, try the next key in the list */
574                 continue;
575             }
576 
577             /* Read the actual hack flags */
578             HackFlags = *(PULONGLONG)((ULONG_PTR)ValueInfo +
579                                       ValueInfo->DataOffset);
580 
581             /* Check what kind of errata entry this is, based on the name */
582             NameLength = ValueInfo->NameLength;
583             if ((NameLength != PCI_HACK_ENTRY_SIZE) &&
584                 (NameLength != PCI_HACK_ENTRY_REV_SIZE) &&
585                 (NameLength != PCI_HACK_ENTRY_SUBSYS_SIZE) &&
586                 (NameLength != PCI_HACK_ENTRY_FULL_SIZE))
587             {
588                 /* It's an invalid entry, skip it */
589                 DPRINT1("Skipping hack entry with invalid length name\n");
590                 continue;
591             }
592 
593             /* Initialize the entry */
594             RtlZeroMemory(Entry, sizeof(PCI_HACK_ENTRY));
595 
596             /* Get the vendor and device data */
597             if (!(PciStringToUSHORT(ValueInfo->Name, &Entry->VendorID)) ||
598                 !(PciStringToUSHORT(&ValueInfo->Name[4], &Entry->DeviceID)))
599             {
600                 /* This failed, try the next entry */
601                 continue;
602             }
603 
604             /* Check if the entry contains subsystem information */
605             if ((NameLength == PCI_HACK_ENTRY_SUBSYS_SIZE) ||
606                 (NameLength == PCI_HACK_ENTRY_FULL_SIZE))
607             {
608                 /* Get the data */
609                 if (!(PciStringToUSHORT(&ValueInfo->Name[8],
610                                         &Entry->SubVendorID)) ||
611                     !(PciStringToUSHORT(&ValueInfo->Name[12],
612                                         &Entry->SubSystemID)))
613                   {
614                       /* This failed, try the next entry */
615                       continue;
616                   }
617 
618                   /* Save the fact this entry has finer controls */
619                   Entry->Flags |= PCI_HACK_HAS_SUBSYSTEM_INFO;
620              }
621 
622              /* Check if the entry contains revision information */
623              if ((NameLength == PCI_HACK_ENTRY_REV_SIZE) ||
624                  (NameLength == PCI_HACK_ENTRY_FULL_SIZE))
625              {
626                  /* Get the data */
627                  if (!PciStringToUSHORT(&ValueInfo->Name[16],
628                                         &Entry->RevisionID))
629                  {
630                      /* This failed, try the next entry */
631                      continue;
632                  }
633 
634                  /* Save the fact this entry has finer controls */
635                  Entry->Flags |= PCI_HACK_HAS_REVISION_INFO;
636              }
637 
638             /* Only the last entry should have this set */
639             ASSERT(Entry->VendorID != PCI_INVALID_VENDORID);
640 
641             /* Save the actual hack flags */
642             Entry->HackFlags = HackFlags;
643 
644             /* Print out for the debugger's sake */
645 #ifdef HACK_DEBUG
646             DPRINT1("Adding Hack entry for Vendor:0x%04x Device:0x%04x ",
647                     Entry->VendorID, Entry->DeviceID);
648             if (Entry->Flags & PCI_HACK_HAS_SUBSYSTEM_INFO)
649                 DbgPrint("SybSys:0x%04x SubVendor:0x%04x ",
650                          Entry->SubSystemID, Entry->SubVendorID);
651             if (Entry->Flags & PCI_HACK_HAS_REVISION_INFO)
652                 DbgPrint("Revision:0x%02x", Entry->RevisionID);
653             DbgPrint(" = 0x%I64x\n", Entry->HackFlags);
654 #endif
655         }
656 
657         /* Bail out in case of failure */
658         if (!NT_SUCCESS(Status)) break;
659 
660         /* Terminate the table with an invalid entry */
661         ASSERT(Entry < (PciHackTable + HackCount + 1));
662         Entry->VendorID = PCI_INVALID_VENDORID;
663 
664         /* Success path, free the temporary registry data */
665         ExFreePoolWithTag(ValueInfo, 0);
666         return STATUS_SUCCESS;
667     } while (TRUE);
668 
669     /* Failure path, free temporary allocations and return failure code */
670     ASSERT(!NT_SUCCESS(Status));
671     if (FullInfo) ExFreePool(FullInfo);
672     if (ValueInfo) ExFreePool(ValueInfo);
673     if (PciHackTable) ExFreePool(PciHackTable);
674     return Status;
675 }
676 
677 NTSTATUS
678 NTAPI
679 PciGetDebugPorts(IN HANDLE DebugKey)
680 {
681     UNREFERENCED_PARAMETER(DebugKey);
682     /* This function is not yet implemented */
683     UNIMPLEMENTED_DBGBREAK();
684     return STATUS_SUCCESS;
685 }
686 
687 DRIVER_UNLOAD PciDriverUnload;
688 
689 VOID
690 NTAPI
691 PciDriverUnload(IN PDRIVER_OBJECT DriverObject)
692 {
693     UNREFERENCED_PARAMETER(DriverObject);
694     /* This function is not yet implemented */
695     UNIMPLEMENTED_DBGBREAK("PCI: Unload\n");
696 }
697 
698 NTSTATUS
699 NTAPI
700 DriverEntry(IN PDRIVER_OBJECT DriverObject,
701             IN PUNICODE_STRING RegistryPath)
702 {
703     HANDLE KeyHandle, ParametersKey, DebugKey, ControlSetKey;
704     BOOLEAN Result;
705     OBJECT_ATTRIBUTES ObjectAttributes;
706     ULONG ResultLength;
707     PULONG Value;
708     PWCHAR StartOptions;
709     UNICODE_STRING OptionString, PciLockString;
710     NTSTATUS Status;
711     DPRINT1("PCI: DriverEntry!\n");
712 
713     /* Setup initial loop variables */
714     KeyHandle = NULL;
715     ParametersKey = NULL;
716     DebugKey = NULL;
717     ControlSetKey = NULL;
718     do
719     {
720         /* Remember our object so we can get it to it later */
721         PciDriverObject = DriverObject;
722 
723         /* Setup the IRP dispatcher */
724         DriverObject->MajorFunction[IRP_MJ_POWER] = PciDispatchIrp;
725         DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PciDispatchIrp;
726         DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PciDispatchIrp;
727         DriverObject->MajorFunction[IRP_MJ_PNP] = PciDispatchIrp;
728         DriverObject->DriverUnload = PciDriverUnload;
729 
730         /* This is how we'll detect a new PCI bus */
731         DriverObject->DriverExtension->AddDevice = PciAddDevice;
732 
733         /* Open the PCI key */
734         InitializeObjectAttributes(&ObjectAttributes,
735                                    RegistryPath,
736                                    OBJ_CASE_INSENSITIVE,
737                                    NULL,
738                                    NULL);
739         Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes);
740         if (!NT_SUCCESS(Status)) break;
741 
742         /* Open the Parameters subkey */
743         Result = PciOpenKey(L"Parameters",
744                             KeyHandle,
745                             KEY_QUERY_VALUE,
746                             &ParametersKey,
747                             &Status);
748         //if (!Result) break;
749 
750         /* Build the list of all known PCI erratas */
751         Status = PciBuildHackTable(ParametersKey);
752         //if (!NT_SUCCESS(Status)) break;
753 
754         /* Open the debug key, if it exists */
755         Result = PciOpenKey(L"Debug",
756                             KeyHandle,
757                             KEY_QUERY_VALUE,
758                             &DebugKey,
759                             &Status);
760         if (Result)
761         {
762             /* There are PCI debug devices, go discover them */
763             Status = PciGetDebugPorts(DebugKey);
764             if (!NT_SUCCESS(Status)) break;
765         }
766 
767         /* Initialize the synchronization locks */
768         KeInitializeEvent(&PciGlobalLock, SynchronizationEvent, TRUE);
769         KeInitializeEvent(&PciBusLock, SynchronizationEvent, TRUE);
770         KeInitializeEvent(&PciLegacyDescriptionLock, SynchronizationEvent, TRUE);
771 
772         /* Open the control set key */
773         Result = PciOpenKey(L"\\Registry\\Machine\\System\\CurrentControlSet",
774                             NULL,
775                             KEY_QUERY_VALUE,
776                             &ControlSetKey,
777                             &Status);
778         if (!Result) break;
779 
780         /* Read the command line */
781         Status = PciGetRegistryValue(L"SystemStartOptions",
782                                      L"Control",
783                                      ControlSetKey,
784                                      REG_SZ,
785                                      (PVOID*)&StartOptions,
786                                      &ResultLength);
787         if (NT_SUCCESS(Status))
788         {
789             /* Initialize the command-line as a string */
790             OptionString.Buffer = StartOptions;
791             OptionString.MaximumLength = OptionString.Length = ResultLength;
792 
793             /* Check if the command-line has the PCILOCK argument */
794             RtlInitUnicodeString(&PciLockString, L"PCILOCK");
795             if (PciUnicodeStringStrStr(&OptionString, &PciLockString, TRUE))
796             {
797                 /* The PCI Bus driver will keep the BIOS-assigned resources */
798                 PciLockDeviceResources = TRUE;
799             }
800 
801             /* This data isn't needed anymore */
802             ExFreePoolWithTag(StartOptions, 0);
803         }
804 
805         /* The PCILOCK feature can also be enabled per-system in the registry */
806         Status = PciGetRegistryValue(L"PCILock",
807                                      L"Control\\BiosInfo\\PCI",
808                                      ControlSetKey,
809                                      REG_DWORD,
810                                      (PVOID*)&Value,
811                                      &ResultLength);
812         if (NT_SUCCESS(Status))
813         {
814             /* Read the value it's been set to. This overrides /PCILOCK */
815             if (ResultLength == sizeof(ULONG)) PciLockDeviceResources = *Value;
816             ExFreePoolWithTag(Value, 0);
817         }
818 
819         /* The system can have global PCI erratas in the registry */
820         Status = PciGetRegistryValue(L"HackFlags",
821                                      L"Control\\PnP\\PCI",
822                                      ControlSetKey,
823                                      REG_DWORD,
824                                      (PVOID*)&Value,
825                                      &ResultLength);
826         if (NT_SUCCESS(Status))
827         {
828             /* Read them in */
829             if (ResultLength == sizeof(ULONG)) PciSystemWideHackFlags = *Value;
830             ExFreePoolWithTag(Value, 0);
831         }
832 
833         /* Check if the system should allow native ATA support */
834         Status = PciGetRegistryValue(L"EnableNativeModeATA",
835                                      L"Control\\PnP\\PCI",
836                                      ControlSetKey,
837                                      REG_DWORD,
838                                      (PVOID*)&Value,
839                                      &ResultLength);
840         if (NT_SUCCESS(Status))
841         {
842             /* This key is typically set by drivers, but users can force it */
843             if (ResultLength == sizeof(ULONG)) PciEnableNativeModeATA = *Value;
844             ExFreePoolWithTag(Value, 0);
845         }
846 
847         /* Build the range lists for all the excluded resource areas */
848         Status = PciBuildDefaultExclusionLists();
849         if (!NT_SUCCESS(Status)) break;
850 
851         /* Read the PCI IRQ Routing Table that the loader put in the registry */
852         PciGetIrqRoutingTableFromRegistry(&PciIrqRoutingTable);
853 
854         /* Take over the HAL's default PCI Bus Handler routines */
855         PciHookHal();
856 
857         /* Initialize verification of PCI BIOS and devices, if requested */
858         PciVerifierInit(DriverObject);
859 
860         /* Check if this is a Datacenter SKU, which impacts IRQ alignment */
861         PciRunningDatacenter = PciIsDatacenter();
862         if (PciRunningDatacenter) DPRINT1("PCI running on datacenter build\n");
863 
864         /* Check if the system has an ACPI Hardware Watchdog Timer */
865         //WdTable = PciGetAcpiTable(WDRT_SIGNATURE);
866         Status = STATUS_SUCCESS;
867     } while (FALSE);
868 
869     /* Close all opened keys, return driver status to PnP Manager */
870     if (KeyHandle) ZwClose(KeyHandle);
871     if (ControlSetKey) ZwClose(ControlSetKey);
872     if (ParametersKey) ZwClose(ParametersKey);
873     if (DebugKey) ZwClose(DebugKey);
874     return Status;
875 }
876 
877 /* EOF */
878