Home | History | Annotate | Download | only in Bds
      1 /** @file
      2 *
      3 *  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
      4 *
      5 *  This program and the accompanying materials
      6 *  are licensed and made available under the terms and conditions of the BSD License
      7 *  which accompanies this distribution.  The full text of the license may be found at
      8 *  http://opensource.org/licenses/bsd-license.php
      9 *
     10 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 *
     13 **/
     14 
     15 #include "BdsInternal.h"
     16 
     17 #include <Library/NetLib.h>
     18 
     19 #include <Protocol/BlockIo.h>
     20 #include <Protocol/DevicePathToText.h>
     21 #include <Protocol/FirmwareVolumeBlock.h>
     22 #include <Protocol/PxeBaseCode.h>
     23 #include <Protocol/SimpleFileSystem.h>
     24 #include <Protocol/SimpleNetwork.h>
     25 #include <Protocol/Dhcp4.h>
     26 #include <Protocol/Mtftp4.h>
     27 
     28 #include <Guid/FileSystemInfo.h>
     29 
     30 #define IS_DEVICE_PATH_NODE(node,type,subtype) (((node)->Type == (type)) && ((node)->SubType == (subtype)))
     31 
     32 EFI_STATUS
     33 BdsLoadOptionFileSystemList (
     34   IN OUT LIST_ENTRY* BdsLoadOptionList
     35   );
     36 
     37 EFI_STATUS
     38 BdsLoadOptionFileSystemCreateDevicePath (
     39   IN CHAR16*                    FileName,
     40   OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePathNodes
     41   );
     42 
     43 EFI_STATUS
     44 BdsLoadOptionFileSystemUpdateDevicePath (
     45   IN EFI_DEVICE_PATH            *OldDevicePath,
     46   IN CHAR16*                    FileName,
     47   OUT EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath
     48   );
     49 
     50 BOOLEAN
     51 BdsLoadOptionFileSystemIsSupported (
     52   IN  EFI_DEVICE_PATH           *DevicePath
     53   );
     54 
     55 EFI_STATUS
     56 BdsLoadOptionMemMapList (
     57   IN OUT LIST_ENTRY* BdsLoadOptionList
     58   );
     59 
     60 EFI_STATUS
     61 BdsLoadOptionMemMapCreateDevicePath (
     62   IN CHAR16*                    FileName,
     63   OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePathNodes
     64   );
     65 
     66 EFI_STATUS
     67 BdsLoadOptionMemMapUpdateDevicePath (
     68   IN EFI_DEVICE_PATH            *OldDevicePath,
     69   IN CHAR16*                    FileName,
     70   OUT EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath
     71   );
     72 
     73 BOOLEAN
     74 BdsLoadOptionMemMapIsSupported (
     75   IN  EFI_DEVICE_PATH           *DevicePath
     76   );
     77 
     78 EFI_STATUS
     79 BdsLoadOptionPxeList (
     80   IN OUT LIST_ENTRY* BdsLoadOptionList
     81   );
     82 
     83 EFI_STATUS
     84 BdsLoadOptionPxeCreateDevicePath (
     85   IN CHAR16*                    FileName,
     86   OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePathNodes
     87   );
     88 
     89 EFI_STATUS
     90 BdsLoadOptionPxeUpdateDevicePath (
     91   IN EFI_DEVICE_PATH            *OldDevicePath,
     92   IN CHAR16*                    FileName,
     93   OUT EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath
     94   );
     95 
     96 BOOLEAN
     97 BdsLoadOptionPxeIsSupported (
     98   IN  EFI_DEVICE_PATH           *DevicePath
     99   );
    100 
    101 EFI_STATUS
    102 BdsLoadOptionTftpList (
    103   IN OUT LIST_ENTRY* BdsLoadOptionList
    104   );
    105 
    106 EFI_STATUS
    107 BdsLoadOptionTftpCreateDevicePath (
    108   IN CHAR16*                    FileName,
    109   OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePathNodes
    110   );
    111 
    112 EFI_STATUS
    113 BdsLoadOptionTftpUpdateDevicePath (
    114   IN EFI_DEVICE_PATH            *OldDevicePath,
    115   IN CHAR16*                    FileName,
    116   OUT EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath
    117   );
    118 
    119 BOOLEAN
    120 BdsLoadOptionTftpIsSupported (
    121   IN  EFI_DEVICE_PATH           *DevicePath
    122   );
    123 
    124 BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList[] = {
    125   {
    126     BDS_DEVICE_FILESYSTEM,
    127     BdsLoadOptionFileSystemList,
    128     BdsLoadOptionFileSystemIsSupported,
    129     BdsLoadOptionFileSystemCreateDevicePath,
    130     BdsLoadOptionFileSystemUpdateDevicePath,
    131     TRUE
    132   },
    133   {
    134     BDS_DEVICE_MEMMAP,
    135     BdsLoadOptionMemMapList,
    136     BdsLoadOptionMemMapIsSupported,
    137     BdsLoadOptionMemMapCreateDevicePath,
    138     BdsLoadOptionMemMapUpdateDevicePath,
    139     TRUE
    140   },
    141   {
    142     BDS_DEVICE_PXE,
    143     BdsLoadOptionPxeList,
    144     BdsLoadOptionPxeIsSupported,
    145     BdsLoadOptionPxeCreateDevicePath,
    146     BdsLoadOptionPxeUpdateDevicePath,
    147     FALSE
    148   },
    149   {
    150     BDS_DEVICE_TFTP,
    151     BdsLoadOptionTftpList,
    152     BdsLoadOptionTftpIsSupported,
    153     BdsLoadOptionTftpCreateDevicePath,
    154     BdsLoadOptionTftpUpdateDevicePath,
    155     TRUE
    156   }
    157 };
    158 
    159 EFI_STATUS
    160 BootDeviceListSupportedInit (
    161   IN OUT LIST_ENTRY *SupportedDeviceList
    162   )
    163 {
    164   UINTN   Index;
    165 
    166   // Initialize list of supported devices
    167   InitializeListHead (SupportedDeviceList);
    168 
    169   for (Index = 0; Index < BDS_DEVICE_MAX; Index++) {
    170     BdsLoadOptionSupportList[Index].ListDevices (SupportedDeviceList);
    171   }
    172 
    173   return EFI_SUCCESS;
    174 }
    175 
    176 EFI_STATUS
    177 BootDeviceListSupportedFree (
    178   IN LIST_ENTRY *SupportedDeviceList,
    179   IN BDS_SUPPORTED_DEVICE *Except
    180   )
    181 {
    182   LIST_ENTRY  *Entry;
    183   BDS_SUPPORTED_DEVICE* SupportedDevice;
    184 
    185   Entry = GetFirstNode (SupportedDeviceList);
    186   while (Entry != SupportedDeviceList) {
    187     SupportedDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
    188     Entry = RemoveEntryList (Entry);
    189     if (SupportedDevice != Except) {
    190       FreePool (SupportedDevice);
    191     }
    192   }
    193 
    194   return EFI_SUCCESS;
    195 }
    196 
    197 EFI_STATUS
    198 BootDeviceGetDeviceSupport (
    199   IN  EFI_DEVICE_PATH           *DevicePath,
    200   OUT BDS_LOAD_OPTION_SUPPORT   **DeviceSupport
    201   )
    202 {
    203   UINTN Index;
    204 
    205   // Find which supported device is the most appropriate
    206   for (Index = 0; Index < BDS_DEVICE_MAX; Index++) {
    207     if (BdsLoadOptionSupportList[Index].IsSupported (DevicePath)) {
    208       *DeviceSupport = &BdsLoadOptionSupportList[Index];
    209       return EFI_SUCCESS;
    210     }
    211   }
    212 
    213   return EFI_UNSUPPORTED;
    214 }
    215 
    216 EFI_STATUS
    217 BdsLoadOptionFileSystemList (
    218   IN OUT LIST_ENTRY* BdsLoadOptionList
    219   )
    220 {
    221   EFI_STATUS                        Status;
    222   UINTN                             HandleCount;
    223   EFI_HANDLE                        *HandleBuffer;
    224   UINTN                             Index;
    225   BDS_SUPPORTED_DEVICE              *SupportedDevice;
    226   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL*  FileProtocol;
    227   EFI_FILE_HANDLE                   Fs;
    228   UINTN                             Size;
    229   EFI_FILE_SYSTEM_INFO*             FsInfo;
    230   EFI_DEVICE_PATH_PROTOCOL*         DevicePathProtocol;
    231 
    232   // List all the Simple File System Protocols
    233   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer);
    234   if (EFI_ERROR (Status)) {
    235     return Status;
    236   }
    237 
    238   for (Index = 0; Index < HandleCount; Index++) {
    239     Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
    240     if (!EFI_ERROR(Status)) {
    241       // Allocate BDS Supported Device structure
    242       SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool (sizeof(BDS_SUPPORTED_DEVICE));
    243 
    244       FileProtocol = NULL;
    245       Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FileProtocol);
    246       ASSERT_EFI_ERROR(Status);
    247 
    248       FileProtocol->OpenVolume (FileProtocol, &Fs);
    249 
    250       // Generate a Description from the file system
    251       Size = 0;
    252       FsInfo = NULL;
    253       Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo);
    254       if (Status == EFI_BUFFER_TOO_SMALL) {
    255         FsInfo = AllocatePool (Size);
    256         Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo);
    257       }
    258       UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"%s (%d MB)",FsInfo->VolumeLabel,(UINT32)(FsInfo->VolumeSize / (1024 * 1024)));
    259       FreePool(FsInfo);
    260       Fs->Close (Fs);
    261 
    262       SupportedDevice->DevicePathProtocol = DevicePathProtocol;
    263       SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_FILESYSTEM];
    264 
    265       InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
    266     }
    267   }
    268 
    269   return EFI_SUCCESS;
    270 }
    271 
    272 EFI_STATUS
    273 BdsLoadOptionFileSystemCreateDevicePath (
    274   IN CHAR16*                    FileName,
    275   OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePathNodes
    276   )
    277 {
    278   EFI_STATUS  Status;
    279   FILEPATH_DEVICE_PATH* FilePathDevicePath;
    280   CHAR16      BootFilePath[BOOT_DEVICE_FILEPATH_MAX];
    281   UINTN       BootFilePathSize;
    282 
    283   Print(L"File path of the %s: ", FileName);
    284   Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);
    285   if (EFI_ERROR(Status)) {
    286     return EFI_ABORTED;
    287   }
    288 
    289   BootFilePathSize = StrSize (BootFilePath);
    290   if (BootFilePathSize == 2) {
    291     *DevicePathNodes = NULL;
    292     return EFI_NOT_FOUND;
    293   }
    294 
    295   // Create the FilePath Device Path node
    296   FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH);
    297   FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
    298   FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
    299   SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
    300   CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
    301   SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize));
    302   *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)FilePathDevicePath;
    303 
    304   return Status;
    305 }
    306 
    307 EFI_STATUS
    308 BdsLoadOptionFileSystemUpdateDevicePath (
    309   IN EFI_DEVICE_PATH            *OldDevicePath,
    310   IN CHAR16*                    FileName,
    311   OUT EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath
    312   )
    313 {
    314   EFI_STATUS  Status;
    315   CHAR16      BootFilePath[BOOT_DEVICE_FILEPATH_MAX];
    316   UINTN       BootFilePathSize;
    317   FILEPATH_DEVICE_PATH* EndingDevicePath;
    318   FILEPATH_DEVICE_PATH* FilePathDevicePath;
    319   EFI_DEVICE_PATH*  DevicePath;
    320 
    321   DevicePath = DuplicateDevicePath (OldDevicePath);
    322 
    323   EndingDevicePath = (FILEPATH_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);
    324 
    325   Print(L"File path of the %s: ", FileName);
    326   StrnCpy (BootFilePath, EndingDevicePath->PathName, BOOT_DEVICE_FILEPATH_MAX);
    327   Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);
    328   if (EFI_ERROR(Status)) {
    329     return Status;
    330   }
    331 
    332   BootFilePathSize = StrSize(BootFilePath);
    333   if (BootFilePathSize == 2) {
    334     *NewDevicePath = NULL;
    335     return EFI_NOT_FOUND;
    336   }
    337 
    338   // Create the FilePath Device Path node
    339   FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
    340   FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
    341   FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
    342   SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
    343   CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
    344 
    345   // Generate the new Device Path by replacing the last node by the updated node
    346   SetDevicePathEndNode (EndingDevicePath);
    347   *NewDevicePath = AppendDevicePathNode (DevicePath, (CONST EFI_DEVICE_PATH_PROTOCOL *)FilePathDevicePath);
    348   FreePool(DevicePath);
    349 
    350   return EFI_SUCCESS;
    351 }
    352 
    353 /**
    354   Check if a boot option path is a file system boot option path or not.
    355 
    356   The device specified by the beginning of the path has to support the Simple File
    357   System protocol. Furthermore, the remaining part of the path has to be composed of
    358   a single node of type MEDIA_DEVICE_PATH and sub-type MEDIA_FILEPATH_DP.
    359 
    360   @param[in]  DevicePath  Complete device path of a boot option.
    361 
    362   @retval  FALSE  The boot option path has not been identified as that of a
    363                   file system boot option.
    364   @retval  TRUE   The boot option path is a file system boot option.
    365 **/
    366 BOOLEAN
    367 BdsLoadOptionFileSystemIsSupported (
    368   IN  EFI_DEVICE_PATH  *DevicePath
    369   )
    370 {
    371   EFI_STATUS                        Status;
    372   EFI_HANDLE                        Handle;
    373   EFI_DEVICE_PATH                  *RemainingDevicePath;
    374   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *FileProtocol;
    375 
    376   Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
    377   if (EFI_ERROR (Status)) {
    378     return FALSE;
    379   }
    380 
    381   Status = gBS->HandleProtocol (
    382                    Handle,
    383                    &gEfiSimpleFileSystemProtocolGuid,
    384                    (VOID **)(&FileProtocol)
    385                    );
    386   if (EFI_ERROR (Status)) {
    387     return FALSE;
    388   }
    389 
    390   if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP))
    391     return FALSE;
    392 
    393   return TRUE;
    394 }
    395 
    396 STATIC
    397 BOOLEAN
    398 IsParentDevicePath (
    399   IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
    400   IN EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath
    401   )
    402 {
    403   UINTN ParentSize;
    404   UINTN ChildSize;
    405 
    406   ParentSize = GetDevicePathSize (ParentDevicePath);
    407   ChildSize = GetDevicePathSize (ChildDevicePath);
    408 
    409   if (ParentSize > ChildSize) {
    410     return FALSE;
    411   }
    412 
    413   if (CompareMem (ParentDevicePath, ChildDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0) {
    414     return FALSE;
    415   }
    416 
    417   return TRUE;
    418 }
    419 
    420 EFI_STATUS
    421 BdsLoadOptionMemMapList (
    422   IN OUT LIST_ENTRY* BdsLoadOptionList
    423   )
    424 {
    425   EFI_STATUS                          Status;
    426   UINTN                               HandleCount;
    427   EFI_HANDLE                         *HandleBuffer;
    428   UINTN                               DevicePathHandleCount;
    429   EFI_HANDLE                         *DevicePathHandleBuffer;
    430   BOOLEAN                             IsParent;
    431   UINTN                               Index;
    432   UINTN                               Index2;
    433   BDS_SUPPORTED_DEVICE               *SupportedDevice;
    434   EFI_DEVICE_PATH_PROTOCOL*           DevicePathProtocol;
    435   EFI_DEVICE_PATH*                    DevicePath;
    436   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL    *FileProtocol;
    437   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
    438 
    439   // List all the BlockIo Protocols
    440   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);
    441   if (EFI_ERROR (Status)) {
    442     return Status;
    443   }
    444 
    445   for (Index = 0; Index < HandleCount; Index++) {
    446     // We only select handles WITH a Device Path AND not part of Media (to
    447     // avoid duplication with HardDisk, CDROM, etc). Skip handles used by
    448     // Simple Filesystem or used for Variable Storage.
    449 
    450 
    451     Status = gBS->HandleProtocol (HandleBuffer[Index],
    452                                   &gEfiSimpleFileSystemProtocolGuid,
    453                                   (VOID *)&FileProtocol);
    454     if (!EFI_ERROR(Status)) {
    455       // SimpleFilesystem supported on this handle, skip
    456       continue;
    457     }
    458 
    459     Status = gBS->HandleProtocol (HandleBuffer[Index],
    460                                   &gEfiFirmwareVolumeBlockProtocolGuid,
    461                                   (VOID *)&FvbProtocol);
    462     if (!EFI_ERROR(Status)) {
    463       // Firmware Volme Block / Variable storage supported on this handle, skip
    464       continue;
    465     }
    466 
    467     Status = gBS->HandleProtocol (HandleBuffer[Index],
    468                                   &gEfiFirmwareVolumeBlock2ProtocolGuid,
    469                                   (VOID *)&FvbProtocol);
    470     if (!EFI_ERROR(Status)) {
    471       // Firmware Volme Block / Variable storage supported on this handle, skip
    472       continue;
    473     }
    474 
    475     Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
    476     if (!EFI_ERROR(Status)) {
    477       // BlockIo is not part of Media Device Path
    478       DevicePath = DevicePathProtocol;
    479       while (!IsDevicePathEndType (DevicePath) && (DevicePathType (DevicePath) != MEDIA_DEVICE_PATH)) {
    480         DevicePath = NextDevicePathNode (DevicePath);
    481       }
    482       if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) {
    483         continue;
    484       }
    485 
    486       // Open all the handle supporting the DevicePath protocol and verify this handle has not got any child
    487       Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &DevicePathHandleCount, &DevicePathHandleBuffer);
    488       ASSERT_EFI_ERROR (Status);
    489       IsParent = FALSE;
    490       for (Index2 = 0; (Index2 < DevicePathHandleCount) && !IsParent; Index2++) {
    491         if (HandleBuffer[Index] != DevicePathHandleBuffer[Index2]) {
    492           gBS->HandleProtocol (DevicePathHandleBuffer[Index2], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
    493           if (IsParentDevicePath (DevicePathProtocol, DevicePath)) {
    494             IsParent = TRUE;
    495           }
    496         }
    497       }
    498       if (IsParent) {
    499         continue;
    500       }
    501 
    502       // Allocate BDS Supported Device structure
    503       SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
    504 
    505       Status = GenerateDeviceDescriptionName (HandleBuffer[Index], SupportedDevice->Description);
    506       ASSERT_EFI_ERROR (Status);
    507 
    508       SupportedDevice->DevicePathProtocol = DevicePathProtocol;
    509       SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_MEMMAP];
    510 
    511       InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
    512     }
    513   }
    514 
    515   return EFI_SUCCESS;
    516 }
    517 
    518 EFI_STATUS
    519 BdsLoadOptionMemMapCreateDevicePath (
    520   IN CHAR16*                    FileName,
    521   OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePathNodes
    522   )
    523 {
    524   EFI_STATUS              Status;
    525   MEMMAP_DEVICE_PATH      *MemMapDevicePath;
    526   CHAR16                  StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX];
    527   CHAR16                  StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX];
    528 
    529   Print(L"Starting Address of the %s: ", FileName);
    530   Status = GetHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX);
    531   if (EFI_ERROR(Status)) {
    532     return EFI_ABORTED;
    533   }
    534 
    535   Print(L"Ending Address of the %s: ", FileName);
    536   Status = GetHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX);
    537   if (EFI_ERROR(Status)) {
    538     return EFI_ABORTED;
    539   }
    540 
    541   // Create the MemMap Device Path Node
    542   MemMapDevicePath = (MEMMAP_DEVICE_PATH*)AllocatePool (sizeof(MEMMAP_DEVICE_PATH) + END_DEVICE_PATH_LENGTH);
    543   MemMapDevicePath->Header.Type = HARDWARE_DEVICE_PATH;
    544   MemMapDevicePath->Header.SubType = HW_MEMMAP_DP;
    545   SetDevicePathNodeLength (MemMapDevicePath, sizeof(MEMMAP_DEVICE_PATH));
    546   MemMapDevicePath->MemoryType = EfiBootServicesData;
    547   MemMapDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress);
    548   MemMapDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress);
    549 
    550   // Set a Device Path End Node after the Memory Map Device Path Node
    551   SetDevicePathEndNode (MemMapDevicePath + 1);
    552   *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)MemMapDevicePath;
    553 
    554   return Status;
    555 }
    556 
    557 EFI_STATUS
    558 BdsLoadOptionMemMapUpdateDevicePath (
    559   IN EFI_DEVICE_PATH            *OldDevicePath,
    560   IN CHAR16*                    FileName,
    561   OUT EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath
    562   )
    563 {
    564   EFI_STATUS          Status;
    565   CHAR16              StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX];
    566   CHAR16              StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX];
    567   MEMMAP_DEVICE_PATH* EndingDevicePath;
    568   EFI_DEVICE_PATH*    DevicePath;
    569 
    570   DevicePath = DuplicateDevicePath (OldDevicePath);
    571   EndingDevicePath = (MEMMAP_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);
    572 
    573   Print(L"Starting Address of the %s: ", FileName);
    574   UnicodeSPrint (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->StartingAddress);
    575   Status = EditHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX);
    576   if (EFI_ERROR(Status)) {
    577     return EFI_ABORTED;
    578   }
    579 
    580   Print(L"Ending Address of the %s: ", FileName);
    581   UnicodeSPrint (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->EndingAddress);
    582   Status = EditHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX);
    583   if (EFI_ERROR(Status)) {
    584     return EFI_ABORTED;
    585   }
    586 
    587   EndingDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress);
    588   EndingDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress);
    589 
    590   if (EFI_ERROR(Status)) {
    591     FreePool(DevicePath);
    592   } else {
    593     *NewDevicePath = DevicePath;
    594   }
    595 
    596   return Status;
    597 }
    598 
    599 /**
    600   Check if a boot option path is a memory map boot option path or not.
    601 
    602   The device specified by the beginning of the path has to support the BlockIo
    603   protocol. Furthermore, the remaining part of the path has to be composed of
    604   a single node of type HARDWARE_DEVICE_PATH and sub-type HW_MEMMAP_DP.
    605 
    606   @param[in]  DevicePath  Complete device path of a boot option.
    607 
    608   @retval  FALSE  The boot option path has not been identified as that of a
    609                   memory map boot option.
    610   @retval  TRUE   The boot option path is a a memory map boot option.
    611 **/
    612 BOOLEAN
    613 BdsLoadOptionMemMapIsSupported (
    614   IN  EFI_DEVICE_PATH  *DevicePath
    615   )
    616 {
    617   EFI_STATUS              Status;
    618   EFI_HANDLE              Handle;
    619   EFI_DEVICE_PATH        *RemainingDevicePath;
    620   EFI_BLOCK_IO_PROTOCOL  *BlockIoProtocol;
    621 
    622   Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
    623   if (EFI_ERROR (Status)) {
    624     return FALSE;
    625   }
    626 
    627   Status = gBS->HandleProtocol (
    628                   Handle,
    629                   &gEfiBlockIoProtocolGuid,
    630                   (VOID **)(&BlockIoProtocol)
    631                   );
    632   if (EFI_ERROR (Status)) {
    633     return FALSE;
    634   }
    635 
    636   if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP))
    637     return FALSE;
    638 
    639   return TRUE;
    640 }
    641 
    642 EFI_STATUS
    643 BdsLoadOptionPxeList (
    644   IN OUT LIST_ENTRY* BdsLoadOptionList
    645   )
    646 {
    647   EFI_STATUS                        Status;
    648   UINTN                             HandleCount;
    649   EFI_HANDLE                        *HandleBuffer;
    650   UINTN                             Index;
    651   BDS_SUPPORTED_DEVICE              *SupportedDevice;
    652   EFI_DEVICE_PATH_PROTOCOL*         DevicePathProtocol;
    653   EFI_SIMPLE_NETWORK_PROTOCOL*      SimpleNet;
    654   CHAR16                            DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];
    655   EFI_MAC_ADDRESS                   *Mac;
    656 
    657   // List all the PXE Protocols
    658   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);
    659   if (EFI_ERROR (Status)) {
    660     return Status;
    661   }
    662 
    663   for (Index = 0; Index < HandleCount; Index++) {
    664     // We only select the handle WITH a Device Path AND the PXE Protocol
    665     Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
    666     if (!EFI_ERROR(Status)) {
    667       // Allocate BDS Supported Device structure
    668       SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
    669 
    670       Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimpleNetworkProtocolGuid, (VOID **)&SimpleNet);
    671       if (!EFI_ERROR(Status)) {
    672         Mac = &SimpleNet->Mode->CurrentAddress;
    673         UnicodeSPrint (DeviceDescription,BOOT_DEVICE_DESCRIPTION_MAX,L"MAC Address: %02x:%02x:%02x:%02x:%02x:%02x", Mac->Addr[0],  Mac->Addr[1],  Mac->Addr[2],  Mac->Addr[3],  Mac->Addr[4],  Mac->Addr[5]);
    674       } else {
    675         Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);
    676         ASSERT_EFI_ERROR (Status);
    677       }
    678       UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"PXE on %s",DeviceDescription);
    679 
    680       SupportedDevice->DevicePathProtocol = DevicePathProtocol;
    681       SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_PXE];
    682 
    683       InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
    684     }
    685   }
    686 
    687   return EFI_SUCCESS;
    688 }
    689 
    690 EFI_STATUS
    691 BdsLoadOptionPxeCreateDevicePath (
    692   IN CHAR16*                    FileName,
    693   OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePathNodes
    694   )
    695 {
    696   *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);
    697   SetDevicePathEndNode (*DevicePathNodes);
    698 
    699   return EFI_SUCCESS;
    700 }
    701 
    702 /**
    703   Update the parameters of a Pxe boot option
    704 
    705   @param[in]   OldDevicePath  Current complete device path of the Pxe boot option.
    706                               This has to be a valid complete Pxe boot option path.
    707   @param[in]   FileName       Description of the file the path is asked for
    708   @param[out]  NewDevicePath  Pointer to the new complete device path.
    709 
    710   @retval  EFI_SUCCESS            Update completed
    711   @retval  EFI_OUT_OF_RESOURCES   Fail to perform the update due to lack of resource
    712 **/
    713 EFI_STATUS
    714 BdsLoadOptionPxeUpdateDevicePath (
    715   IN EFI_DEVICE_PATH            *OldDevicePath,
    716   IN CHAR16*                    FileName,
    717   OUT EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath
    718   )
    719 {
    720   //
    721   // Make a copy of the complete device path that is made of :
    722   // the device path of the device supporting the Pxe base code protocol
    723   // followed by an end node.
    724   //
    725   *NewDevicePath = DuplicateDevicePath (OldDevicePath);
    726   if (*NewDevicePath == NULL) {
    727     return EFI_OUT_OF_RESOURCES;
    728   } else {
    729     return EFI_SUCCESS;
    730   }
    731 }
    732 
    733 BOOLEAN
    734 BdsLoadOptionPxeIsSupported (
    735   IN  EFI_DEVICE_PATH  *DevicePath
    736   )
    737 {
    738   EFI_STATUS  Status;
    739   EFI_HANDLE Handle;
    740   EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;
    741   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBcProtocol;
    742 
    743   Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
    744   if (EFI_ERROR(Status)) {
    745     return FALSE;
    746   }
    747 
    748   if (!IsDevicePathEnd(RemainingDevicePath)) {
    749     return FALSE;
    750   }
    751 
    752   Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
    753   if (EFI_ERROR (Status)) {
    754     return FALSE;
    755   } else {
    756     return TRUE;
    757   }
    758 }
    759 
    760 /**
    761   Add to the list of boot devices the devices allowing a TFTP boot
    762 
    763   @param[in]   BdsLoadOptionList  List of devices to boot from
    764 
    765   @retval  EFI_SUCCESS            Update completed
    766   @retval  EFI_OUT_OF_RESOURCES   Fail to perform the update due to lack of resource
    767 **/
    768 EFI_STATUS
    769 BdsLoadOptionTftpList (
    770   IN OUT LIST_ENTRY* BdsLoadOptionList
    771   )
    772 {
    773   EFI_STATUS                   Status;
    774   UINTN                        HandleCount;
    775   EFI_HANDLE                   *HandleBuffer;
    776   EFI_HANDLE                   Handle;
    777   UINTN                        Index;
    778   EFI_DEVICE_PATH_PROTOCOL     *DevicePathProtocol;
    779   VOID                         *Interface;
    780   EFI_SIMPLE_NETWORK_PROTOCOL  *SimpleNetworkProtocol;
    781   BDS_SUPPORTED_DEVICE         *SupportedDevice;
    782   EFI_MAC_ADDRESS              *Mac;
    783 
    784   //
    785   // List all the handles on which the Simple Network Protocol is installed.
    786   //
    787   Status = gBS->LocateHandleBuffer (
    788                   ByProtocol,
    789                   &gEfiSimpleNetworkProtocolGuid,
    790                   NULL,
    791                   &HandleCount,
    792                   &HandleBuffer
    793                   );
    794   if (EFI_ERROR (Status)) {
    795     return Status;
    796   }
    797 
    798   for (Index = 0; Index < HandleCount; Index++) {
    799     Handle = HandleBuffer[Index];
    800     //
    801     // We select the handles that support :
    802     // . the Device Path Protocol
    803     // . the MTFTP4 Protocol
    804     //
    805     Status = gBS->HandleProtocol (
    806                     Handle,
    807                     &gEfiDevicePathProtocolGuid,
    808                     (VOID **)&DevicePathProtocol
    809                     );
    810     if (EFI_ERROR (Status)) {
    811       continue;
    812     }
    813 
    814     Status = gBS->HandleProtocol (
    815                     Handle,
    816                     &gEfiMtftp4ServiceBindingProtocolGuid,
    817                     &Interface
    818                     );
    819     if (EFI_ERROR (Status)) {
    820       continue;
    821     }
    822 
    823     Status = gBS->HandleProtocol (
    824                     Handle,
    825                     &gEfiSimpleNetworkProtocolGuid,
    826                     (VOID **)&SimpleNetworkProtocol
    827                     );
    828     if (EFI_ERROR (Status)) {
    829       continue;
    830     }
    831 
    832     // Allocate BDS Supported Device structure
    833     SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool (sizeof (BDS_SUPPORTED_DEVICE));
    834     if (SupportedDevice == NULL) {
    835       continue;
    836     }
    837 
    838     Mac = &SimpleNetworkProtocol->Mode->CurrentAddress;
    839     UnicodeSPrint (
    840       SupportedDevice->Description,
    841       BOOT_DEVICE_DESCRIPTION_MAX,
    842       L"TFTP on MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
    843       Mac->Addr[0],  Mac->Addr[1],  Mac->Addr[2],  Mac->Addr[3],  Mac->Addr[4],  Mac->Addr[5]
    844       );
    845 
    846     SupportedDevice->DevicePathProtocol = DevicePathProtocol;
    847     SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_TFTP];
    848 
    849     InsertTailList (BdsLoadOptionList, &SupportedDevice->Link);
    850   }
    851 
    852   return EFI_SUCCESS;
    853 }
    854 
    855 EFI_STATUS
    856 BdsLoadOptionTftpCreateDevicePath (
    857   IN CHAR16*                    FileName,
    858   OUT EFI_DEVICE_PATH_PROTOCOL  **DevicePathNodes
    859   )
    860 {
    861   EFI_STATUS            Status;
    862   BOOLEAN               IsDHCP;
    863   EFI_IP_ADDRESS        LocalIp;
    864   EFI_IP_ADDRESS        SubnetMask;
    865   EFI_IP_ADDRESS        GatewayIp;
    866   EFI_IP_ADDRESS        RemoteIp;
    867   IPv4_DEVICE_PATH      *IPv4DevicePathNode;
    868   FILEPATH_DEVICE_PATH  *FilePathDevicePath;
    869   CHAR16                BootFilePath[BOOT_DEVICE_FILEPATH_MAX];
    870   UINTN                 BootFilePathSize;
    871 
    872   Print (L"Get the IP address from DHCP: ");
    873   Status = GetHIInputBoolean (&IsDHCP);
    874   if (EFI_ERROR (Status)) {
    875     return EFI_ABORTED;
    876   }
    877 
    878   if (!IsDHCP) {
    879     Print (L"Local static IP address: ");
    880     Status = GetHIInputIP (&LocalIp);
    881     if (EFI_ERROR (Status)) {
    882       return EFI_ABORTED;
    883     }
    884     Print (L"Get the network mask: ");
    885     Status = GetHIInputIP (&SubnetMask);
    886     if (EFI_ERROR (Status)) {
    887       return EFI_ABORTED;
    888     }
    889     Print (L"Get the gateway IP address: ");
    890     Status = GetHIInputIP (&GatewayIp);
    891     if (EFI_ERROR (Status)) {
    892       return EFI_ABORTED;
    893     }
    894   }
    895 
    896   Print (L"Get the TFTP server IP address: ");
    897   Status = GetHIInputIP (&RemoteIp);
    898   if (EFI_ERROR (Status)) {
    899     return EFI_ABORTED;
    900   }
    901 
    902   Print (L"File path of the %s : ", FileName);
    903   Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);
    904   if (EFI_ERROR (Status)) {
    905     return EFI_ABORTED;
    906   }
    907 
    908   BootFilePathSize = StrSize(BootFilePath);
    909   if (BootFilePathSize == 2) {
    910     return EFI_NOT_FOUND;
    911   }
    912 
    913   // Allocate the memory for the IPv4 + File Path Device Path Nodes
    914   IPv4DevicePathNode = (IPv4_DEVICE_PATH*)AllocatePool(sizeof(IPv4_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH);
    915 
    916   // Create the IPv4 Device Path
    917   IPv4DevicePathNode->Header.Type    = MESSAGING_DEVICE_PATH;
    918   IPv4DevicePathNode->Header.SubType = MSG_IPv4_DP;
    919   SetDevicePathNodeLength (&IPv4DevicePathNode->Header, sizeof(IPv4_DEVICE_PATH));
    920 
    921   if (!IsDHCP) {
    922     CopyMem (&IPv4DevicePathNode->LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));
    923     CopyMem (&IPv4DevicePathNode->SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS));
    924     CopyMem (&IPv4DevicePathNode->GatewayIpAddress, &GatewayIp.v4, sizeof (EFI_IPv4_ADDRESS));
    925   }
    926 
    927   CopyMem (&IPv4DevicePathNode->RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));
    928   IPv4DevicePathNode->LocalPort  = 0;
    929   IPv4DevicePathNode->RemotePort = 0;
    930   IPv4DevicePathNode->Protocol = EFI_IP_PROTO_TCP;
    931   IPv4DevicePathNode->StaticIpAddress = (IsDHCP != TRUE);
    932 
    933   // Create the FilePath Device Path node
    934   FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
    935   FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
    936   FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
    937   SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
    938   CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
    939 
    940   // Set the End Device Path Node
    941   SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize));
    942   *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)IPv4DevicePathNode;
    943 
    944   return Status;
    945 }
    946 
    947 /**
    948   Update the parameters of a TFTP boot option
    949 
    950   The function asks sequentially to update the IPv4 parameters as well as the boot file path,
    951   providing the previously set value if any.
    952 
    953   @param[in]   OldDevicePath  Current complete device path of the Tftp boot option.
    954                               This has to be a valid complete Tftp boot option path.
    955                               By complete, we mean that it is not only the Tftp
    956                               specific end part built by the
    957                               "BdsLoadOptionTftpCreateDevicePath()" function.
    958                               This path is handled as read only.
    959   @param[in]   FileName       Description of the file the path is asked for
    960   @param[out]  NewDevicePath  Pointer to the new complete device path.
    961 
    962   @retval  EFI_SUCCESS            Update completed
    963   @retval  EFI_ABORTED            Update aborted by the user
    964   @retval  EFI_OUT_OF_RESOURCES   Fail to perform the update due to lack of resource
    965 **/
    966 EFI_STATUS
    967 BdsLoadOptionTftpUpdateDevicePath (
    968   IN   EFI_DEVICE_PATH            *OldDevicePath,
    969   IN   CHAR16                     *FileName,
    970   OUT  EFI_DEVICE_PATH_PROTOCOL  **NewDevicePath
    971   )
    972 {
    973   EFI_STATUS             Status;
    974   EFI_DEVICE_PATH       *DevicePath;
    975   EFI_DEVICE_PATH       *DevicePathNode;
    976   UINT8                 *Ipv4NodePtr;
    977   IPv4_DEVICE_PATH       Ipv4Node;
    978   BOOLEAN                IsDHCP;
    979   EFI_IP_ADDRESS         OldIp;
    980   EFI_IP_ADDRESS         OldSubnetMask;
    981   EFI_IP_ADDRESS         OldGatewayIp;
    982   EFI_IP_ADDRESS         LocalIp;
    983   EFI_IP_ADDRESS         SubnetMask;
    984   EFI_IP_ADDRESS         GatewayIp;
    985   EFI_IP_ADDRESS         RemoteIp;
    986   UINT8                 *FileNodePtr;
    987   CHAR16                 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];
    988   UINTN                  PathSize;
    989   UINTN                  BootFilePathSize;
    990   FILEPATH_DEVICE_PATH  *NewFilePathNode;
    991 
    992   Ipv4NodePtr = NULL;
    993 
    994   //
    995   // Make a copy of the complete device path that is made of :
    996   // the device path of the device that support the Simple Network protocol
    997   // followed by an IPv4 node (type IPv4_DEVICE_PATH),
    998   // followed by a file path node (type FILEPATH_DEVICE_PATH) and ended up
    999   // by an end node. The IPv6 case is not handled yet.
   1000   //
   1001 
   1002   DevicePath = DuplicateDevicePath (OldDevicePath);
   1003   if (DevicePath == NULL) {
   1004     Status = EFI_OUT_OF_RESOURCES;
   1005     goto ErrorExit;
   1006   }
   1007 
   1008   //
   1009   // Because of the check done by "BdsLoadOptionTftpIsSupported()" prior to the
   1010   // call to this function, we know that the device path ends with an IPv4 node
   1011   // followed by a file path node and finally an end node. To get the address of
   1012   // the last IPv4 node, we loop over the whole device path, noting down the
   1013   // address of each encountered IPv4 node.
   1014   //
   1015 
   1016   for (DevicePathNode = DevicePath;
   1017        !IsDevicePathEnd (DevicePathNode);
   1018        DevicePathNode = NextDevicePathNode (DevicePathNode))
   1019   {
   1020     if (IS_DEVICE_PATH_NODE (DevicePathNode, MESSAGING_DEVICE_PATH, MSG_IPv4_DP)) {
   1021       Ipv4NodePtr = (UINT8*)DevicePathNode;
   1022     }
   1023   }
   1024 
   1025   // Copy for alignment of the IPv4 node data
   1026   CopyMem (&Ipv4Node, Ipv4NodePtr, sizeof (IPv4_DEVICE_PATH));
   1027 
   1028   Print (L"Get the IP address from DHCP: ");
   1029   Status = GetHIInputBoolean (&IsDHCP);
   1030   if (EFI_ERROR (Status)) {
   1031     goto ErrorExit;
   1032   }
   1033 
   1034   if (!IsDHCP) {
   1035     Print (L"Local static IP address: ");
   1036     if (Ipv4Node.StaticIpAddress) {
   1037       CopyMem (&OldIp.v4, &Ipv4Node.LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
   1038       Status = EditHIInputIP (&OldIp, &LocalIp);
   1039     } else {
   1040       Status = GetHIInputIP (&LocalIp);
   1041     }
   1042     if (EFI_ERROR (Status)) {
   1043       goto ErrorExit;
   1044     }
   1045 
   1046     Print (L"Get the network mask: ");
   1047     if (Ipv4Node.StaticIpAddress) {
   1048       CopyMem (&OldSubnetMask.v4, &Ipv4Node.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
   1049       Status = EditHIInputIP (&OldSubnetMask, &SubnetMask);
   1050     } else {
   1051       Status = GetHIInputIP (&SubnetMask);
   1052     }
   1053     if (EFI_ERROR (Status)) {
   1054       goto ErrorExit;
   1055     }
   1056 
   1057     Print (L"Get the gateway IP address: ");
   1058     if (Ipv4Node.StaticIpAddress) {
   1059       CopyMem (&OldGatewayIp.v4, &Ipv4Node.GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
   1060       Status = EditHIInputIP (&OldGatewayIp, &GatewayIp);
   1061     } else {
   1062       Status = GetHIInputIP (&GatewayIp);
   1063     }
   1064     if (EFI_ERROR (Status)) {
   1065       goto ErrorExit;
   1066     }
   1067   }
   1068 
   1069   Print (L"TFTP server IP address: ");
   1070   // Copy remote IPv4 address into IPv4 or IPv6 union
   1071   CopyMem (&OldIp.v4, &Ipv4Node.RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));
   1072 
   1073   Status = EditHIInputIP (&OldIp, &RemoteIp);
   1074   if (EFI_ERROR (Status)) {
   1075     goto ErrorExit;
   1076   }
   1077 
   1078   // Get the path of the boot file and its size in number of bytes
   1079   FileNodePtr = Ipv4NodePtr + sizeof (IPv4_DEVICE_PATH);
   1080   BootFilePathSize = DevicePathNodeLength (FileNodePtr) - SIZE_OF_FILEPATH_DEVICE_PATH;
   1081 
   1082   //
   1083   // Ask for update of the boot file path
   1084   //
   1085   do {
   1086     // Copy for 2-byte alignment of the Unicode string
   1087     CopyMem (
   1088       BootFilePath, FileNodePtr + SIZE_OF_FILEPATH_DEVICE_PATH,
   1089       MIN (BootFilePathSize, BOOT_DEVICE_FILEPATH_MAX)
   1090       );
   1091     BootFilePath[BOOT_DEVICE_FILEPATH_MAX - 1] = L'\0';
   1092 
   1093     Print (L"File path of the %s: ", FileName);
   1094     Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);
   1095     if (EFI_ERROR (Status)) {
   1096       goto ErrorExit;
   1097     }
   1098     PathSize = StrSize (BootFilePath);
   1099     if (PathSize > 2) {
   1100       break;
   1101     }
   1102     // Empty string, give the user another try
   1103     Print (L"Empty string - Invalid path\n");
   1104   } while (PathSize <= 2) ;
   1105 
   1106   //
   1107   // Update the IPv4 node. IPv6 case not handled yet.
   1108   //
   1109   if (IsDHCP) {
   1110     Ipv4Node.StaticIpAddress = FALSE;
   1111     ZeroMem (&Ipv4Node.LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));
   1112     ZeroMem (&Ipv4Node.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
   1113     ZeroMem (&Ipv4Node.GatewayIpAddress, sizeof (EFI_IPv4_ADDRESS));
   1114   } else {
   1115     Ipv4Node.StaticIpAddress = TRUE;
   1116     CopyMem (&Ipv4Node.LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));
   1117     CopyMem (&Ipv4Node.SubnetMask, &SubnetMask.v4, sizeof (EFI_IPv4_ADDRESS));
   1118     CopyMem (&Ipv4Node.GatewayIpAddress, &GatewayIp.v4, sizeof (EFI_IPv4_ADDRESS));
   1119   }
   1120 
   1121   CopyMem (&Ipv4Node.RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));
   1122   CopyMem (Ipv4NodePtr, &Ipv4Node, sizeof (IPv4_DEVICE_PATH));
   1123 
   1124   //
   1125   // Create the new file path node
   1126   //
   1127   NewFilePathNode = (FILEPATH_DEVICE_PATH*)AllocatePool (
   1128                                              SIZE_OF_FILEPATH_DEVICE_PATH +
   1129                                              PathSize
   1130                                              );
   1131   NewFilePathNode->Header.Type    = MEDIA_DEVICE_PATH;
   1132   NewFilePathNode->Header.SubType = MEDIA_FILEPATH_DP;
   1133   SetDevicePathNodeLength (
   1134     NewFilePathNode,
   1135     SIZE_OF_FILEPATH_DEVICE_PATH + PathSize
   1136     );
   1137   CopyMem (NewFilePathNode->PathName, BootFilePath, PathSize);
   1138 
   1139   //
   1140   // Generate the new Device Path by replacing the file path node at address
   1141   // "FileNodePtr" by the new one "NewFilePathNode" and return its address.
   1142   //
   1143   SetDevicePathEndNode (FileNodePtr);
   1144   *NewDevicePath = AppendDevicePathNode (
   1145                      DevicePath,
   1146                      (CONST EFI_DEVICE_PATH_PROTOCOL*)NewFilePathNode
   1147                      );
   1148 
   1149 ErrorExit:
   1150   if (DevicePath != NULL) {
   1151     FreePool (DevicePath) ;
   1152   }
   1153 
   1154   return Status;
   1155 }
   1156 
   1157 BOOLEAN
   1158 BdsLoadOptionTftpIsSupported (
   1159   IN  EFI_DEVICE_PATH           *DevicePath
   1160   )
   1161 {
   1162   EFI_STATUS  Status;
   1163   EFI_HANDLE Handle;
   1164   EFI_DEVICE_PATH  *RemainingDevicePath;
   1165   EFI_DEVICE_PATH  *NextDevicePath;
   1166   EFI_PXE_BASE_CODE_PROTOCOL  *PxeBcProtocol;
   1167 
   1168   Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
   1169   if (EFI_ERROR(Status)) {
   1170     return FALSE;
   1171   }
   1172 
   1173   // Validate the Remaining Device Path
   1174   if (IsDevicePathEnd(RemainingDevicePath)) {
   1175     return FALSE;
   1176   }
   1177   if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&
   1178       !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {
   1179     return FALSE;
   1180   }
   1181   NextDevicePath = NextDevicePathNode (RemainingDevicePath);
   1182   if (IsDevicePathEnd(NextDevicePath)) {
   1183     return FALSE;
   1184   }
   1185   if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {
   1186     return FALSE;
   1187   }
   1188 
   1189   Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
   1190   if (EFI_ERROR (Status)) {
   1191     return FALSE;
   1192   } else {
   1193     return TRUE;
   1194   }
   1195 }
   1196