--- /dev/null
+/** @file\r
+Module Layer Device I/O on top of PCI Root Bridge I/O (Segment 0)\r
+\r
+Device I/O is on list of deprecated protocols for UEFI 2.0 and later.\r
+This module module layers Device I/O on top of PCI Root Bridge I/O (Segment 0)\r
+ Use if:\r
+ There are no R8.x modules present that produces Device I/O\r
+ EFI drivers included that consume Device I/O\r
+ Platform required to support EFI drivers that consume Device I/O\r
+ Platform required to support EFI applications that consume Device I/O\r
+\r
+Copyright (c) 2008 Intel Corporation. <BR>\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <IndustryStandard/Pci22.h>\r
+#include <Protocol/DeviceIo.h>\r
+#include <Protocol/PciRootBridgeIo.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DevicePathLib.h>\r
+\r
+\r
+/**\r
+ Perform reading memory mapped I/O space of device.\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The destination buffer to store results.\r
+\r
+ @retval EFI_SUCCESS The data was read from the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoMemRead (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+\r
+/**\r
+ Perform writing memory mapped I/O space of device.\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The source buffer of data to be written.\r
+\r
+ @retval EFI_SUCCESS The data was written to the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoMemWrite (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+/**\r
+ Perform reading I/O space of device.\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The destination buffer to store results.\r
+\r
+ @retval EFI_SUCCESS The data was read from the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoIoRead (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+/**\r
+ Perform writing I/O space of device.\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The source buffer of data to be written.\r
+\r
+ @retval EFI_SUCCESS The data was written to the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoIoWrite (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+/**\r
+ Perform reading PCI configuration space of device\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The destination buffer to store results.\r
+\r
+ @retval EFI_SUCCESS The data was read from the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoPciRead (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+/**\r
+ Perform writing PCI configuration space of device.\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The source buffer of data to be written.\r
+\r
+ @retval EFI_SUCCESS The data was written to the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoPciWrite (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+;\r
+\r
+/**\r
+ Provides an EFI Device Path for a PCI device with the given PCI configuration space address.\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+ @param Address The PCI configuration space address of the device\r
+ whose Device Path is going to be returned.\r
+ @param PciDevicePath A pointer to the pointer for the EFI Device Path\r
+ for PciAddress. Memory for the Device Path is\r
+ allocated from the pool.\r
+\r
+ @retval EFI_SUCCESS The PciDevicePath returns a pointer to a valid EFI\r
+ Device Path.\r
+ @retval EFI_UNSUPPORTED The PciAddress does not map to a valid EFI Device\r
+ Path.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoPciDevicePath (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN UINT64 Address,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **PciDevicePath\r
+ )\r
+;\r
+\r
+/**\r
+ Provides the device-specific addresses needed to access system memory.\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+ @param Operation Indicates if the bus master is going to read or\r
+ write to system memory.\r
+ @param HostAddress The system memory address to map to the device.\r
+ @param NumberOfBytes On input the number of bytes to map. On output the\r
+ number of bytes that were mapped.\r
+ @param DeviceAddress The resulting map address for the bus master\r
+ device to use to access the hosts HostAddress.\r
+ @param Mapping A resulting value to pass to Unmap().\r
+\r
+ @retval EFI_SUCCESS The range was mapped for the returned\r
+ NumberOfBytes.\r
+ @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.\r
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common\r
+ buffer.\r
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested\r
+ address.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoMap (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_OPERATION_TYPE Operation,\r
+ IN EFI_PHYSICAL_ADDRESS *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+;\r
+\r
+/**\r
+ Completes the Map() operation and releases any corresponding resources.\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+ @retval EFI_SUCCESS The range was unmapped.\r
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system\r
+ memory.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoUnmap (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN VOID *Mapping\r
+ )\r
+;\r
+\r
+/**\r
+ Allocates pages that are suitable for an EFIBusMasterCommonBuffer mapping.\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+ @param Type The type allocation to perform.\r
+ @param MemoryType The type of memory to allocate,\r
+ EfiBootServicesData or EfiRuntimeServicesData.\r
+ @param Pages The number of pages to allocate.\r
+ @param PhysicalAddress A pointer to store the base address of the\r
+ allocated range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were allocated.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
+ @retval EFI_INVALID_PARAMETER The requested memory type is invalid.\r
+ @retval EFI_UNSUPPORTED The requested PhysicalAddress is not supported on\r
+ this platform.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoAllocateBuffer (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN Pages,\r
+ IN OUT EFI_PHYSICAL_ADDRESS *PhysicalAddress\r
+ )\r
+;\r
+\r
+/**\r
+ Flushes any posted write data to the device.\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+\r
+ @retval EFI_SUCCESS The buffers were flushed.\r
+ @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoFlush (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This\r
+ )\r
+;\r
+\r
+/**\r
+ Frees pages that were allocated with AllocateBuffer().\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+ @param Pages The number of pages to free.\r
+ @param HostAddress The base address of the range to free.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were freed.\r
+ @retval EFI_NOT_FOUND The requested memory pages were not allocated with\r
+ AllocateBuffer().\r
+ @retval EFI_INVALID_PARAMETER HostAddress is not page aligned or Pages is\r
+ invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoFreeBuffer (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN UINTN Pages,\r
+ IN EFI_PHYSICAL_ADDRESS HostAddress\r
+ )\r
+;\r
+\r
+\r
+#define DEVICE_IO_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('D', 'e', 'I', 'O')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ EFI_DEVICE_IO_PROTOCOL DeviceIo;\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ UINT16 PrimaryBus;\r
+ UINT16 SubordinateBus;\r
+} DEVICE_IO_PRIVATE_DATA;\r
+\r
+#define DEVICE_IO_PRIVATE_DATA_FROM_THIS(a) CR (a, DEVICE_IO_PRIVATE_DATA, DeviceIo, DEVICE_IO_PRIVATE_DATA_SIGNATURE)\r
+\r
+#define MAX_COMMON_BUFFER 0x00000000FFFFFFFF\r
+\r
+\r
+EFI_EVENT mPciRootBridgeIoRegistration;\r
+\r
+//\r
+// Device Io Volume Protocol template\r
+//\r
+DEVICE_IO_PRIVATE_DATA gDeviceIoPrivateDataTemplate = {\r
+ DEVICE_IO_PRIVATE_DATA_SIGNATURE,\r
+ {\r
+ {\r
+ DeviceIoMemRead,\r
+ DeviceIoMemWrite\r
+ },\r
+ {\r
+ DeviceIoIoRead,\r
+ DeviceIoIoWrite \r
+ },\r
+ {\r
+ DeviceIoPciRead,\r
+ DeviceIoPciWrite, \r
+ },\r
+ DeviceIoMap,\r
+ DeviceIoPciDevicePath,\r
+ DeviceIoUnmap,\r
+ DeviceIoAllocateBuffer,\r
+ DeviceIoFlush,\r
+ DeviceIoFreeBuffer\r
+ },\r
+ NULL, // PciRootBridgeIo\r
+ NULL, // DevicePath\r
+ 0, // PrimaryBus\r
+ 255 // SubordinateBus\r
+};\r
+\r
+VOID\r
+EFIAPI\r
+PciRootBridgeIoNotificationEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+ EFI_HANDLE Handle;\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+ EFI_DEVICE_IO_PROTOCOL *DeviceIo;\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+\r
+ while (TRUE) {\r
+ BufferSize = sizeof (Handle);\r
+ Status = gBS->LocateHandle (\r
+ ByRegisterNotify,\r
+ &gEfiPciRootBridgeIoProtocolGuid,\r
+ mPciRootBridgeIoRegistration,\r
+ &BufferSize,\r
+ &Handle\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Exit Path of While Loop....\r
+ //\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Skip this handle if the Device Io Protocol is already installed\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ Handle,\r
+ &gEfiDeviceIoProtocolGuid,\r
+ (VOID **)&DeviceIo\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Retrieve the Pci Root Bridge IO Protocol\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ Handle,\r
+ &gEfiPciRootBridgeIoProtocolGuid,\r
+ (VOID **)&PciRootBridgeIo\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // We only install Device IO for PCI bus in Segment 0\r
+ //\r
+ if (PciRootBridgeIo->SegmentNumber != 0) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Allocate private data structure\r
+ //\r
+ Private = AllocateCopyPool (sizeof (DEVICE_IO_PRIVATE_DATA), &gDeviceIoPrivateDataTemplate);\r
+ if (Private == NULL) {\r
+ continue;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (\r
+ Handle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID **) &Private->DevicePath\r
+ );\r
+\r
+ //\r
+ // Install Device Io onto same handle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Handle,\r
+ &gEfiDeviceIoProtocolGuid,\r
+ &Private->DeviceIo,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+}\r
+\r
+/**\r
+ The user Entry Point for DXE driver. The user code starts with this function\r
+ as the real entry point for the image goes into a library that calls this \r
+ function.\r
+\r
+ @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
+ @param[in] SystemTable A pointer to the EFI System Table.\r
+ \r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval other Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeDeviceIo (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EfiCreateProtocolNotifyEvent (\r
+ &gEfiPciRootBridgeIoProtocolGuid,\r
+ TPL_CALLBACK,\r
+ PciRootBridgeIoNotificationEvent,\r
+ NULL,\r
+ &mPciRootBridgeIoRegistration\r
+ );\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Perform reading memory mapped I/O space of device.\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The destination buffer to store results.\r
+\r
+ @retval EFI_SUCCESS The data was read from the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoMemRead (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+\r
+ Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Width > MMIO_COPY_UINT64) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (Width >= MMIO_COPY_UINT8) {\r
+ Width = Width - MMIO_COPY_UINT8;\r
+ Status = Private->PciRootBridgeIo->CopyMem (\r
+ Private->PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ (UINT64) (UINTN) Buffer,\r
+ Address,\r
+ Count\r
+ );\r
+ } else {\r
+ Status = Private->PciRootBridgeIo->Mem.Read (\r
+ Private->PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+\r
+\r
+/**\r
+ Perform writing memory mapped I/O space of device.\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The source buffer of data to be written.\r
+\r
+ @retval EFI_SUCCESS The data was written to the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoMemWrite (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+\r
+ Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Width > MMIO_COPY_UINT64) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (Width >= MMIO_COPY_UINT8) {\r
+ Width = Width - MMIO_COPY_UINT8;\r
+ Status = Private->PciRootBridgeIo->CopyMem (\r
+ Private->PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Address,\r
+ (UINT64) (UINTN) Buffer,\r
+ Count\r
+ );\r
+ } else {\r
+ Status = Private->PciRootBridgeIo->Mem.Write (\r
+ Private->PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Perform reading I/O space of device.\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The destination buffer to store results.\r
+\r
+ @retval EFI_SUCCESS The data was read from the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoIoRead (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+\r
+ Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Width >= MMIO_COPY_UINT8) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = Private->PciRootBridgeIo->Io.Read (\r
+ Private->PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Perform writing I/O space of device.\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The source buffer of data to be written.\r
+\r
+ @retval EFI_SUCCESS The data was written to the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoIoWrite (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+\r
+ Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Width >= MMIO_COPY_UINT8) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = Private->PciRootBridgeIo->Io.Write (\r
+ Private->PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Perform reading PCI configuration space of device\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The destination buffer to store results.\r
+\r
+ @retval EFI_SUCCESS The data was read from the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoPciRead (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+\r
+ Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Width < 0 || Width >= MMIO_COPY_UINT8) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = Private->PciRootBridgeIo->Pci.Read (\r
+ Private->PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Perform writing PCI configuration space of device.\r
+\r
+ @param This A pointer to EFI_DEVICE_IO protocol instance.\r
+ @param Width Width of I/O operations.\r
+ @param Address The base address of I/O operations.\r
+ @param Count The number of I/O operations to perform. Bytes\r
+ moves is Width size * Count, starting at Address.\r
+ @param Buffer The source buffer of data to be written.\r
+\r
+ @retval EFI_SUCCESS The data was written to the device.\r
+ @retval EFI_INVALID_PARAMETER Width is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of\r
+ resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoPciWrite (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_WIDTH Width,\r
+ IN UINT64 Address,\r
+ IN UINTN Count,\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+\r
+ Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Width < 0 || Width >= MMIO_COPY_UINT8) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = Private->PciRootBridgeIo->Pci.Write (\r
+ Private->PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
+ Address,\r
+ Count,\r
+ Buffer\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Append a PCI device path node to another device path.\r
+\r
+ @param Private A pointer to DEVICE_IO_PRIVATE_DATA instance.\r
+ @param Bus PCI bus number of the device.\r
+ @param Device PCI device number of the device.\r
+ @param Function PCI function number of the device.\r
+ @param DevicePath Original device path which will be appended a PCI\r
+ device path node.\r
+ @param BridgePrimaryBus Primary bus number of the bridge.\r
+ @param BridgeSubordinateBus Subordinate bus number of the bridge.\r
+\r
+ @return Pointer to the appended PCI device path.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+AppendPciDevicePath (\r
+ IN DEVICE_IO_PRIVATE_DATA *Private,\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Function,\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ IN OUT UINT16 *BridgePrimaryBus,\r
+ IN OUT UINT16 *BridgeSubordinateBus\r
+ )\r
+{\r
+ UINT16 ThisBus;\r
+ UINT8 ThisDevice;\r
+ UINT8 ThisFunc;\r
+ UINT64 Address;\r
+ PCI_TYPE01 PciBridge;\r
+ PCI_TYPE01 *PciPtr;\r
+ EFI_DEVICE_PATH_PROTOCOL *ReturnDevicePath;\r
+ PCI_DEVICE_PATH PciNode;\r
+\r
+ PciPtr = &PciBridge;\r
+ for (ThisBus = *BridgePrimaryBus; ThisBus <= *BridgeSubordinateBus; ThisBus++) {\r
+ for (ThisDevice = 0; ThisDevice <= PCI_MAX_DEVICE; ThisDevice++) {\r
+ for (ThisFunc = 0; ThisFunc <= PCI_MAX_FUNC; ThisFunc++) {\r
+ Address = EFI_PCI_ADDRESS (ThisBus, ThisDevice, ThisFunc, 0);\r
+ ZeroMem (PciPtr, sizeof (PCI_TYPE01));\r
+ Private->DeviceIo.Pci.Read (\r
+ &Private->DeviceIo,\r
+ IO_UINT32,\r
+ Address,\r
+ 1,\r
+ &(PciPtr->Hdr.VendorId)\r
+ );\r
+ if ((PciPtr->Hdr.VendorId == 0xffff) && (ThisFunc == 0)) {\r
+ break;\r
+ }\r
+ if (PciPtr->Hdr.VendorId == 0xffff) {\r
+ continue;\r
+ } else {\r
+ Private->DeviceIo.Pci.Read (\r
+ &Private->DeviceIo,\r
+ IO_UINT32,\r
+ Address,\r
+ sizeof (PCI_TYPE01) / sizeof (UINT32),\r
+ PciPtr\r
+ );\r
+ if (IS_PCI_BRIDGE (PciPtr)) {\r
+ if (Bus >= PciPtr->Bridge.SecondaryBus && Bus <= PciPtr->Bridge.SubordinateBus) {\r
+\r
+ PciNode.Header.Type = HARDWARE_DEVICE_PATH;\r
+ PciNode.Header.SubType = HW_PCI_DP;\r
+ SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));\r
+\r
+ PciNode.Device = ThisDevice;\r
+ PciNode.Function = ThisFunc;\r
+ ReturnDevicePath = AppendDevicePathNode (DevicePath, &PciNode.Header);\r
+\r
+ *BridgePrimaryBus = PciPtr->Bridge.SecondaryBus;\r
+ *BridgeSubordinateBus = PciPtr->Bridge.SubordinateBus;\r
+ return ReturnDevicePath;\r
+ }\r
+ }\r
+ if (ThisFunc == 0 && !(PciPtr->Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION)) {\r
+ //\r
+ // Skip sub functions, this is not a multi function device\r
+ //\r
+ ThisFunc = 8;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ ZeroMem (&PciNode, sizeof (PciNode));\r
+ PciNode.Header.Type = HARDWARE_DEVICE_PATH;\r
+ PciNode.Header.SubType = HW_PCI_DP;\r
+ SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));\r
+ PciNode.Device = Device;\r
+ PciNode.Function = Function;\r
+\r
+ ReturnDevicePath = AppendDevicePathNode (DevicePath, &PciNode.Header);\r
+\r
+ *BridgePrimaryBus = 0xffff;\r
+ *BridgeSubordinateBus = 0xffff;\r
+ return ReturnDevicePath;\r
+}\r
+\r
+\r
+/**\r
+ Provides an EFI Device Path for a PCI device with the given PCI configuration space address.\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+ @param Address The PCI configuration space address of the device\r
+ whose Device Path is going to be returned.\r
+ @param PciDevicePath A pointer to the pointer for the EFI Device Path\r
+ for PciAddress. Memory for the Device Path is\r
+ allocated from the pool.\r
+\r
+ @retval EFI_SUCCESS The PciDevicePath returns a pointer to a valid EFI\r
+ Device Path.\r
+ @retval EFI_UNSUPPORTED The PciAddress does not map to a valid EFI Device\r
+ Path.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoPciDevicePath (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN UINT64 Address,\r
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **PciDevicePath\r
+ )\r
+{\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+ UINT16 PrimaryBus;\r
+ UINT16 SubordinateBus;\r
+ UINT8 Bus;\r
+ UINT8 Device;\r
+ UINT8 Func;\r
+\r
+ Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ Bus = (UINT8) (((UINT32) Address >> 24) & 0xff);\r
+ Device = (UINT8) (((UINT32) Address >> 16) & 0xff);\r
+ Func = (UINT8) (((UINT32) Address >> 8) & 0xff);\r
+\r
+ if (Bus < Private->PrimaryBus || Bus > Private->SubordinateBus) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ *PciDevicePath = Private->DevicePath;\r
+ PrimaryBus = Private->PrimaryBus;\r
+ SubordinateBus = Private->SubordinateBus;\r
+ do {\r
+ *PciDevicePath = AppendPciDevicePath (\r
+ Private,\r
+ Bus,\r
+ Device,\r
+ Func,\r
+ *PciDevicePath,\r
+ &PrimaryBus,\r
+ &SubordinateBus\r
+ );\r
+ if (*PciDevicePath == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } while (PrimaryBus != 0xffff);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Provides the device-specific addresses needed to access system memory.\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+ @param Operation Indicates if the bus master is going to read or\r
+ write to system memory.\r
+ @param HostAddress The system memory address to map to the device.\r
+ @param NumberOfBytes On input the number of bytes to map. On output the\r
+ number of bytes that were mapped.\r
+ @param DeviceAddress The resulting map address for the bus master\r
+ device to use to access the hosts HostAddress.\r
+ @param Mapping A resulting value to pass to Unmap().\r
+\r
+ @retval EFI_SUCCESS The range was mapped for the returned\r
+ NumberOfBytes.\r
+ @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.\r
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common\r
+ buffer.\r
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested\r
+ address.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r
+ of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoMap (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_IO_OPERATION_TYPE Operation,\r
+ IN EFI_PHYSICAL_ADDRESS *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+\r
+ Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ if (Operation < 0 || Operation > EfiBusMasterCommonBuffer) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (((UINTN) (*HostAddress) != (*HostAddress)) && Operation == EfiBusMasterCommonBuffer) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Status = Private->PciRootBridgeIo->Map (\r
+ Private->PciRootBridgeIo,\r
+ (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation,\r
+ (VOID *) (UINTN) (*HostAddress),\r
+ NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Completes the Map() operation and releases any corresponding resources.\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+ @retval EFI_SUCCESS The range was unmapped.\r
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system\r
+ memory.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoUnmap (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+\r
+ Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ Status = Private->PciRootBridgeIo->Unmap (\r
+ Private->PciRootBridgeIo,\r
+ Mapping\r
+ );\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Allocates pages that are suitable for an EFIBusMasterCommonBuffer mapping.\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+ @param Type The type allocation to perform.\r
+ @param MemoryType The type of memory to allocate,\r
+ EfiBootServicesData or EfiRuntimeServicesData.\r
+ @param Pages The number of pages to allocate.\r
+ @param PhysicalAddress A pointer to store the base address of the\r
+ allocated range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were allocated.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
+ @retval EFI_INVALID_PARAMETER The requested memory type is invalid.\r
+ @retval EFI_UNSUPPORTED The requested PhysicalAddress is not supported on\r
+ this platform.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoAllocateBuffer (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN Pages,\r
+ IN OUT EFI_PHYSICAL_ADDRESS *PhysicalAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS HostAddress;\r
+\r
+ HostAddress = *PhysicalAddress;\r
+\r
+ if ((MemoryType != EfiBootServicesData) && (MemoryType != EfiRuntimeServicesData)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Type >= MaxAllocateType) || (Type < AllocateAnyPages)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((Type == AllocateAddress) && (HostAddress + EFI_PAGES_TO_SIZE (Pages) - 1 > MAX_COMMON_BUFFER)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if ((AllocateAnyPages == Type) || (AllocateMaxAddress == Type && HostAddress > MAX_COMMON_BUFFER)) {\r
+ Type = AllocateMaxAddress;\r
+ HostAddress = MAX_COMMON_BUFFER;\r
+ }\r
+\r
+ Status = gBS->AllocatePages (\r
+ Type,\r
+ MemoryType,\r
+ Pages,\r
+ &HostAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+\r
+ *PhysicalAddress = HostAddress;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Flushes any posted write data to the device.\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+\r
+ @retval EFI_SUCCESS The buffers were flushed.\r
+ @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware\r
+ error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoFlush (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ DEVICE_IO_PRIVATE_DATA *Private;\r
+\r
+ Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ Status = Private->PciRootBridgeIo->Flush (Private->PciRootBridgeIo);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Frees pages that were allocated with AllocateBuffer().\r
+\r
+ @param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.\r
+ @param Pages The number of pages to free.\r
+ @param HostAddress The base address of the range to free.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were freed.\r
+ @retval EFI_NOT_FOUND The requested memory pages were not allocated with\r
+ AllocateBuffer().\r
+ @retval EFI_INVALID_PARAMETER HostAddress is not page aligned or Pages is\r
+ invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeviceIoFreeBuffer (\r
+ IN EFI_DEVICE_IO_PROTOCOL *This,\r
+ IN UINTN Pages,\r
+ IN EFI_PHYSICAL_ADDRESS HostAddress\r
+ )\r
+{\r
+ if (((HostAddress & EFI_PAGE_MASK) != 0) || (Pages <= 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return gBS->FreePages (HostAddress, Pages);\r
+}\r
+\r