blob: 307045be70ea0da13513eb5cc6677b260a4f8214 [file] [log] [blame]
/** @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;
}