| /** @file | |
| The device path help function. | |
| Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "NvmExpressPei.h" | |
| // | |
| // Template for an Nvm Express Device Path node | |
| // | |
| NVME_NAMESPACE_DEVICE_PATH mNvmeDevicePathNodeTemplate = { | |
| { // Header | |
| MESSAGING_DEVICE_PATH, | |
| MSG_NVME_NAMESPACE_DP, | |
| { | |
| (UINT8)(sizeof (NVME_NAMESPACE_DEVICE_PATH)), | |
| (UINT8)((sizeof (NVME_NAMESPACE_DEVICE_PATH)) >> 8) | |
| } | |
| }, | |
| 0x0, // NamespaceId | |
| 0x0 // NamespaceUuid | |
| }; | |
| // | |
| // Template for an End of entire Device Path node | |
| // | |
| EFI_DEVICE_PATH_PROTOCOL mNvmeEndDevicePathNodeTemplate = { | |
| END_DEVICE_PATH_TYPE, | |
| END_ENTIRE_DEVICE_PATH_SUBTYPE, | |
| { | |
| (UINT8)(sizeof (EFI_DEVICE_PATH_PROTOCOL)), | |
| (UINT8)((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8) | |
| } | |
| }; | |
| /** | |
| Get the size of the current device path instance. | |
| @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL | |
| structure. | |
| @param[out] InstanceSize The size of the current device path instance. | |
| @param[out] EntireDevicePathEnd Indicate whether the instance is the last | |
| one in the device path strucure. | |
| @retval EFI_SUCCESS The size of the current device path instance is fetched. | |
| @retval Others Fails to get the size of the current device path instance. | |
| **/ | |
| EFI_STATUS | |
| GetDevicePathInstanceSize ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| OUT UINTN *InstanceSize, | |
| OUT BOOLEAN *EntireDevicePathEnd | |
| ) | |
| { | |
| EFI_DEVICE_PATH_PROTOCOL *Walker; | |
| if ((DevicePath == NULL) || (InstanceSize == NULL) || (EntireDevicePathEnd == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Find the end of the device path instance | |
| // | |
| Walker = DevicePath; | |
| while (Walker->Type != END_DEVICE_PATH_TYPE) { | |
| Walker = NextDevicePathNode (Walker); | |
| } | |
| // | |
| // Check if 'Walker' points to the end of an entire device path | |
| // | |
| if (Walker->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) { | |
| *EntireDevicePathEnd = TRUE; | |
| } else if (Walker->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) { | |
| *EntireDevicePathEnd = FALSE; | |
| } else { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Compute the size of the device path instance | |
| // | |
| *InstanceSize = ((UINTN)Walker - (UINTN)(DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Check the validity of the device path of a NVM Express host controller. | |
| @param[in] DevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL | |
| structure. | |
| @param[in] DevicePathLength The length of the device path. | |
| @retval EFI_SUCCESS The device path is valid. | |
| @retval EFI_INVALID_PARAMETER The device path is invalid. | |
| **/ | |
| EFI_STATUS | |
| NvmeIsHcDevicePathValid ( | |
| IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, | |
| IN UINTN DevicePathLength | |
| ) | |
| { | |
| EFI_DEVICE_PATH_PROTOCOL *Start; | |
| UINTN Size; | |
| if (DevicePath == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Validate the DevicePathLength is big enough to touch the first node. | |
| // | |
| if (DevicePathLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Start = DevicePath; | |
| while (!(DevicePath->Type == END_DEVICE_PATH_TYPE && | |
| DevicePath->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE)) | |
| { | |
| DevicePath = NextDevicePathNode (DevicePath); | |
| // | |
| // Prevent overflow and invalid zero in the 'Length' field of a device path | |
| // node. | |
| // | |
| if ((UINTN)DevicePath <= (UINTN)Start) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Prevent touching memory beyond given DevicePathLength. | |
| // | |
| if ((UINTN)DevicePath - (UINTN)Start > | |
| DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) | |
| { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| // | |
| // Check if the device path and its size match exactly with each other. | |
| // | |
| Size = ((UINTN)DevicePath - (UINTN)Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL); | |
| if (Size != DevicePathLength) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Build the device path for an Nvm Express device with given namespace identifier | |
| and namespace extended unique identifier. | |
| @param[in] Private A pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA | |
| data structure. | |
| @param[in] NamespaceId The given namespace identifier. | |
| @param[in] NamespaceUuid The given namespace extended unique identifier. | |
| @param[out] DevicePathLength The length of the device path in bytes specified | |
| by DevicePath. | |
| @param[out] DevicePath The device path of Nvm Express device. | |
| @retval EFI_SUCCESS The operation succeeds. | |
| @retval EFI_INVALID_PARAMETER The parameters are invalid. | |
| @retval EFI_OUT_OF_RESOURCES The operation fails due to lack of resources. | |
| **/ | |
| EFI_STATUS | |
| NvmeBuildDevicePath ( | |
| IN PEI_NVME_CONTROLLER_PRIVATE_DATA *Private, | |
| IN UINT32 NamespaceId, | |
| IN UINT64 NamespaceUuid, | |
| OUT UINTN *DevicePathLength, | |
| OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath | |
| ) | |
| { | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker; | |
| NVME_NAMESPACE_DEVICE_PATH *NvmeDeviceNode; | |
| if ((DevicePathLength == NULL) || (DevicePath == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| *DevicePathLength = Private->DevicePathLength + sizeof (NVME_NAMESPACE_DEVICE_PATH); | |
| *DevicePath = AllocatePool (*DevicePathLength); | |
| if (*DevicePath == NULL) { | |
| *DevicePathLength = 0; | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Construct the host controller part device nodes | |
| // | |
| DevicePathWalker = *DevicePath; | |
| CopyMem ( | |
| DevicePathWalker, | |
| Private->DevicePath, | |
| Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL) | |
| ); | |
| // | |
| // Construct the Nvm Express device node | |
| // | |
| DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)DevicePathWalker + | |
| (Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL))); | |
| CopyMem ( | |
| DevicePathWalker, | |
| &mNvmeDevicePathNodeTemplate, | |
| sizeof (mNvmeDevicePathNodeTemplate) | |
| ); | |
| NvmeDeviceNode = (NVME_NAMESPACE_DEVICE_PATH *)DevicePathWalker; | |
| NvmeDeviceNode->NamespaceId = NamespaceId; | |
| NvmeDeviceNode->NamespaceUuid = NamespaceUuid; | |
| // | |
| // Construct the end device node | |
| // | |
| DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)DevicePathWalker + | |
| sizeof (NVME_NAMESPACE_DEVICE_PATH)); | |
| CopyMem ( | |
| DevicePathWalker, | |
| &mNvmeEndDevicePathNodeTemplate, | |
| sizeof (mNvmeEndDevicePathNodeTemplate) | |
| ); | |
| return EFI_SUCCESS; | |
| } |