//\r
LIST_ENTRY mPciDevicePool;\r
\r
+/**\r
+ Disable Bus Master Enable bit in all devices in the list.\r
+\r
+ @param Devices A device list.\r
+**/\r
+VOID\r
+DisableBmeOnTree (\r
+ IN LIST_ENTRY *Devices\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ PCI_IO_DEVICE *PciIoDevice;\r
+ UINT16 Command;\r
+\r
+ for ( Link = GetFirstNode (Devices)\r
+ ; !IsNull (Devices, Link)\r
+ ; Link = GetNextNode (Devices, Link)\r
+ ) {\r
+ PciIoDevice = PCI_IO_DEVICE_FROM_LINK (Link);\r
+ //\r
+ // Turn off all children's Bus Master, if any\r
+ //\r
+ DisableBmeOnTree (&PciIoDevice->ChildList);\r
+\r
+ //\r
+ // If this is a device that supports BME, disable BME on this device.\r
+ //\r
+ if ((PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) != 0) {\r
+ PCI_READ_COMMAND_REGISTER(PciIoDevice, &Command);\r
+ if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {\r
+ Command &= ~EFI_PCI_COMMAND_BUS_MASTER;\r
+ PCI_SET_COMMAND_REGISTER (PciIoDevice, Command);\r
+ DEBUG ((\r
+ DEBUG_INFO," %02x %02x %02x %04x\n",\r
+ PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber,\r
+ Command\r
+ ));\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Exit Boot Services Event notification handler.\r
+\r
+ Disable Bus Master on any that were enabled during BDS.\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ @param[in] Context Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnExitBootServices (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "PciBus: Disable Bus Master of all devices...\n"\r
+ " Bus# Device# Function# NewCommand\n"\r
+ ));\r
+ DisableBmeOnTree(&mPciDevicePool);\r
+}\r
+\r
/**\r
Initialize the PCI devices pool.\r
\r
VOID\r
)\r
{\r
+ EFI_EVENT ExitBootServicesEvent;\r
+ EFI_STATUS Status;\r
+\r
InitializeListHead (&mPciDevicePool);\r
+\r
+ //\r
+ // DisableBME on ExitBootServices should be synchonized with any IOMMU ExitBootServices routine.\r
+ // DisableBME should be run before the IOMMU protections are disabled.\r
+ // One way to do this is to ensure that the IOMMU ExitBootServices callback runs at TPL_CALLBACK.\r
+ //\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ OnExitBootServices,\r
+ NULL,\r
+ &gEfiEventExitBootServicesGuid,\r
+ &ExitBootServicesEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "PciBus: Unable to hook ExitBootServices event - %r\n", Status));\r
+ }\r
}\r
\r
/**\r