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
PciAcpiFindRsdt(OUT PACPI_BIOS_MULTI_NODE * AcpiMultiNode)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
PciGetAcpiTable(IN ULONG TableCode)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
PciGetIrqRoutingTableFromRegistry(OUT PPCI_IRQ_ROUTING_TABLE * PciRoutingTable)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
PciBuildHackTable(IN HANDLE KeyHandle)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
PciGetDebugPorts(IN HANDLE DebugKey)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
PciDriverUnload(IN PDRIVER_OBJECT DriverObject)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
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)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 | OBJ_KERNEL_HANDLE,
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