]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
MdeModulePkg/NvmExpressPei: Add logic to produce SSC PPI
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / NvmExpressPei / DevicePath.c
diff --git a/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c b/MdeModulePkg/Bus/Pci/NvmExpressPei/DevicePath.c
new file mode 100644 (file)
index 0000000..fd30ad5
--- /dev/null
@@ -0,0 +1,231 @@
+/** @file\r
+  The device path help function.\r
+\r
+  Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions\r
+  of the BSD License which accompanies this distribution.  The\r
+  full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "NvmExpressPei.h"\r
+\r
+//\r
+// Template for an Nvm Express Device Path node\r
+//\r
+NVME_NAMESPACE_DEVICE_PATH  mNvmeDevicePathNodeTemplate = {\r
+  {        // Header\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_NVME_NAMESPACE_DP,\r
+    {\r
+      (UINT8) (sizeof (NVME_NAMESPACE_DEVICE_PATH)),\r
+      (UINT8) ((sizeof (NVME_NAMESPACE_DEVICE_PATH)) >> 8)\r
+    }\r
+  },\r
+  0x0,     // NamespaceId\r
+  0x0      // NamespaceUuid\r
+};\r
+\r
+//\r
+// Template for an End of entire Device Path node\r
+//\r
+EFI_DEVICE_PATH_PROTOCOL  mNvmeEndDevicePathNodeTemplate = {\r
+  END_DEVICE_PATH_TYPE,\r
+  END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+  {\r
+    (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),\r
+    (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)\r
+  }\r
+};\r
+\r
+/**\r
+  Returns the 16-bit Length field of a device path node.\r
+\r
+  Returns the 16-bit Length field of the device path node specified by Node.\r
+  Node is not required to be aligned on a 16-bit boundary, so it is recommended\r
+  that a function such as ReadUnaligned16() be used to extract the contents of\r
+  the Length field.\r
+\r
+  If Node is NULL, then ASSERT().\r
+\r
+  @param  Node      A pointer to a device path node data structure.\r
+\r
+  @return The 16-bit Length field of the device path node specified by Node.\r
+\r
+**/\r
+UINTN\r
+DevicePathNodeLength (\r
+  IN CONST VOID  *Node\r
+  )\r
+{\r
+  ASSERT (Node != NULL);\r
+  return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);\r
+}\r
+\r
+/**\r
+  Returns a pointer to the next node in a device path.\r
+\r
+  If Node is NULL, then ASSERT().\r
+\r
+  @param  Node    A pointer to a device path node data structure.\r
+\r
+  @return a pointer to the device path node that follows the device path node\r
+  specified by Node.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+NextDevicePathNode (\r
+  IN CONST VOID  *Node\r
+  )\r
+{\r
+  ASSERT (Node != NULL);\r
+  return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + DevicePathNodeLength(Node));\r
+}\r
+\r
+/**\r
+  Check the validity of the device path of a NVM Express host controller.\r
+\r
+  @param[in] DevicePath          A pointer to the EFI_DEVICE_PATH_PROTOCOL\r
+                                 structure.\r
+  @param[in] DevicePathLength    The length of the device path.\r
+\r
+  @retval EFI_SUCCESS              The device path is valid.\r
+  @retval EFI_INVALID_PARAMETER    The device path is invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeIsHcDevicePathValid (\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *DevicePath,\r
+  IN UINTN                       DevicePathLength\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL    *Start;\r
+  UINTN                       Size;\r
+\r
+  if (DevicePath == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Validate the DevicePathLength is big enough to touch the first node.\r
+  //\r
+  if (DevicePathLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Start = DevicePath;\r
+  while (!(DevicePath->Type == END_DEVICE_PATH_TYPE &&\r
+           DevicePath->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE)) {\r
+    DevicePath = NextDevicePathNode (DevicePath);\r
+\r
+    //\r
+    // Prevent overflow and invalid zero in the 'Length' field of a device path\r
+    // node.\r
+    //\r
+    if ((UINTN) DevicePath <= (UINTN) Start) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // Prevent touching memory beyond given DevicePathLength.\r
+    //\r
+    if ((UINTN) DevicePath - (UINTN) Start >\r
+        DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check if the device path and its size match exactly with each other.\r
+  //\r
+  Size = ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
+  if (Size != DevicePathLength) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Build the device path for an Nvm Express device with given namespace identifier\r
+  and namespace extended unique identifier.\r
+\r
+  @param[in]  Private              A pointer to the PEI_NVME_CONTROLLER_PRIVATE_DATA\r
+                                   data structure.\r
+  @param[in]  NamespaceId          The given namespace identifier.\r
+  @param[in]  NamespaceUuid        The given namespace extended unique identifier.\r
+  @param[out] DevicePathLength     The length of the device path in bytes specified\r
+                                   by DevicePath.\r
+  @param[out] DevicePath           The device path of Nvm Express device.\r
+\r
+  @retval EFI_SUCCESS              The operation succeeds.\r
+  @retval EFI_INVALID_PARAMETER    The parameters are invalid.\r
+  @retval EFI_OUT_OF_RESOURCES     The operation fails due to lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+NvmeBuildDevicePath (\r
+  IN  PEI_NVME_CONTROLLER_PRIVATE_DATA    *Private,\r
+  IN  UINT32                              NamespaceId,\r
+  IN  UINT64                              NamespaceUuid,\r
+  OUT UINTN                               *DevicePathLength,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath\r
+  )\r
+{\r
+  EFI_DEVICE_PATH_PROTOCOL      *DevicePathWalker;\r
+  NVME_NAMESPACE_DEVICE_PATH    *NvmeDeviceNode;\r
+\r
+  if (DevicePathLength == NULL || DevicePath == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *DevicePathLength = Private->DevicePathLength + sizeof (NVME_NAMESPACE_DEVICE_PATH);\r
+  *DevicePath       = AllocatePool (*DevicePathLength);\r
+  if (*DevicePath == NULL) {\r
+    *DevicePathLength = 0;\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Construct the host controller part device nodes\r
+  //\r
+  DevicePathWalker = *DevicePath;\r
+  CopyMem (\r
+    DevicePathWalker,\r
+    Private->DevicePath,\r
+    Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)\r
+    );\r
+\r
+  //\r
+  // Construct the Nvm Express device node\r
+  //\r
+  DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +\r
+                     (Private->DevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)));\r
+  CopyMem (\r
+    DevicePathWalker,\r
+    &mNvmeDevicePathNodeTemplate,\r
+    sizeof (mNvmeDevicePathNodeTemplate)\r
+    );\r
+  NvmeDeviceNode                = (NVME_NAMESPACE_DEVICE_PATH *)DevicePathWalker;\r
+  NvmeDeviceNode->NamespaceId   = NamespaceId;\r
+  NvmeDeviceNode->NamespaceUuid = NamespaceUuid;\r
+\r
+  //\r
+  // Construct the end device node\r
+  //\r
+  DevicePathWalker = (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *)DevicePathWalker +\r
+                     sizeof (NVME_NAMESPACE_DEVICE_PATH));\r
+  CopyMem (\r
+    DevicePathWalker,\r
+    &mNvmeEndDevicePathNodeTemplate,\r
+    sizeof (mNvmeEndDevicePathNodeTemplate)\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r