Revision: 18015
          http://sourceforge.net/p/edk2/code/18015
Author:   jljusten
Date:     2015-07-26 07:36:51 +0000 (Sun, 26 Jul 2015)
Log Message:
-----------
ShellPkg: Add optional 'tftp' EFI Shell command

This 'tftp' command allows to download a file from a TFTP server.
A specific network interface can be chosen in case there are multiple
interfaces.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ronald Cron <[email protected]>
Reviewed-by: Olivier Martin <[email protected]>
Reviewed-by: Jaben Carsey <[email protected]>

Modified Paths:
--------------
    trunk/edk2/ShellPkg/Include/Guid/ShellLibHiiGuid.h
    trunk/edk2/ShellPkg/ShellPkg.dec
    trunk/edk2/ShellPkg/ShellPkg.dsc

Added Paths:
-----------
    trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/
    trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c
    
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.c
    
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.h
    
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf
    
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.uni

Modified: trunk/edk2/ShellPkg/Include/Guid/ShellLibHiiGuid.h
===================================================================
--- trunk/edk2/ShellPkg/Include/Guid/ShellLibHiiGuid.h  2015-07-15 03:46:13 UTC 
(rev 18014)
+++ trunk/edk2/ShellPkg/Include/Guid/ShellLibHiiGuid.h  2015-07-26 07:36:51 UTC 
(rev 18015)
@@ -54,6 +54,12 @@
   { \
     0xf3d301bb, 0xf4a5, 0x45a8, { 0xb0, 0xb7, 0xfa, 0x99, 0x9c, 0x62, 0x37, 
0xae } \
   }
+#define SHELL_TFTP_HII_GUID \
+  { \
+    0x738a9314, 0x82c1, 0x4592, { 0x8f, 0xf7, 0xc1, 0xbd, 0xf1, 0xb2, 0x0e, 
0xd4 } \
+  }
+
+
 #define SHELL_BCFG_HII_GUID \
   { \
     0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 0xeb, 0x12, 0xda, 0xb4, 0xa2, 
0xb6 } \
@@ -67,6 +73,7 @@
 extern EFI_GUID gShellLevel2HiiGuid;
 extern EFI_GUID gShellLevel3HiiGuid;
 extern EFI_GUID gShellNetwork1HiiGuid;
+extern EFI_GUID gShellTftpHiiGuid;
 extern EFI_GUID gShellBcfgHiiGuid;
 
 #endif

Added: trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c
===================================================================
--- trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c                  
        (rev 0)
+++ trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c  2015-07-26 
07:36:51 UTC (rev 18015)
@@ -0,0 +1,880 @@
+/** @file
+  The implementation for the 'tftp' Shell command.
+
+  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD 
License
+  which accompanies this distribution.  The full text of the license may be 
found at
+  http://opensource.org/licenses/bsd-license.php.
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include "UefiShellTftpCommandLib.h"
+
+/*
+   Constant strings and definitions related to the message indicating the 
amount of
+   progress in the dowloading of a TFTP file.
+*/
+
+// Frame for the progression slider
+STATIC CONST CHAR16 mTftpProgressFrame[] = L"[                                 
       ]";
+
+// Number of steps in the progression slider
+#define TFTP_PROGRESS_SLIDER_STEPS  ((sizeof (mTftpProgressFrame) / sizeof 
(CHAR16)) - 3)
+
+// Size in number of characters plus one (final zero) of the message to
+// indicate the progress of a TFTP download. The format is "[(progress slider:
+// 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There
+// are thus the number of characters in mTftpProgressFrame[] plus 11 characters
+// (2 // spaces, "Kb" and seven characters for the number of KBytes).
+#define TFTP_PROGRESS_MESSAGE_SIZE  ((sizeof (mTftpProgressFrame) / sizeof 
(CHAR16)) + 12)
+
+// String to delete the TFTP progress message to be able to update it :
+// (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b'
+STATIC CONST CHAR16 mTftpProgressDelete[] = 
L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
+
+STATIC BOOLEAN StringToUint16 (
+  IN   CONST CHAR16  *ValueStr,
+  OUT  UINT16        *Value
+  );
+
+STATIC EFI_STATUS GetNicName (
+  IN   EFI_HANDLE  ControllerHandle,
+  IN   UINTN       Index,
+  OUT  CHAR16      *NicName
+  );
+
+STATIC EFI_STATUS CreateServiceChildAndOpenProtocol (
+  IN   EFI_HANDLE  ControllerHandle,
+  IN   EFI_GUID    *ServiceBindingProtocolGuid,
+  IN   EFI_GUID    *ProtocolGuid,
+  OUT  EFI_HANDLE  *ChildHandle,
+  OUT  VOID        **Interface
+  );
+
+STATIC VOID CloseProtocolAndDestroyServiceChild (
+  IN  EFI_HANDLE  ControllerHandle,
+  IN  EFI_GUID    *ServiceBindingProtocolGuid,
+  IN  EFI_GUID    *ProtocolGuid,
+  IN  EFI_HANDLE  ChildHandle
+  );
+
+STATIC EFI_STATUS GetFileSize (
+  IN   EFI_MTFTP4_PROTOCOL  *Mtftp4,
+  IN   CONST CHAR8          *FilePath,
+  OUT  UINTN                *FileSize
+  );
+
+STATIC EFI_STATUS DownloadFile (
+  IN   EFI_MTFTP4_PROTOCOL  *Mtftp4,
+  IN   CONST CHAR16         *FilePath,
+  IN   CONST CHAR8          *AsciiFilePath,
+  IN   UINTN                FileSize,
+  OUT  VOID                 **Data
+  );
+
+STATIC EFI_STATUS CheckPacket (
+  IN EFI_MTFTP4_PROTOCOL  *This,
+  IN EFI_MTFTP4_TOKEN     *Token,
+  IN UINT16               PacketLen,
+  IN EFI_MTFTP4_PACKET    *Packet
+  );
+
+EFI_MTFTP4_CONFIG_DATA DefaultMtftp4ConfigData = {
+  TRUE,                             // Use default setting
+  { { 0, 0, 0, 0 } },               // StationIp         - Not relevant as 
UseDefaultSetting=TRUE
+  { { 0, 0, 0, 0 } },               // SubnetMask        - Not relevant as 
UseDefaultSetting=TRUE
+  0,                                // LocalPort         - Automatically 
assigned port number.
+  { { 0, 0, 0, 0 } },               // GatewayIp         - Not relevant as 
UseDefaultSetting=TRUE
+  { { 0, 0, 0, 0 } },               // ServerIp          - Not known yet
+  69,                               // InitialServerPort - Standard TFTP 
server port
+  6,                                // TryCount          - Max number of 
retransmissions.
+  4                                 // TimeoutValue      - Retransmission 
timeout in seconds.
+};
+
+STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
+  {L"-i", TypeValue},
+  {L"-l", TypeValue},
+  {L"-r", TypeValue},
+  {L"-c", TypeValue},
+  {L"-t", TypeValue},
+  {NULL , TypeMax}
+  };
+
+/**
+  Function for 'tftp' command.
+
+  @param[in] ImageHandle  Handle to the Image (NULL if Internal).
+  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
+
+  @return  SHELL_SUCCESS            The 'tftp' command completed successfully.
+  @return  SHELL_ABORTED            The Shell Library initialization failed.
+  @return  SHELL_INVALID_PARAMETER  At least one of the command's arguments is
+                                    not valid.
+  @return  SHELL_OUT_OF_RESOURCES   A memory allocation failed.
+  @return  SHELL_NOT_FOUND          Network Interface Card not found or server
+                                    error or file error.
+
+**/
+SHELL_STATUS
+EFIAPI
+ShellCommandRunTftp (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  SHELL_STATUS            ShellStatus;
+  EFI_STATUS              Status;
+  LIST_ENTRY              *CheckPackage;
+  CHAR16                  *ProblemParam;
+  UINTN                   ParamCount;
+  CONST CHAR16            *UserNicName;
+  BOOLEAN                 NicFound;
+  CONST CHAR16            *ValueStr;
+  CONST CHAR16            *RemoteFilePath;
+  CHAR8                   *AsciiRemoteFilePath;
+  CONST CHAR16            *Walker;
+  CONST CHAR16            *LocalFilePath;
+  EFI_MTFTP4_CONFIG_DATA  Mtftp4ConfigData;
+  EFI_HANDLE              *Handles;
+  UINTN                   HandleCount;
+  UINTN                   NicNumber;
+  CHAR16                  NicName[IP4_NIC_NAME_LENGTH];
+  EFI_HANDLE              ControllerHandle;
+  EFI_HANDLE              Mtftp4ChildHandle;
+  EFI_MTFTP4_PROTOCOL     *Mtftp4;
+  UINTN                   FileSize;
+  VOID                    *Data;
+  SHELL_FILE_HANDLE       FileHandle;
+
+  ShellStatus         = SHELL_INVALID_PARAMETER;
+  ProblemParam        = NULL;
+  NicFound            = FALSE;
+  AsciiRemoteFilePath = NULL;
+  Handles             = NULL;
+
+  //
+  // Initialize the Shell library (we must be in non-auto-init...)
+  //
+  Status = ShellInitialize ();
+  if (EFI_ERROR (Status)) {
+    ASSERT_EFI_ERROR (Status);
+    return SHELL_ABORTED;
+  }
+
+  //
+  // Parse the command line.
+  //
+  Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, 
TRUE);
+  if (EFI_ERROR (Status)) {
+    if ((Status == EFI_VOLUME_CORRUPTED) &&
+        (ProblemParam != NULL) ) {
+      ShellPrintHiiEx (
+        -1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellTftpHiiHandle,
+        L"tftp", ProblemParam
+        );
+      FreePool (ProblemParam);
+    } else {
+      ASSERT (FALSE);
+    }
+    goto Error;
+  }
+
+  //
+  // Check the number of parameters
+  //
+  ParamCount = ShellCommandLineGetCount (CheckPackage);
+  if (ParamCount > 4) {
+    ShellPrintHiiEx (
+      -1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY),
+      gShellTftpHiiHandle, L"tftp"
+      );
+    goto Error;
+  }
+  if (ParamCount < 3) {
+    ShellPrintHiiEx (
+      -1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW),
+      gShellTftpHiiHandle, L"tftp"
+      );
+    goto Error;
+  }
+
+  Mtftp4ConfigData = DefaultMtftp4ConfigData;
+
+  //
+  // Check the host IPv4 address
+  //
+  ValueStr = ShellCommandLineGetRawValue (CheckPackage, 1);
+  Status = NetLibStrToIp4 (ValueStr, &Mtftp4ConfigData.ServerIp);
+  if (EFI_ERROR (Status)) {
+    ShellPrintHiiEx (
+      -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
+      gShellTftpHiiHandle, L"tftp", ValueStr
+    );
+    goto Error;
+  }
+
+  RemoteFilePath = ShellCommandLineGetRawValue (CheckPackage, 2);
+  AsciiRemoteFilePath = AllocatePool (
+                          (StrLen (RemoteFilePath) + 1) * sizeof (CHAR8)
+                          );
+  if (AsciiRemoteFilePath == NULL) {
+    ShellStatus = SHELL_OUT_OF_RESOURCES;
+    goto Error;
+  }
+  UnicodeStrToAsciiStr (RemoteFilePath, AsciiRemoteFilePath);
+
+  if (ParamCount == 4) {
+    LocalFilePath = ShellCommandLineGetRawValue (CheckPackage, 3);
+  } else {
+    Walker = RemoteFilePath + StrLen (RemoteFilePath);
+    while ((--Walker) >= RemoteFilePath) {
+      if ((*Walker == L'\\') ||
+          (*Walker == L'/' )    ) {
+        break;
+      }
+    }
+    LocalFilePath = Walker + 1;
+  }
+
+  //
+  // Get the name of the Network Interface Card to be used if any.
+  //
+  UserNicName = ShellCommandLineGetValue (CheckPackage, L"-i");
+
+  ValueStr = ShellCommandLineGetValue (CheckPackage, L"-l");
+  if (ValueStr != NULL) {
+    if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.LocalPort)) {
+      goto Error;
+    }
+  }
+
+  ValueStr = ShellCommandLineGetValue (CheckPackage, L"-r");
+  if (ValueStr != NULL) {
+    if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.InitialServerPort)) {
+      goto Error;
+    }
+  }
+
+  ValueStr = ShellCommandLineGetValue (CheckPackage, L"-c");
+  if (ValueStr != NULL) {
+    if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TryCount)) {
+      goto Error;
+    }
+  }
+
+  ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t");
+  if (ValueStr != NULL) {
+    if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TimeoutValue)) {
+      goto Error;
+    }
+    if (Mtftp4ConfigData.TimeoutValue == 0) {
+      ShellPrintHiiEx (
+        -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
+        gShellTftpHiiHandle, L"tftp", ValueStr
+      );
+      goto Error;
+    }
+  }
+
+  //
+  // Locate all MTFTP4 Service Binding protocols
+  //
+  ShellStatus = SHELL_NOT_FOUND;
+  Status = gBS->LocateHandleBuffer (
+                 ByProtocol,
+                 &gEfiManagedNetworkServiceBindingProtocolGuid,
+                 NULL,
+                 &HandleCount,
+                 &Handles
+                 );
+  if (EFI_ERROR (Status) || (HandleCount == 0)) {
+    ShellPrintHiiEx (
+      -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NO_NIC),
+      gShellTftpHiiHandle
+    );
+    goto Error;
+  }
+
+  for (NicNumber = 0;
+       (NicNumber < HandleCount) && (ShellStatus != SHELL_SUCCESS);
+       NicNumber++) {
+    ControllerHandle = Handles[NicNumber];
+    Data = NULL;
+
+    Status = GetNicName (ControllerHandle, NicNumber, NicName);
+    if (EFI_ERROR (Status)) {
+      ShellPrintHiiEx (
+        -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NAME),
+        gShellTftpHiiHandle, NicNumber, Status
+      );
+      continue;
+    }
+
+    if (UserNicName != NULL) {
+      if (StrCmp (NicName, UserNicName) != 0) {
+        continue;
+      }
+      NicFound = TRUE;
+    }
+
+    Status = CreateServiceChildAndOpenProtocol (
+               ControllerHandle,
+               &gEfiMtftp4ServiceBindingProtocolGuid,
+               &gEfiMtftp4ProtocolGuid,
+               &Mtftp4ChildHandle,
+               (VOID**)&Mtftp4
+               );
+    if (EFI_ERROR (Status)) {
+      ShellPrintHiiEx (
+        -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_OPEN_PROTOCOL),
+        gShellTftpHiiHandle, NicName, Status
+      );
+      continue;
+    }
+
+    Status = Mtftp4->Configure (Mtftp4, &Mtftp4ConfigData);
+    if (EFI_ERROR (Status)) {
+      ShellPrintHiiEx (
+        -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_CONFIGURE),
+        gShellTftpHiiHandle, NicName, Status
+      );
+      goto NextHandle;
+    }
+
+    Status = GetFileSize (Mtftp4, AsciiRemoteFilePath, &FileSize);
+    if (EFI_ERROR (Status)) {
+      ShellPrintHiiEx (
+        -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_FILE_SIZE),
+        gShellTftpHiiHandle, RemoteFilePath, NicName, Status
+      );
+      goto NextHandle;
+    }
+
+    Status = DownloadFile (Mtftp4, RemoteFilePath, AsciiRemoteFilePath, 
FileSize, &Data);
+    if (EFI_ERROR (Status)) {
+      ShellPrintHiiEx (
+        -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD),
+        gShellTftpHiiHandle, RemoteFilePath, NicName, Status
+      );
+      goto NextHandle;
+    }
+
+    if (!EFI_ERROR (ShellFileExists (LocalFilePath))) {
+      ShellDeleteFileByName (LocalFilePath);
+    }
+
+    Status = ShellOpenFileByName (
+               LocalFilePath,
+               &FileHandle,
+               EFI_FILE_MODE_CREATE |
+               EFI_FILE_MODE_WRITE  |
+               EFI_FILE_MODE_READ,
+               0
+               );
+    if (EFI_ERROR (Status)) {
+      ShellPrintHiiEx (
+        -1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL),
+        gShellTftpHiiHandle, L"tftp", LocalFilePath
+      );
+      goto NextHandle;
+    }
+
+    Status = ShellWriteFile (FileHandle, &FileSize, Data);
+    if (!EFI_ERROR (Status)) {
+      ShellStatus = SHELL_SUCCESS;
+    } else {
+      ShellPrintHiiEx (
+        -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_WRITE),
+        gShellTftpHiiHandle, LocalFilePath, Status
+      );
+    }
+    ShellCloseFile (&FileHandle);
+
+    NextHandle:
+
+    if (Data != NULL) {
+      gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)Data, EFI_SIZE_TO_PAGES 
(FileSize));
+    }
+
+    CloseProtocolAndDestroyServiceChild (
+      ControllerHandle,
+      &gEfiMtftp4ServiceBindingProtocolGuid,
+      &gEfiMtftp4ProtocolGuid,
+      Mtftp4ChildHandle
+      );
+  }
+
+  if ((UserNicName != NULL) && (NicFound == FALSE)) {
+    ShellPrintHiiEx (
+      -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NOT_FOUND),
+      gShellTftpHiiHandle, UserNicName
+    );
+  }
+
+  Error:
+
+  ShellCommandLineFreeVarList (CheckPackage);
+  if (AsciiRemoteFilePath != NULL) {
+    FreePool (AsciiRemoteFilePath);
+  }
+  if (Handles != NULL) {
+    FreePool (Handles);
+  }
+
+  return ShellStatus;
+}
+
+/**
+  Check and convert the UINT16 option values of the 'tftp' command
+
+  @param[in]  ValueStr  Value as an Unicode encoded string
+  @param[out] Value     UINT16 value
+
+  @return     TRUE      The value was returned.
+  @return     FALSE     A parsing error occured.
+**/
+STATIC
+BOOLEAN
+StringToUint16 (
+  IN   CONST CHAR16  *ValueStr,
+  OUT  UINT16        *Value
+  )
+{
+  UINTN  Val;
+
+  Val = ShellStrToUintn (ValueStr);
+  if (Val > MAX_UINT16) {
+    ShellPrintHiiEx (
+      -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),
+      gShellTftpHiiHandle, L"tftp", ValueStr
+    );
+    return FALSE;
+  }
+
+  *Value = Val;
+  return TRUE;
+}
+
+/**
+  Get the name of the NIC.
+
+  @param[in]   ControllerHandle  The network physical device handle.
+  @param[in]   NicNumber         The network physical device number.
+  @param[out]  NicName           Address where to store the NIC name.
+                                 The memory area has to be at least
+                                 IP4_NIC_NAME_LENGTH bytes wide.
+
+  @return  EFI_SUCCESS  The name of the NIC was returned.
+  @return  Others       The creation of the child for the Managed
+                        Network Service failed or the opening of
+                        the Managed Network Protocol failed or
+                        the operational parameters for the
+                        Managed Network Protocol could not be
+                        read.
+**/
+STATIC
+EFI_STATUS
+GetNicName (
+  IN   EFI_HANDLE  ControllerHandle,
+  IN   UINTN       NicNumber,
+  OUT  CHAR16      *NicName
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_HANDLE                    MnpHandle;
+  EFI_MANAGED_NETWORK_PROTOCOL  *Mnp;
+  EFI_SIMPLE_NETWORK_MODE       SnpMode;
+
+  Status = CreateServiceChildAndOpenProtocol (
+             ControllerHandle,
+             &gEfiManagedNetworkServiceBindingProtocolGuid,
+             &gEfiManagedNetworkProtocolGuid,
+             &MnpHandle,
+             (VOID**)&Mnp
+             );
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
+  Status = Mnp->GetModeData (Mnp, NULL, &SnpMode);
+  if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
+    goto Error;
+  }
+
+  UnicodeSPrint (
+    NicName,
+    IP4_NIC_NAME_LENGTH,
+    SnpMode.IfType == NET_IFTYPE_ETHERNET ?
+    L"eth%d" :
+    L"unk%d" ,
+    NicNumber
+    );
+
+  Status = EFI_SUCCESS;
+
+Error:
+
+  if (MnpHandle != NULL) {
+    CloseProtocolAndDestroyServiceChild (
+      ControllerHandle,
+      &gEfiManagedNetworkServiceBindingProtocolGuid,
+      &gEfiManagedNetworkProtocolGuid,
+      MnpHandle
+      );
+  }
+
+  return Status;
+}
+
+/**
+  Create a child for the service identified by its service binding protocol 
GUID
+  and get from the child the interface of the protocol identified by its GUID.
+
+  @param[in]   ControllerHandle            Controller handle.
+  @param[in]   ServiceBindingProtocolGuid  Service binding protocol GUID of the
+                                           service to be created.
+  @param[in]   ProtocolGuid                GUID of the protocol to be open.
+  @param[out]  ChildHandle                 Address where the handler of the
+                                           created child is returned. NULL is
+                                           returned in case of error.
+  @param[out]  Interface                   Address where a pointer to the
+                                           protocol interface is returned in
+                                           case of success.
+
+  @return  EFI_SUCCESS  The child was created and the protocol opened.
+  @return  Others       Either the creation of the child or the opening
+                        of the protocol failed.
+**/
+STATIC
+EFI_STATUS
+CreateServiceChildAndOpenProtocol (
+  IN   EFI_HANDLE  ControllerHandle,
+  IN   EFI_GUID    *ServiceBindingProtocolGuid,
+  IN   EFI_GUID    *ProtocolGuid,
+  OUT  EFI_HANDLE  *ChildHandle,
+  OUT  VOID        **Interface
+  )
+{
+  EFI_STATUS  Status;
+
+  *ChildHandle = NULL;
+  Status = NetLibCreateServiceChild (
+             ControllerHandle,
+             gImageHandle,
+             ServiceBindingProtocolGuid,
+             ChildHandle
+             );
+  if (!EFI_ERROR (Status)) {
+    Status = gBS->OpenProtocol (
+                    *ChildHandle,
+                    ProtocolGuid,
+                    Interface,
+                    gImageHandle,
+                    ControllerHandle,
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                    );
+    if (EFI_ERROR (Status)) {
+      NetLibDestroyServiceChild (
+        ControllerHandle,
+        gImageHandle,
+        ServiceBindingProtocolGuid,
+        *ChildHandle
+        );
+      *ChildHandle = NULL;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Close the protocol identified by its GUID on the child handle of the service
+  identified by its service binding protocol GUID, then destroy the child
+  handle.
+
+  @param[in]  ControllerHandle            Controller handle.
+  @param[in]  ServiceBindingProtocolGuid  Service binding protocol GUID of the
+                                          service to be destroyed.
+  @param[in]  ProtocolGuid                GUID of the protocol to be closed.
+  @param[in]  ChildHandle                 Handle of the child to be destroyed.
+
+**/
+STATIC
+VOID
+CloseProtocolAndDestroyServiceChild (
+  IN  EFI_HANDLE  ControllerHandle,
+  IN  EFI_GUID    *ServiceBindingProtocolGuid,
+  IN  EFI_GUID    *ProtocolGuid,
+  IN  EFI_HANDLE  ChildHandle
+  )
+{
+  gBS->CloseProtocol (
+         ChildHandle,
+         ProtocolGuid,
+         gImageHandle,
+         ControllerHandle
+         );
+
+  NetLibDestroyServiceChild (
+    ControllerHandle,
+    gImageHandle,
+    ServiceBindingProtocolGuid,
+    ChildHandle
+    );
+}
+
+/**
+  Worker function that gets the size in numbers of bytes of a file from a TFTP
+  server before to download the file.
+
+  @param[in]   Mtftp4    MTFTP4 protocol interface
+  @param[in]   FilePath  Path of the file, ASCII encoded
+  @param[out]  FileSize  Address where to store the file size in number of
+                         bytes.
+
+  @retval  EFI_SUCCESS      The size of the file was returned.
+  @retval  EFI_UNSUPPORTED  The server does not support the "tsize" option.
+  @retval  Others           Error when retrieving the information from the 
server
+                            (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes)
+                            or error when parsing the response of the server.
+**/
+STATIC
+EFI_STATUS
+GetFileSize (
+  IN   EFI_MTFTP4_PROTOCOL  *Mtftp4,
+  IN   CONST CHAR8          *FilePath,
+  OUT  UINTN                *FileSize
+  )
+{
+  EFI_STATUS         Status;
+  EFI_MTFTP4_OPTION  ReqOpt[1];
+  EFI_MTFTP4_PACKET  *Packet;
+  UINT32             PktLen;
+  EFI_MTFTP4_OPTION  *TableOfOptions;
+  EFI_MTFTP4_OPTION  *Option;
+  UINT32             OptCnt;
+  UINT8              OptBuf[128];
+
+  ReqOpt[0].OptionStr = (UINT8*)"tsize";
+  OptBuf[0] = '0';
+  OptBuf[1] = 0;
+  ReqOpt[0].ValueStr = OptBuf;
+
+  Status = Mtftp4->GetInfo (
+             Mtftp4,
+             NULL,
+             (UINT8*)FilePath,
+             NULL,
+             1,
+             ReqOpt,
+             &PktLen,
+             &Packet
+             );
+
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
+  Status = Mtftp4->ParseOptions (
+                     Mtftp4,
+                     PktLen,
+                     Packet,
+                     (UINT32 *) &OptCnt,
+                     &TableOfOptions
+                     );
+  if (EFI_ERROR (Status)) {
+    goto Error;
+  }
+
+  Option = TableOfOptions;
+  while (OptCnt != 0) {
+    if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {
+      *FileSize = AsciiStrDecimalToUintn ((CHAR8 *)Option->ValueStr);
+      break;
+    }
+    OptCnt--;
+    Option++;
+  }
+  FreePool (TableOfOptions);
+
+  if (OptCnt == 0) {
+    Status = EFI_UNSUPPORTED;
+  }
+
+Error :
+
+  return Status;
+}
+
+/**
+  Worker function that download the data of a file from a TFTP server given
+  the path of the file and its size.
+
+  @param[in]   Mtftp4         MTFTP4 protocol interface
+  @param[in]   FilePath       Path of the file, Unicode encoded
+  @param[in]   AsciiFilePath  Path of the file, ASCII encoded
+  @param[in]   FileSize       Size of the file in number of bytes
+  @param[out]  Data           Address where to store the address of the buffer
+                              where the data of the file were downloaded in
+                              case of success.
+
+  @retval  EFI_SUCCESS           The file was downloaded.
+  @retval  EFI_OUT_OF_RESOURCES  A memory allocation failed.
+  @retval  Others                The downloading of the file from the server 
failed
+                                 (see EFI_MTFTP4_PROTOCOL.ReadFile() status 
codes).
+
+**/
+STATIC
+EFI_STATUS
+DownloadFile (
+  IN   EFI_MTFTP4_PROTOCOL  *Mtftp4,
+  IN   CONST CHAR16         *FilePath,
+  IN   CONST CHAR8          *AsciiFilePath,
+  IN   UINTN                FileSize,
+  OUT  VOID                 **Data
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PHYSICAL_ADDRESS  PagesAddress;
+  VOID                  *Buffer;
+  DOWNLOAD_CONTEXT      *TftpContext;
+  EFI_MTFTP4_TOKEN      Mtftp4Token;
+
+  // Downloaded file can be large. BS.AllocatePages() is more faster
+  // than AllocatePool() and avoid fragmentation.
+  // The downloaded file could be an EFI application. Marking the
+  // allocated page as EfiBootServicesCode would allow to execute a
+  // potential downloaded EFI application.
+  Status = gBS->AllocatePages (
+                   AllocateAnyPages,
+                   EfiBootServicesCode,
+                   EFI_SIZE_TO_PAGES (FileSize),
+                   &PagesAddress
+                   );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Buffer = (VOID*)(UINTN)PagesAddress;
+  TftpContext = AllocatePool (sizeof (DOWNLOAD_CONTEXT));
+  if (TftpContext == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Error;
+  }
+  TftpContext->FileSize = FileSize;
+  TftpContext->DownloadedNbOfBytes   = 0;
+  TftpContext->LastReportedNbOfBytes = 0;
+
+  ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));
+  Mtftp4Token.Filename    = (UINT8*)AsciiFilePath;
+  Mtftp4Token.BufferSize  = FileSize;
+  Mtftp4Token.Buffer      = Buffer;
+  Mtftp4Token.CheckPacket = CheckPacket;
+  Mtftp4Token.Context     = (VOID*)TftpContext;
+
+  ShellPrintHiiEx (
+    -1, -1, NULL, STRING_TOKEN (STR_TFTP_DOWNLOADING),
+    gShellTftpHiiHandle, FilePath
+    );
+
+  Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);
+  ShellPrintHiiEx (
+    -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF),
+    gShellTftpHiiHandle
+    );
+
+Error :
+
+  if (TftpContext == NULL) {
+    FreePool (TftpContext);
+  }
+
+  if (EFI_ERROR (Status)) {
+    gBS->FreePages (PagesAddress, EFI_SIZE_TO_PAGES (FileSize));
+    return Status;
+  }
+
+  *Data = Buffer;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Update the progress of a file download
+  This procedure is called each time a new TFTP packet is received.
+
+  @param[in]  This       MTFTP4 protocol interface
+  @param[in]  Token      Parameters for the download of the file
+  @param[in]  PacketLen  Length of the packet
+  @param[in]  Packet     Address of the packet
+
+  @retval  EFI_SUCCESS  All packets are accepted.
+
+**/
+STATIC
+EFI_STATUS
+CheckPacket (
+  IN EFI_MTFTP4_PROTOCOL  *This,
+  IN EFI_MTFTP4_TOKEN     *Token,
+  IN UINT16               PacketLen,
+  IN EFI_MTFTP4_PACKET    *Packet
+  )
+{
+  DOWNLOAD_CONTEXT  *Context;
+  CHAR16            Progress[TFTP_PROGRESS_MESSAGE_SIZE];
+  UINT64            NbOfKb;
+  UINTN             Index;
+  UINTN             LastStep;
+  UINTN             Step;
+
+  if ((NTOHS (Packet->OpCode)) != EFI_MTFTP4_OPCODE_DATA) {
+    return EFI_SUCCESS;
+  }
+
+  Context = (DOWNLOAD_CONTEXT*)Token->Context;
+  if (Context->DownloadedNbOfBytes == 0) {
+    ShellPrintEx (-1, -1, L"%s       0 Kb", mTftpProgressFrame);
+  }
+
+  //
+  // The data in the packet are prepended with two UINT16 :
+  // . OpCode = EFI_MTFTP4_OPCODE_DATA
+  // . Block  = the number of this block of data
+  //
+  Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode)
+                                            - sizeof (Packet->Data.Block);
+  NbOfKb = Context->DownloadedNbOfBytes / 1024;
+
+  Progress[0] = L'\0';
+  LastStep  = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) /
+              Context->FileSize;
+  Step      = (Context->DownloadedNbOfBytes   * TFTP_PROGRESS_SLIDER_STEPS) /
+              Context->FileSize;
+  if (Step <= LastStep) {
+    return EFI_SUCCESS;
+  }
+
+  ShellPrintEx (-1, -1, L"%s", mTftpProgressDelete);
+
+  StrCpy (Progress, mTftpProgressFrame);
+  for (Index = 1; Index < Step; Index++) {
+    Progress[Index] = L'=';
+  }
+  Progress[Step] = L'>';
+
+  UnicodeSPrint (
+    Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1,
+    sizeof (Progress) - sizeof (mTftpProgressFrame),
+    L" %7d Kb",
+    NbOfKb
+    );
+  Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;
+
+  ShellPrintEx (-1, -1, L"%s", Progress);
+
+  return EFI_SUCCESS;
+}

Added: 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.c
===================================================================
--- 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.c   
                            (rev 0)
+++ 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.c   
    2015-07-26 07:36:51 UTC (rev 18015)
@@ -0,0 +1,97 @@
+/** @file
+  Main file for NULL named library for 'tftp' Shell command functions.
+
+  Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved. <BR>
+  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD 
License
+  which accompanies this distribution.  The full text of the license may be 
found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "UefiShellTftpCommandLib.h"
+
+CONST CHAR16 gShellTftpFileName[] = L"ShellCommand";
+EFI_HANDLE gShellTftpHiiHandle = NULL;
+
+/**
+  Return the file name of the help text file if not using HII.
+
+  @return The string pointer to the file name.
+**/
+CONST CHAR16*
+EFIAPI
+ShellCommandGetManFileNameTftp (
+  VOID
+  )
+{
+  return gShellTftpFileName;
+}
+
+/**
+  Constructor for the Shell Tftp Command library.
+
+  Install the handlers for Tftp UEFI Shell command.
+
+  @param ImageHandle            The image handle of the process.
+  @param SystemTable            The EFI System Table pointer.
+
+  @retval EFI_SUCCESS           The Shell command handlers were installed 
sucessfully.
+  @retval EFI_UNSUPPORTED       The Shell level required was not found.
+**/
+EFI_STATUS
+EFIAPI
+ShellTftpCommandLibConstructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  gShellTftpHiiHandle = NULL;
+
+  //
+  // check our bit of the profiles mask
+  //
+  if ((PcdGet8 (PcdShellProfileMask) & BIT3) == 0) {
+    return EFI_SUCCESS;
+  }
+
+  gShellTftpHiiHandle = HiiAddPackages (
+                          &gShellTftpHiiGuid, gImageHandle,
+                          UefiShellTftpCommandLibStrings, NULL
+                          );
+  if (gShellTftpHiiHandle == NULL) {
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // Install our Shell command handler
+  //
+  ShellCommandRegisterCommandName (
+     L"tftp", ShellCommandRunTftp, ShellCommandGetManFileNameTftp, 0,
+     L"tftp", TRUE , gShellTftpHiiHandle, STRING_TOKEN (STR_GET_HELP_TFTP)
+     );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Destructor for the library.  free any resources.
+
+  @param ImageHandle            The image handle of the process.
+  @param SystemTable            The EFI System Table pointer.
+**/
+EFI_STATUS
+EFIAPI
+ShellTftpCommandLibDestructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  if (gShellTftpHiiHandle != NULL) {
+    HiiRemovePackages (gShellTftpHiiHandle);
+  }
+  return EFI_SUCCESS;
+}

Added: 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.h
===================================================================
--- 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.h   
                            (rev 0)
+++ 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.h   
    2015-07-26 07:36:51 UTC (rev 18015)
@@ -0,0 +1,63 @@
+/** @file
+  header file for NULL named library for 'tftp' Shell command functions.
+
+  Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved. <BR>
+  Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD 
License
+  which accompanies this distribution.  The full text of the license may be 
found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _UEFI_SHELL_TFTP_COMMAND_LIB_H_
+#define _UEFI_SHELL_TFTP_COMMAND_LIB_H_
+
+#include <Uefi.h>
+#include <ShellBase.h>
+
+#include <Guid/ShellLibHiiGuid.h>
+#include <Guid/NicIp4ConfigNvData.h>
+
+#include <Protocol/ServiceBinding.h>
+#include <Protocol/Mtftp4.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ShellCommandLib.h>
+#include <Library/ShellLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HiiLib.h>
+#include <Library/NetLib.h>
+#include <Library/PrintLib.h>
+
+extern EFI_HANDLE gShellTftpHiiHandle;
+
+typedef struct {
+  UINT64  FileSize;
+  UINT64  DownloadedNbOfBytes;
+  UINT64  LastReportedNbOfBytes;
+} DOWNLOAD_CONTEXT;
+
+/**
+  Function for 'tftp' command.
+
+  @param[in] ImageHandle  Handle to the Image (NULL if Internal).
+  @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
+**/
+SHELL_STATUS
+EFIAPI
+ShellCommandRunTftp (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+#endif /* _UEFI_SHELL_TFTP_COMMAND_LIB_H_ */

Added: 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf
===================================================================
--- 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf 
                            (rev 0)
+++ 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf 
    2015-07-26 07:36:51 UTC (rev 18015)
@@ -0,0 +1,61 @@
+##  @file
+# Provides Shell 'tftp' command functions
+#
+# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved. <BR>
+# Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD 
License
+#  which accompanies this distribution. The full text of the license may be 
found at
+#  http://opensource.org/licenses/bsd-license.php
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR 
IMPLIED.
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010006
+  BASE_NAME                      = UefiShellTftpCommandLib
+  FILE_GUID                      = D2B61A25-9835-4E5D-906A-15615E1FF668
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = NULL|UEFI_APPLICATION UEFI_DRIVER
+  CONSTRUCTOR                    = ShellTftpCommandLibConstructor
+  DESTRUCTOR                     = ShellTftpCommandLibDestructor
+
+[Sources.common]
+  UefiShellTftpCommandLib.uni
+  UefiShellTftpCommandLib.c
+  UefiShellTftpCommandLib.h
+  Tftp.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  ShellPkg/ShellPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  ShellCommandLib
+  ShellLib
+  UefiLib
+  UefiRuntimeServicesTableLib
+  UefiBootServicesTableLib
+  PcdLib
+  HiiLib
+  FileHandleLib
+  NetLib
+
+[Pcd]
+  gEfiShellPkgTokenSpaceGuid.PcdShellProfileMask ## CONSUMES
+
+[Protocols]
+  gEfiManagedNetworkServiceBindingProtocolGuid   ## CONSUMES
+  gEfiMtftp4ServiceBindingProtocolGuid           ## CONSUMES
+
+[Guids]
+  gShellTftpHiiGuid                              ## CONSUMES ## HII

Added: 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.uni
===================================================================
--- 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.uni 
                            (rev 0)
+++ 
trunk/edk2/ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.uni 
    2015-07-26 07:36:51 UTC (rev 18015)
@@ -0,0 +1,167 @@
+\xFF\xFE/+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\
 No newline at end of file

Modified: trunk/edk2/ShellPkg/ShellPkg.dec
===================================================================
--- trunk/edk2/ShellPkg/ShellPkg.dec    2015-07-15 03:46:13 UTC (rev 18014)
+++ trunk/edk2/ShellPkg/ShellPkg.dec    2015-07-26 07:36:51 UTC (rev 18015)
@@ -53,6 +53,7 @@
   gShellLevel2HiiGuid             = {0xf95a7ccc, 0x4c55, 0x4426, {0xa7, 0xb4, 
0xdc, 0x89, 0x61, 0x95, 0xb, 0xae}}
   gShellLevel3HiiGuid             = {0x4344558d, 0x4ef9, 0x4725, {0xb1, 0xe4, 
0x33, 0x76, 0xe8, 0xd6, 0x97, 0x4f}}
   gShellNetwork1HiiGuid           = {0xf3d301bb, 0xf4a5, 0x45a8, {0xb0, 0xb7, 
0xfa, 0x99, 0x9c, 0x62, 0x37, 0xae}}
+  gShellTftpHiiGuid               = {0x738a9314, 0x82c1, 0x4592, {0x8f, 0xf7, 
0xc1, 0xbd, 0xf1, 0xb2, 0x0e, 0xd4}}
   gShellBcfgHiiGuid               = {0x5f5f605d, 0x1583, 0x4a2d, {0xa6, 0xb2, 
0xeb, 0x12, 0xda, 0xb4, 0xa2, 0xb6}}
 
 [Protocols]

Modified: trunk/edk2/ShellPkg/ShellPkg.dsc
===================================================================
--- trunk/edk2/ShellPkg/ShellPkg.dsc    2015-07-15 03:46:13 UTC (rev 18014)
+++ trunk/edk2/ShellPkg/ShellPkg.dsc    2015-07-26 07:36:51 UTC (rev 18015)
@@ -98,6 +98,9 @@
 !ifdef $(INCLUDE_DP)
       NULL|ShellPkg/Library/UefiDpLib/UefiDpLib.inf
 !endif #$(INCLUDE_DP)
+!ifdef $(INCLUDE_TFTP_COMMAND)
+      NULL|ShellPkg/Library/UefiShellTftpCommandLib/UefiShellTftpCommandLib.inf
+!endif #$(INCLUDE_TFTP_COMMAND)
 !endif #$(NO_SHELL_PROFILES)
   }
 


------------------------------------------------------------------------------
_______________________________________________
edk2-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-commits

Reply via email to