summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c531
1 files changed, 531 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
new file mode 100644
index 00000000..29b83b15
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/SourceLevelDebugPkg/Library/DebugCommunicationLibUsb3/DebugCommunicationLibUsb3Dxe.c
@@ -0,0 +1,531 @@
+/** @file
+ Debug Port Library implementation based on usb3 debug port.
+
+ Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <PiDxe.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/IoMmu.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+#include "DebugCommunicationLibUsb3Internal.h"
+
+GUID gUsb3DbgGuid = USB3_DBG_GUID;
+
+USB3_DEBUG_PORT_HANDLE mUsb3Instance = {USB3DBG_UNINITIALIZED};
+EFI_PHYSICAL_ADDRESS mUsb3InstanceAddr = 0;
+EFI_PHYSICAL_ADDRESS *mUsb3InstanceAddrPtr = NULL;
+EFI_PCI_IO_PROTOCOL *mUsb3PciIo = NULL;
+
+/**
+ Creates a named event that can be signaled.
+
+ This function creates an event using NotifyTpl, NotifyFunction.
+ If Name is NULL, then ASSERT().
+ If NotifyTpl is not a legal TPL value, then ASSERT().
+ If NotifyFunction is NULL, then ASSERT().
+
+ @param Name Supplies the GUID name of the event.
+ @param NotifyTpl Supplies the task priority level of the event notifications.
+ @param NotifyFunction Supplies the function to notify when the event is signaled.
+ @param Event A pointer to the event created.
+
+ @retval EFI_SUCCESS A named event was created.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resource to create the named event.
+
+**/
+EFI_STATUS
+EFIAPI
+Usb3NamedEventListen (
+ IN CONST EFI_GUID *Name,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction,
+ IN EFI_EVENT *Event
+ )
+{
+ EFI_STATUS Status;
+ VOID *RegistrationLocal;
+
+ ASSERT (Name != NULL);
+ ASSERT (NotifyFunction != NULL);
+ ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
+
+ //
+ // Create event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ NotifyTpl,
+ NotifyFunction,
+ NULL,
+ Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for an installation of protocol interface
+ //
+ Status = gBS->RegisterProtocolNotify (
+ (EFI_GUID *) Name,
+ *Event,
+ &RegistrationLocal
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ USB3 map one DMA buffer.
+
+ @param PciIo Pointer to PciIo for USB3 debug port.
+ @param Address DMA buffer address to be mapped.
+ @param NumberOfBytes Number of bytes to be mapped.
+
+**/
+VOID
+Usb3MapOneDmaBuffer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN NumberOfBytes
+ )
+{
+ EFI_STATUS Status;
+ VOID *HostAddress;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+ VOID *Mapping;
+
+ HostAddress = (VOID *) (UINTN) Address;
+ Status = PciIo->Map (
+ PciIo,
+ EfiPciIoOperationBusMasterCommonBuffer,
+ HostAddress,
+ &NumberOfBytes,
+ &DeviceAddress,
+ &Mapping
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (DeviceAddress == ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress));
+}
+
+/**
+ USB3 map DMA buffers.
+
+ @param Instance Pointer to USB3 debug port instance.
+ @param PciIo Pointer to PciIo for USB3 debug port.
+
+**/
+VOID
+Usb3MapDmaBuffers (
+ IN USB3_DEBUG_PORT_HANDLE *Instance,
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->UrbIn.Data,
+ XHCI_DEBUG_DEVICE_MAX_PACKET_SIZE * 2 + USB3_DEBUG_PORT_WRITE_MAX_PACKET_SIZE
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->TransferRingIn.RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->TransferRingOut.RingSeg0,
+ sizeof (TRB_TEMPLATE) * TR_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->EventRing.EventRingSeg0,
+ sizeof (TRB_TEMPLATE) * EVENT_RING_TRB_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->EventRing.ERSTBase,
+ sizeof (EVENT_RING_SEG_TABLE_ENTRY) * ERST_NUMBER
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ Instance->DebugCapabilityContext,
+ sizeof (XHC_DC_CONTEXT)
+ );
+
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ ((XHC_DC_CONTEXT *) (UINTN) Instance->DebugCapabilityContext)->DbcInfoContext.String0DescAddress,
+ STRING0_DESC_LEN + MANU_DESC_LEN + PRODUCT_DESC_LEN + SERIAL_DESC_LEN
+ );
+}
+
+/**
+ Invoke a notification event
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+Usb3DxeSmmReadyToLockNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *Instance;
+
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+
+ Instance->InNotify = TRUE;
+
+ //
+ // For the case that the USB3 debug port instance and DMA buffers are
+ // from PEI HOB with IOMMU enabled.
+ // Reinitialize USB3 debug port with granted DXE DMA buffer accessible
+ // by SMM environment.
+ //
+ InitializeUsbDebugHardware (Instance);
+
+ //
+ // Wait some time for host to be ready after re-initialization.
+ //
+ MicroSecondDelay (1000000);
+
+ Instance->InNotify = FALSE;
+ gBS->CloseEvent (Event);
+}
+
+/**
+ USB3 get IOMMU protocol.
+
+ @return Pointer to IOMMU protocol.
+
+**/
+EDKII_IOMMU_PROTOCOL *
+Usb3GetIoMmu (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_IOMMU_PROTOCOL *IoMmu;
+
+ IoMmu = NULL;
+ Status = gBS->LocateProtocol (
+ &gEdkiiIoMmuProtocolGuid,
+ NULL,
+ (VOID **) &IoMmu
+ );
+ if (!EFI_ERROR (Status) && (IoMmu != NULL)) {
+ return IoMmu;
+ }
+
+ return NULL;
+}
+
+/**
+ Invoke a notification event
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+Usb3PciIoNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN PciIoHandleCount;
+ EFI_HANDLE *PciIoHandleBuffer;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN PciSegment;
+ UINTN PciBusNumber;
+ UINTN PciDeviceNumber;
+ UINTN PciFunctionNumber;
+ UINT32 PciAddress;
+ USB3_DEBUG_PORT_HANDLE *Instance;
+ EFI_EVENT SmmReadyToLockEvent;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &PciIoHandleCount,
+ &PciIoHandleBuffer
+ );
+ if (!EFI_ERROR (Status) &&
+ (PciIoHandleBuffer != NULL) &&
+ (PciIoHandleCount != 0)) {
+ for (Index = 0; Index < PciIoHandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ PciIoHandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBusNumber, &PciDeviceNumber, &PciFunctionNumber);
+ ASSERT_EFI_ERROR (Status);
+ PciAddress = (UINT32) ((PciBusNumber << 20) | (PciDeviceNumber << 15) | (PciFunctionNumber << 12));
+ if (PciAddress == PcdGet32(PcdUsbXhciPciAddress)) {
+ //
+ // Found the PciIo for USB3 debug port.
+ //
+ DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__));
+ if (Usb3GetIoMmu () != NULL) {
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+ if (Instance->Ready) {
+ Instance->InNotify = TRUE;
+ Usb3MapDmaBuffers (Instance, PciIo);
+ Instance->InNotify = FALSE;
+
+ if (Instance->FromHob) {
+ mUsb3PciIo = PciIo;
+ Usb3NamedEventListen (
+ &gEfiDxeSmmReadyToLockProtocolGuid,
+ TPL_NOTIFY,
+ Usb3DxeSmmReadyToLockNotify,
+ &SmmReadyToLockEvent
+ );
+ }
+ }
+ }
+ gBS->CloseEvent (Event);
+ break;
+ }
+ }
+
+ gBS->FreePool (PciIoHandleBuffer);
+ }
+}
+
+/**
+ Return USB3 debug instance address pointer.
+
+**/
+EFI_PHYSICAL_ADDRESS *
+GetUsb3DebugPortInstanceAddrPtr (
+ VOID
+ )
+{
+ if (mUsb3InstanceAddrPtr == NULL) {
+ //
+ // Use the local variables temporarily.
+ //
+ mUsb3InstanceAddr = (EFI_PHYSICAL_ADDRESS) (UINTN) &mUsb3Instance;
+ mUsb3InstanceAddrPtr = &mUsb3InstanceAddr;
+ }
+ return mUsb3InstanceAddrPtr;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param PciIo Pointer to PciIo for USB3 debug port.
+ @param Pages The number of pages to allocate.
+ @param Address A pointer to store the base system memory address of the
+ allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+Usb3AllocateDmaBuffer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN Pages,
+ OUT VOID **Address
+ )
+{
+ EFI_STATUS Status;
+
+ *Address = NULL;
+ Status = PciIo->AllocateBuffer (
+ PciIo,
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ Pages,
+ Address,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+ Usb3MapOneDmaBuffer (
+ PciIo,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) *Address,
+ EFI_PAGES_TO_SIZE (Pages)
+ );
+ }
+ return Status;
+}
+
+/**
+ Allocate aligned memory for XHC's usage.
+
+ @param BufferSize The size, in bytes, of the Buffer.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID*
+AllocateAlignBuffer (
+ IN UINTN BufferSize
+ )
+{
+ EFI_PHYSICAL_ADDRESS TmpAddr;
+ EFI_STATUS Status;
+ VOID *Buf;
+
+ Buf = NULL;
+
+ if (gBS != NULL) {
+ if (mUsb3PciIo != NULL) {
+ Usb3AllocateDmaBuffer (
+ mUsb3PciIo,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Buf
+ );
+ } else {
+ TmpAddr = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &TmpAddr
+ );
+ if (!EFI_ERROR (Status)) {
+ Buf = (VOID *) (UINTN) TmpAddr;
+ }
+ }
+ }
+
+ return Buf;
+}
+
+/**
+ The constructor function initialize USB3 debug port.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugCommunicationUsb3DxeConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_PHYSICAL_ADDRESS *AddrPtr;
+ USB3_DEBUG_PORT_HANDLE *Instance;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ Status = EfiGetSystemConfigurationTable (&gUsb3DbgGuid, (VOID **) &AddrPtr);
+ if (EFI_ERROR (Status) || (AddrPtr == NULL)) {
+ //
+ // Instead of using local variables, install system configuration table for
+ // the local instance and the buffer to save instance address pointer.
+ //
+ Address = SIZE_4GB;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE)),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ AddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) Address;
+ ZeroMem (AddrPtr, sizeof (EFI_PHYSICAL_ADDRESS) + sizeof (USB3_DEBUG_PORT_HANDLE));
+ Instance = (USB3_DEBUG_PORT_HANDLE *) (AddrPtr + 1);
+ CopyMem (Instance, &mUsb3Instance, sizeof (USB3_DEBUG_PORT_HANDLE));
+ *AddrPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) Instance;
+
+ Status = gBS->InstallConfigurationTable (&gUsb3DbgGuid, AddrPtr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (mUsb3InstanceAddrPtr != NULL) {
+ *AddrPtr = *mUsb3InstanceAddrPtr;
+ }
+ mUsb3InstanceAddrPtr = AddrPtr;
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+
+ if (Instance->PciIoEvent == 0) {
+ Status = Usb3NamedEventListen (
+ &gEfiPciIoProtocolGuid,
+ TPL_NOTIFY,
+ Usb3PciIoNotify,
+ &Event
+ );
+ if (!EFI_ERROR (Status)) {
+ Instance->PciIoEvent = (EFI_PHYSICAL_ADDRESS) (UINTN) Event;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+DebugCommunicationUsb3DxeDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ USB3_DEBUG_PORT_HANDLE *Instance;
+
+ Instance = GetUsb3DebugPortInstance ();
+ ASSERT (Instance != NULL);
+
+ if (Instance->PciIoEvent != 0) {
+ //
+ // Close the event created.
+ //
+ gBS->CloseEvent ((EFI_EVENT) (UINTN) Instance->PciIoEvent);
+ Instance->PciIoEvent = 0;
+ }
+ return EFI_SUCCESS;
+}
+