/** @file The device path help function. Copyright (c) 2019, Intel Corporation. All rights reserved.
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; }