Пример #1
0
/**
  Load the persistent platform configuration and translate it to binary form
  state.

  If the platform configuration is missing, then the function fills in a
  default state.

  @param[out] MainFormState  Binary form/widget state after translation.

  @retval EFI_SUCCESS  Form/widget state ready.
  @return              Error codes from underlying functions.
**/
STATIC
EFI_STATUS
EFIAPI
PlatformConfigToFormState (
  OUT MAIN_FORM_STATE *MainFormState
  )
{
  EFI_STATUS      Status;
  PLATFORM_CONFIG PlatformConfig;
  UINT64          OptionalElements;
  UINTN           ModeNumber;

  ZeroMem (MainFormState, sizeof *MainFormState);

  Status = PlatformConfigLoad (&PlatformConfig, &OptionalElements);
  switch (Status) {
  case EFI_SUCCESS:
    if (OptionalElements & PLATFORM_CONFIG_F_GRAPHICS_RESOLUTION) {
      //
      // Format the preferred resolution as text.
      //
      UnicodeSPrintAsciiFormat (
        (CHAR16 *) MainFormState->CurrentPreferredResolution,
        sizeof MainFormState->CurrentPreferredResolution,
        "%Ldx%Ld",
        (INT64) PlatformConfig.HorizontalResolution,
        (INT64) PlatformConfig.VerticalResolution);

      //
      // Try to locate it in the drop-down list too. This may not succeed, but
      // that's fine.
      //
      for (ModeNumber = 0; ModeNumber < mNumGopModes; ++ModeNumber) {
        if (mGopModes[ModeNumber].X == PlatformConfig.HorizontalResolution &&
            mGopModes[ModeNumber].Y == PlatformConfig.VerticalResolution) {
          MainFormState->NextPreferredResolution = (UINT32) ModeNumber;
          break;
        }
      }

      break;
    }
    //
    // fall through otherwise
    //

  case EFI_NOT_FOUND:
    UnicodeSPrintAsciiFormat (
      (CHAR16 *) MainFormState->CurrentPreferredResolution,
      sizeof MainFormState->CurrentPreferredResolution,
      "Unset");
    break;

  default:
    return Status;
  }

  return EFI_SUCCESS;
}
Пример #2
0
/**
  Delete Boot#### variables that stand for such active boot options that have
  been dropped (ie. have not been selected by either matching or "survival
  policy").

  @param[in]  ActiveOption  The array of active boot options to scan. Each
                            entry not marked as appended will trigger the
                            deletion of the matching Boot#### variable.

  @param[in]  ActiveCount   Number of elements in ActiveOption.
**/
STATIC
VOID
PruneBootVariables (
  IN  CONST ACTIVE_OPTION *ActiveOption,
  IN  UINTN               ActiveCount
  )
{
  UINTN Idx;

  for (Idx = 0; Idx < ActiveCount; ++Idx) {
    if (!ActiveOption[Idx].Appended) {
      CHAR16 VariableName[9];

      UnicodeSPrintAsciiFormat (VariableName, sizeof VariableName, "Boot%04x",
        ActiveOption[Idx].BootOption->BootCurrent);

      //
      // "The space consumed by the deleted variable may not be available until
      // the next power cycle", but that's good enough.
      //
      gRT->SetVariable (VariableName, &gEfiGlobalVariableGuid,
             0,   // Attributes, 0 means deletion
             0,   // DataSize, 0 means deletion
             NULL // Data
             );
    }
  }
}
Пример #3
0
/**
  Create a set of "one-of-many" (ie. "drop down list") option IFR opcodes,
  based on available GOP resolutions, to be placed under a "one-of-many" (ie.
  "drop down list") opcode.

  @param[in]  PackageList   The package list with the formset and form for
                            which the drop down options are produced. Option
                            names are added as new strings to PackageList.

  @param[out] OpCodeBuffer  On output, a dynamically allocated opcode buffer
                            with drop down list options corresponding to GOP
                            resolutions. The caller is responsible for freeing
                            OpCodeBuffer with HiiFreeOpCodeHandle() after use.

  @param[in]  NumGopModes   Number of entries in GopModes.

  @param[in]  GopModes      Array of resolutions retrieved from the GOP.

  @retval EFI_SUCESS  Opcodes have been successfully produced.

  @return             Status codes from underlying functions. PackageList may
                      have been extended with new strings. OpCodeBuffer is
                      unchanged.
**/
STATIC
EFI_STATUS
EFIAPI
CreateResolutionOptions (
  IN  EFI_HII_HANDLE  *PackageList,
  OUT VOID            **OpCodeBuffer,
  IN  UINTN           NumGopModes,
  IN  GOP_MODE        *GopModes
  )
{
  EFI_STATUS Status;
  VOID       *OutputBuffer;
  UINTN      ModeNumber;

  OutputBuffer = HiiAllocateOpCodeHandle ();
  if (OutputBuffer == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  for (ModeNumber = 0; ModeNumber < NumGopModes; ++ModeNumber) {
    CHAR16        Desc[MAXSIZE_RES_CUR];
    EFI_STRING_ID NewString;
    VOID          *OpCode;

    UnicodeSPrintAsciiFormat (Desc, sizeof Desc, "%Ldx%Ld",
      (INT64) GopModes[ModeNumber].X, (INT64) GopModes[ModeNumber].Y);
    NewString = HiiSetString (PackageList, 0 /* new string */, Desc,
                  NULL /* for all languages */);
    if (NewString == 0) {
      Status = EFI_OUT_OF_RESOURCES;
      goto FreeOutputBuffer;
    }
    OpCode = HiiCreateOneOfOptionOpCode (OutputBuffer, NewString,
               0 /* Flags */, EFI_IFR_NUMERIC_SIZE_4, ModeNumber);
    if (OpCode == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto FreeOutputBuffer;
    }
  }

  *OpCodeBuffer = OutputBuffer;
  return EFI_SUCCESS;

FreeOutputBuffer:
  HiiFreeOpCodeHandle (OutputBuffer);

  return Status;
}
Пример #4
0
/**
  Prints an assert message containing a filename, line number, and description.
  This may be followed by a breakpoint or a dead loop.

  Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"
  to the debug output device.  If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of
  PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if
  DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then
  CpuDeadLoop() is called.  If neither of these bits are set, then this function
  returns immediately after the message is printed to the debug output device.
  DebugAssert() must actively prevent recursion.  If DebugAssert() is called while
  processing another DebugAssert(), then DebugAssert() must return immediately.

  If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.
  If Description is NULL, then a <Description> string of "(NULL) Description" is printed.

  @param  FileName     The pointer to the name of the source file that generated
                       the assert condition.
  @param  LineNumber   The line number in the source file that generated the
                       assert condition
  @param  Description  The pointer to the description of the assert condition.

**/
VOID
EFIAPI
DebugAssert (
  IN CONST CHAR8  *FileName,
  IN UINTN        LineNumber,
  IN CONST CHAR8  *Description
  )
{
  CHAR16  Buffer[MAX_DEBUG_MESSAGE_LENGTH];

  //
  // Generate the ASSERT() message in Unicode format
  //
  UnicodeSPrintAsciiFormat (
    Buffer,
    sizeof (Buffer),
    "ASSERT [%a] %a(%d): %a\n",
    gEfiCallerBaseName,
    FileName,
    LineNumber,
    Description
    );

  //
  // Send the print string to the Console Output device
  //
  if ((gST != NULL) && (gST->ConOut != NULL)) {
    gST->ConOut->OutputString (gST->ConOut, Buffer);
  }

  //
  // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings
  //
  if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
    CpuBreakpoint ();
  } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {
    CpuDeadLoop ();
  }
}
Пример #5
0
/**

  Translate an array of OpenFirmware device nodes to a UEFI device path
  fragment.

  @param[in]     OfwNode         Array of OpenFirmware device nodes to
                                 translate, constituting the beginning of an
                                 OpenFirmware device path.

  @param[in]     NumNodes        Number of elements in OfwNode.

  @param[out]    Translated      Destination array receiving the UEFI path
                                 fragment, allocated by the caller. If the
                                 return value differs from RETURN_SUCCESS, its
                                 contents is indeterminate.

  @param[in out] TranslatedSize  On input, the number of CHAR16's in
                                 Translated. On RETURN_SUCCESS this parameter
                                 is assigned the number of non-NUL CHAR16's
                                 written to Translated. In case of other return
                                 values, TranslatedSize is indeterminate.


  @retval RETURN_SUCCESS           Translation successful.

  @retval RETURN_BUFFER_TOO_SMALL  The translation does not fit into the number
                                   of bytes provided.

  @retval RETURN_UNSUPPORTED       The array of OpenFirmware device nodes can't
                                   be translated in the current implementation.

**/
STATIC
RETURN_STATUS
TranslateOfwNodes (
  IN      CONST OFW_NODE *OfwNode,
  IN      UINTN          NumNodes,
  OUT     CHAR16         *Translated,
  IN OUT  UINTN          *TranslatedSize
  )
{
  UINT32 PciDevFun[2];
  UINTN  NumEntries;
  UINTN  Written;

  //
  // Get PCI device and optional PCI function. Assume a single PCI root.
  //
  if (NumNodes < REQUIRED_OFW_NODES ||
      !SubstringEq (OfwNode[0].DriverName, "pci")
      ) {
    return RETURN_UNSUPPORTED;
  }
  PciDevFun[1] = 0;
  NumEntries = sizeof (PciDevFun) / sizeof (PciDevFun[0]);
  if (ParseUnitAddressHexList (
        OfwNode[1].UnitAddress,
        PciDevFun,
        &NumEntries
        ) != RETURN_SUCCESS
      ) {
    return RETURN_UNSUPPORTED;
  }

  if (NumNodes >= 4 &&
      SubstringEq (OfwNode[1].DriverName, "ide") &&
      SubstringEq (OfwNode[2].DriverName, "drive") &&
      SubstringEq (OfwNode[3].DriverName, "disk")
      ) {
    //
    // OpenFirmware device path (IDE disk, IDE CD-ROM):
    //
    //   /pci@i0cf8/ide@1,1/drive@0/disk@0
    //        ^         ^ ^       ^      ^
    //        |         | |       |      master or slave
    //        |         | |       primary or secondary
    //        |         PCI slot & function holding IDE controller
    //        PCI root at system bus port, PIO
    //
    // UEFI device path:
    //
    //   PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)
    //                                                ^
    //                                                fixed LUN
    //
    UINT32 Secondary;
    UINT32 Slave;

    NumEntries = 1;
    if (ParseUnitAddressHexList (
          OfwNode[2].UnitAddress,
          &Secondary,
          &NumEntries
          ) != RETURN_SUCCESS ||
        Secondary > 1 ||
        ParseUnitAddressHexList (
          OfwNode[3].UnitAddress,
          &Slave,
          &NumEntries // reuse after previous single-element call
          ) != RETURN_SUCCESS ||
        Slave > 1
        ) {
      return RETURN_UNSUPPORTED;
    }

    Written = UnicodeSPrintAsciiFormat (
      Translated,
      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes
      "PciRoot(0x0)/Pci(0x%x,0x%x)/Ata(%a,%a,0x0)",
      PciDevFun[0],
      PciDevFun[1],
      Secondary ? "Secondary" : "Primary",
      Slave ? "Slave" : "Master"
      );
  } else if (NumNodes >= 4 &&
             SubstringEq (OfwNode[1].DriverName, "isa") &&
             SubstringEq (OfwNode[2].DriverName, "fdc") &&
             SubstringEq (OfwNode[3].DriverName, "floppy")
             ) {
    //
    // OpenFirmware device path (floppy disk):
    //
    //   /pci@i0cf8/isa@1/fdc@03f0/floppy@0
    //        ^         ^     ^           ^
    //        |         |     |           A: or B:
    //        |         |     ISA controller io-port (hex)
    //        |         PCI slot holding ISA controller
    //        PCI root at system bus port, PIO
    //
    // UEFI device path:
    //
    //   PciRoot(0x0)/Pci(0x1,0x0)/Floppy(0x0)
    //                                    ^
    //                                    ACPI UID
    //
    UINT32 AcpiUid;

    NumEntries = 1;
    if (ParseUnitAddressHexList (
          OfwNode[3].UnitAddress,
          &AcpiUid,
          &NumEntries
          ) != RETURN_SUCCESS ||
        AcpiUid > 1
        ) {
      return RETURN_UNSUPPORTED;
    }

    Written = UnicodeSPrintAsciiFormat (
      Translated,
      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes
      "PciRoot(0x0)/Pci(0x%x,0x%x)/Floppy(0x%x)",
      PciDevFun[0],
      PciDevFun[1],
      AcpiUid
      );
  } else if (NumNodes >= 3 &&
             SubstringEq (OfwNode[1].DriverName, "scsi") &&
             SubstringEq (OfwNode[2].DriverName, "disk")
             ) {
    //
    // OpenFirmware device path (virtio-blk disk):
    //
    //   /pci@i0cf8/scsi@6[,3]/disk@0,0
    //        ^          ^  ^       ^ ^
    //        |          |  |       fixed
    //        |          |  PCI function corresponding to disk (optional)
    //        |          PCI slot holding disk
    //        PCI root at system bus port, PIO
    //
    // UEFI device path prefix:
    //
    //   PciRoot(0x0)/Pci(0x6,0x0)/HD( -- if PCI function is 0 or absent
    //   PciRoot(0x0)/Pci(0x6,0x3)/HD( -- if PCI function is present and nonzero
    //
    Written = UnicodeSPrintAsciiFormat (
      Translated,
      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes
      "PciRoot(0x0)/Pci(0x%x,0x%x)/HD(",
      PciDevFun[0],
      PciDevFun[1]
      );
  } else if (NumNodes >= 4 &&
             SubstringEq (OfwNode[1].DriverName, "scsi") &&
             SubstringEq (OfwNode[2].DriverName, "channel") &&
             SubstringEq (OfwNode[3].DriverName, "disk")
             ) {
    //
    // OpenFirmware device path (virtio-scsi disk):
    //
    //   /pci@i0cf8/scsi@7[,3]/channel@0/disk@2,3
    //        ^          ^             ^      ^ ^
    //        |          |             |      | LUN
    //        |          |             |      target
    //        |          |             channel (unused, fixed 0)
    //        |          PCI slot[, function] holding SCSI controller
    //        PCI root at system bus port, PIO
    //
    // UEFI device path prefix:
    //
    //   PciRoot(0x0)/Pci(0x7,0x0)/Scsi(0x2,0x3)
    //                                        -- if PCI function is 0 or absent
    //   PciRoot(0x0)/Pci(0x7,0x3)/Scsi(0x2,0x3)
    //                                -- if PCI function is present and nonzero
    //
    UINT32 TargetLun[2];

    TargetLun[1] = 0;
    NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]);
    if (ParseUnitAddressHexList (
          OfwNode[3].UnitAddress,
          TargetLun,
          &NumEntries
          ) != RETURN_SUCCESS
        ) {
      return RETURN_UNSUPPORTED;
    }

    Written = UnicodeSPrintAsciiFormat (
      Translated,
      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes
      "PciRoot(0x0)/Pci(0x%x,0x%x)/Scsi(0x%x,0x%x)",
      PciDevFun[0],
      PciDevFun[1],
      TargetLun[0],
      TargetLun[1]
      );
  } else if (NumNodes >= 3 &&
             SubstringEq (OfwNode[1].DriverName, "ethernet") &&
             SubstringEq (OfwNode[2].DriverName, "ethernet-phy")
             ) {
    //
    // OpenFirmware device path (Ethernet NIC):
    //
    //   /pci@i0cf8/ethernet@3[,2]/ethernet-phy@0
    //        ^              ^                  ^
    //        |              |                  fixed
    //        |              PCI slot[, function] holding Ethernet card
    //        PCI root at system bus port, PIO
    //
    // UEFI device path prefix (dependent on presence of nonzero PCI function):
    //
    //   PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400E15EEF,0x1)
    //   PciRoot(0x0)/Pci(0x3,0x2)/MAC(525400E15EEF,0x1)
    //                                 ^            ^
    //                                 MAC address  IfType (1 == Ethernet)
    //
    // (Some UEFI NIC drivers don't set 0x1 for IfType.)
    //
    Written = UnicodeSPrintAsciiFormat (
      Translated,
      *TranslatedSize * sizeof (*Translated), // BufferSize in bytes
      "PciRoot(0x0)/Pci(0x%x,0x%x)/MAC",
      PciDevFun[0],
      PciDevFun[1]
      );
  } else {
    return RETURN_UNSUPPORTED;
  }

  //
  // There's no way to differentiate between "completely used up without
  // truncation" and "truncated", so treat the former as the latter, and return
  // success only for "some room left unused".
  //
  if (Written + 1 < *TranslatedSize) {
    *TranslatedSize = Written;
    return RETURN_SUCCESS;
  }

  return RETURN_BUFFER_TOO_SMALL;
}
/**
  Check if the specified Nvm Express device namespace is active, and create child handles
  for them with BlockIo and DiskInfo protocol instances.

  @param[in] Private         The pointer to the NVME_CONTROLLER_PRIVATE_DATA data structure.
  @param[in] NamespaceId     The NVM Express namespace ID  for which a device path node is to be
                             allocated and built. Caller must set the NamespaceId to zero if the
                             device path node will contain a valid UUID.

  @retval EFI_SUCCESS        All the namespaces in the device are successfully enumerated.
  @return Others             Some error occurs when enumerating the namespaces.

**/
EFI_STATUS
EnumerateNvmeDevNamespace (
  IN NVME_CONTROLLER_PRIVATE_DATA       *Private,
  UINT32                                NamespaceId
  )
{
  NVME_ADMIN_NAMESPACE_DATA             *NamespaceData;
  EFI_DEVICE_PATH_PROTOCOL              *NewDevicePathNode;
  EFI_DEVICE_PATH_PROTOCOL              *DevicePath;
  EFI_HANDLE                            DeviceHandle;
  EFI_DEVICE_PATH_PROTOCOL              *ParentDevicePath;
  EFI_DEVICE_PATH_PROTOCOL              *RemainingDevicePath;
  NVME_DEVICE_PRIVATE_DATA              *Device;
  EFI_STATUS                            Status;
  UINT32                                Lbads;
  UINT32                                Flbas;
  UINT32                                LbaFmtIdx;
  UINT8                                 Sn[21];
  UINT8                                 Mn[41];
  VOID                                  *DummyInterface;

  NewDevicePathNode = NULL;
  DevicePath        = NULL;
  Device            = NULL;

  //
  // Allocate a buffer for Identify Namespace data
  //
  NamespaceData = AllocateZeroPool(sizeof (NVME_ADMIN_NAMESPACE_DATA));
  if(NamespaceData == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  ParentDevicePath = Private->ParentDevicePath;
  //
  // Identify Namespace
  //
  Status = NvmeIdentifyNamespace (
             Private,
             NamespaceId,
             (VOID *)NamespaceData
             );
  if (EFI_ERROR(Status)) {
    goto Exit;
  }
  //
  // Validate Namespace
  //
  if (NamespaceData->Ncap == 0) {
    Status = EFI_DEVICE_ERROR;
  } else {
    //
    // allocate device private data for each discovered namespace
    //
    Device = AllocateZeroPool(sizeof(NVME_DEVICE_PRIVATE_DATA));
    if (Device == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Exit;
    }

    //
    // Initialize SSD namespace instance data
    //
    Device->Signature           = NVME_DEVICE_PRIVATE_DATA_SIGNATURE;
    Device->NamespaceId         = NamespaceId;
    Device->NamespaceUuid       = NamespaceData->Eui64;

    Device->ControllerHandle    = Private->ControllerHandle;
    Device->DriverBindingHandle = Private->DriverBindingHandle;
    Device->Controller          = Private;

    //
    // Build BlockIo media structure
    //
    Device->Media.MediaId        = 0;
    Device->Media.RemovableMedia = FALSE;
    Device->Media.MediaPresent   = TRUE;
    Device->Media.LogicalPartition = FALSE;
    Device->Media.ReadOnly       = FALSE;
    Device->Media.WriteCaching   = FALSE;
    Device->Media.IoAlign        = Private->PassThruMode.IoAlign;

    Flbas     = NamespaceData->Flbas;
    LbaFmtIdx = Flbas & 0xF;
    Lbads     = NamespaceData->LbaFormat[LbaFmtIdx].Lbads;
    Device->Media.BlockSize = (UINT32)1 << Lbads;

    Device->Media.LastBlock                     = NamespaceData->Nsze - 1;
    Device->Media.LogicalBlocksPerPhysicalBlock = 1;
    Device->Media.LowestAlignedLba              = 1;

    //
    // Create BlockIo Protocol instance
    //
    Device->BlockIo.Revision     = EFI_BLOCK_IO_PROTOCOL_REVISION2;
    Device->BlockIo.Media        = &Device->Media;
    Device->BlockIo.Reset        = NvmeBlockIoReset;
    Device->BlockIo.ReadBlocks   = NvmeBlockIoReadBlocks;
    Device->BlockIo.WriteBlocks  = NvmeBlockIoWriteBlocks;
    Device->BlockIo.FlushBlocks  = NvmeBlockIoFlushBlocks;

    //
    // Create BlockIo2 Protocol instance
    //
    Device->BlockIo2.Media          = &Device->Media;
    Device->BlockIo2.Reset          = NvmeBlockIoResetEx;
    Device->BlockIo2.ReadBlocksEx   = NvmeBlockIoReadBlocksEx;
    Device->BlockIo2.WriteBlocksEx  = NvmeBlockIoWriteBlocksEx;
    Device->BlockIo2.FlushBlocksEx  = NvmeBlockIoFlushBlocksEx;
    InitializeListHead (&Device->AsyncQueue);

    //
    // Create StorageSecurityProtocol Instance
    //
    Device->StorageSecurity.ReceiveData = NvmeStorageSecurityReceiveData;
    Device->StorageSecurity.SendData    = NvmeStorageSecuritySendData;

    //
    // Create DiskInfo Protocol instance
    //
    CopyMem (&Device->NamespaceData, NamespaceData, sizeof (NVME_ADMIN_NAMESPACE_DATA));
    InitializeDiskInfo (Device);

    //
    // Create a Nvm Express Namespace Device Path Node
    //
    Status = Private->Passthru.BuildDevicePath (
                                 &Private->Passthru,
                                 Device->NamespaceId,
                                 &NewDevicePathNode
                                 );

    if (EFI_ERROR(Status)) {
      goto Exit;
    }

    //
    // Append the SSD node to the controller's device path
    //
    DevicePath = AppendDevicePathNode (ParentDevicePath, NewDevicePathNode);
    if (DevicePath == NULL) {
      Status = EFI_OUT_OF_RESOURCES;
      goto Exit;
    }

    DeviceHandle = NULL;
    RemainingDevicePath = DevicePath;
    Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);
    if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {
      Status = EFI_ALREADY_STARTED;
      FreePool (DevicePath);
      goto Exit;
    }

    Device->DevicePath = DevicePath;

    //
    // Make sure the handle is NULL so we create a new handle
    //
    Device->DeviceHandle = NULL;

    Status = gBS->InstallMultipleProtocolInterfaces (
                    &Device->DeviceHandle,
                    &gEfiDevicePathProtocolGuid,
                    Device->DevicePath,
                    &gEfiBlockIoProtocolGuid,
                    &Device->BlockIo,
                    &gEfiBlockIo2ProtocolGuid,
                    &Device->BlockIo2,
                    &gEfiDiskInfoProtocolGuid,
                    &Device->DiskInfo,
                    NULL
                    );

    if(EFI_ERROR(Status)) {
      goto Exit;
    }

    //
    // Check if the NVMe controller supports the Security Send and Security Receive commands
    //
    if ((Private->ControllerData->Oacs & SECURITY_SEND_RECEIVE_SUPPORTED) != 0) {
      Status = gBS->InstallProtocolInterface (
                      &Device->DeviceHandle,
                      &gEfiStorageSecurityCommandProtocolGuid,
                      EFI_NATIVE_INTERFACE,
                      &Device->StorageSecurity
                      );
      if(EFI_ERROR(Status)) {
        gBS->UninstallMultipleProtocolInterfaces (
               &Device->DeviceHandle,
               &gEfiDevicePathProtocolGuid,
               Device->DevicePath,
               &gEfiBlockIoProtocolGuid,
               &Device->BlockIo,
               &gEfiBlockIo2ProtocolGuid,
               &Device->BlockIo2,
               &gEfiDiskInfoProtocolGuid,
               &Device->DiskInfo,
               NULL
               );
        goto Exit;
      }
    }

    gBS->OpenProtocol (
           Private->ControllerHandle,
           &gEfiNvmExpressPassThruProtocolGuid,
           (VOID **) &DummyInterface,
           Private->DriverBindingHandle,
           Device->DeviceHandle,
           EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
           );

    //
    // Dump NvmExpress Identify Namespace Data
    //
    DEBUG ((EFI_D_INFO, " == NVME IDENTIFY NAMESPACE [%d] DATA ==\n", NamespaceId));
    DEBUG ((EFI_D_INFO, "    NSZE        : 0x%x\n", NamespaceData->Nsze));
    DEBUG ((EFI_D_INFO, "    NCAP        : 0x%x\n", NamespaceData->Ncap));
    DEBUG ((EFI_D_INFO, "    NUSE        : 0x%x\n", NamespaceData->Nuse));
    DEBUG ((EFI_D_INFO, "    LBAF0.LBADS : 0x%x\n", (NamespaceData->LbaFormat[0].Lbads)));

    //
    // Build controller name for Component Name (2) protocol.
    //
    CopyMem (Sn, Private->ControllerData->Sn, sizeof (Private->ControllerData->Sn));
    Sn[20] = 0;
    CopyMem (Mn, Private->ControllerData->Mn, sizeof (Private->ControllerData->Mn));
    Mn[40] = 0;
    UnicodeSPrintAsciiFormat (Device->ModelName, sizeof (Device->ModelName), "%a-%a-%x", Sn, Mn, NamespaceData->Eui64);

    AddUnicodeString2 (
      "eng",
      gNvmExpressComponentName.SupportedLanguages,
      &Device->ControllerNameTable,
      Device->ModelName,
      TRUE
      );

    AddUnicodeString2 (
      "en",
      gNvmExpressComponentName2.SupportedLanguages,
      &Device->ControllerNameTable,
      Device->ModelName,
      FALSE
      );
  }

Exit:
  if(NamespaceData != NULL) {
    FreePool (NamespaceData);
  }

  if (NewDevicePathNode != NULL) {
    FreePool (NewDevicePathNode);
  }

  if(EFI_ERROR(Status) && (Device != NULL) && (Device->DevicePath != NULL)) {
    FreePool (Device->DevicePath);
  }
  if(EFI_ERROR(Status) && (Device != NULL)) {
    FreePool (Device);
  }
  return Status;
}