/** @file Copyright (c) 2016, Linaro, Ltd. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include /** 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; }