| /** @file | |
| Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <PiDxe.h> | |
| #include <Guid/NonDiscoverableDevice.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/DevicePathLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/NonDiscoverableDeviceRegistrationLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Protocol/DevicePath.h> | |
| #include <Protocol/NonDiscoverableDevice.h> | |
| /** | |
| Get Guid form the type of non-discoverable device. | |
| @param[in] Type The type of non-discoverable device. | |
| @retval Return the Guid. | |
| **/ | |
| STATIC | |
| CONST EFI_GUID * | |
| GetGuidFromType ( | |
| IN NON_DISCOVERABLE_DEVICE_TYPE Type | |
| ) | |
| { | |
| switch (Type) { | |
| case NonDiscoverableDeviceTypeAhci: | |
| return &gEdkiiNonDiscoverableAhciDeviceGuid; | |
| case NonDiscoverableDeviceTypeAmba: | |
| return &gEdkiiNonDiscoverableAmbaDeviceGuid; | |
| case NonDiscoverableDeviceTypeEhci: | |
| return &gEdkiiNonDiscoverableEhciDeviceGuid; | |
| case NonDiscoverableDeviceTypeNvme: | |
| return &gEdkiiNonDiscoverableNvmeDeviceGuid; | |
| case NonDiscoverableDeviceTypeOhci: | |
| return &gEdkiiNonDiscoverableOhciDeviceGuid; | |
| case NonDiscoverableDeviceTypeSdhci: | |
| return &gEdkiiNonDiscoverableSdhciDeviceGuid; | |
| case NonDiscoverableDeviceTypeUfs: | |
| return &gEdkiiNonDiscoverableUfsDeviceGuid; | |
| case NonDiscoverableDeviceTypeUhci: | |
| return &gEdkiiNonDiscoverableUhciDeviceGuid; | |
| case NonDiscoverableDeviceTypeXhci: | |
| return &gEdkiiNonDiscoverableXhciDeviceGuid; | |
| default: | |
| return NULL; | |
| } | |
| } | |
| #pragma pack (1) | |
| typedef struct { | |
| VENDOR_DEVICE_PATH Vendor; | |
| UINT64 BaseAddress; | |
| UINT8 ResourceType; | |
| EFI_DEVICE_PATH_PROTOCOL End; | |
| } NON_DISCOVERABLE_DEVICE_PATH; | |
| #pragma pack () | |
| /** | |
| Register a non-discoverable MMIO device. | |
| @param[in] Type The type of non-discoverable device | |
| @param[in] DmaType Whether the device is DMA coherent | |
| @param[in] InitFunc Initialization routine to be invoked when | |
| the device is enabled | |
| @param[in,out] Handle The handle onto which to install the | |
| non-discoverable device protocol. | |
| If Handle is NULL or *Handle is NULL, a | |
| new handle will be allocated. | |
| @param[in] NumMmioResources The number of UINTN base/size pairs that | |
| follow, each describing an MMIO region | |
| owned by the device | |
| @param[in] ... The variable argument list which contains the | |
| info about MmioResources. | |
| @retval EFI_SUCCESS The registration succeeded. | |
| @retval EFI_INVALID_PARAMETER An invalid argument was given | |
| @retval Other The registration failed. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| RegisterNonDiscoverableMmioDevice ( | |
| IN NON_DISCOVERABLE_DEVICE_TYPE Type, | |
| IN NON_DISCOVERABLE_DEVICE_DMA_TYPE DmaType, | |
| IN NON_DISCOVERABLE_DEVICE_INIT InitFunc, | |
| IN OUT EFI_HANDLE *Handle OPTIONAL, | |
| IN UINTN NumMmioResources, | |
| ... | |
| ) | |
| { | |
| NON_DISCOVERABLE_DEVICE *Device; | |
| NON_DISCOVERABLE_DEVICE_PATH *DevicePath; | |
| EFI_HANDLE LocalHandle; | |
| EFI_STATUS Status; | |
| UINTN AllocSize; | |
| UINTN Index; | |
| VA_LIST Args; | |
| EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc; | |
| EFI_ACPI_END_TAG_DESCRIPTOR *End; | |
| UINTN Base, Size; | |
| if ((Type >= NonDiscoverableDeviceTypeMax) || | |
| (DmaType >= NonDiscoverableDeviceDmaTypeMax) || | |
| (NumMmioResources == 0)) | |
| { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Handle == NULL) { | |
| Handle = &LocalHandle; | |
| LocalHandle = NULL; | |
| } | |
| AllocSize = sizeof *Device + | |
| NumMmioResources * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + | |
| sizeof (EFI_ACPI_END_TAG_DESCRIPTOR); | |
| Device = (NON_DISCOVERABLE_DEVICE *)AllocateZeroPool (AllocSize); | |
| if (Device == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| Device->Type = GetGuidFromType (Type); | |
| ASSERT (Device->Type != NULL); | |
| Device->DmaType = DmaType; | |
| Device->Initialize = InitFunc; | |
| Device->Resources = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(Device + 1); | |
| VA_START (Args, NumMmioResources); | |
| for (Index = 0; Index < NumMmioResources; Index++) { | |
| Desc = &Device->Resources[Index]; | |
| Base = VA_ARG (Args, UINTN); | |
| Size = VA_ARG (Args, UINTN); | |
| Desc->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR; | |
| Desc->Len = sizeof *Desc - 3; | |
| Desc->AddrRangeMin = Base; | |
| Desc->AddrLen = Size; | |
| Desc->AddrRangeMax = Base + Size - 1; | |
| Desc->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM; | |
| Desc->AddrSpaceGranularity = ((EFI_PHYSICAL_ADDRESS)Base + Size > SIZE_4GB) ? 64 : 32; | |
| Desc->AddrTranslationOffset = 0; | |
| } | |
| VA_END (Args); | |
| End = (EFI_ACPI_END_TAG_DESCRIPTOR *)&Device->Resources[NumMmioResources]; | |
| End->Desc = ACPI_END_TAG_DESCRIPTOR; | |
| End->Checksum = 0; | |
| DevicePath = (NON_DISCOVERABLE_DEVICE_PATH *)CreateDeviceNode ( | |
| HARDWARE_DEVICE_PATH, | |
| HW_VENDOR_DP, | |
| sizeof (*DevicePath) | |
| ); | |
| if (DevicePath == NULL) { | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto FreeDevice; | |
| } | |
| CopyGuid (&DevicePath->Vendor.Guid, &gEdkiiNonDiscoverableDeviceProtocolGuid); | |
| // | |
| // Use the base address and type of the first region to | |
| // make the device path unique | |
| // | |
| DevicePath->BaseAddress = Device->Resources[0].AddrRangeMin; | |
| DevicePath->ResourceType = Device->Resources[0].ResType; | |
| SetDevicePathNodeLength ( | |
| &DevicePath->Vendor, | |
| sizeof (*DevicePath) - sizeof (DevicePath->End) | |
| ); | |
| SetDevicePathEndNode (&DevicePath->End); | |
| Status = gBS->InstallMultipleProtocolInterfaces ( | |
| Handle, | |
| &gEdkiiNonDiscoverableDeviceProtocolGuid, | |
| Device, | |
| &gEfiDevicePathProtocolGuid, | |
| DevicePath, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto FreeDevicePath; | |
| } | |
| return EFI_SUCCESS; | |
| FreeDevicePath: | |
| FreePool (DevicePath); | |
| FreeDevice: | |
| FreePool (Device); | |
| return Status; | |
| } |