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
BootDeviceListSupportedInit(IN OUT LIST_ENTRY * SupportedDeviceList)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
BootDeviceListSupportedFree(IN LIST_ENTRY * SupportedDeviceList,IN BDS_SUPPORTED_DEVICE * Except)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
BootDeviceGetDeviceSupport(IN EFI_DEVICE_PATH * DevicePath,OUT BDS_LOAD_OPTION_SUPPORT ** DeviceSupport)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
BdsLoadOptionFileSystemList(IN OUT LIST_ENTRY * BdsLoadOptionList)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
BdsLoadOptionFileSystemCreateDevicePath(IN CHAR16 * FileName,OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePathNodes)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
BdsLoadOptionFileSystemUpdateDevicePath(IN EFI_DEVICE_PATH * OldDevicePath,IN CHAR16 * FileName,OUT EFI_DEVICE_PATH_PROTOCOL ** NewDevicePath)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
BdsLoadOptionFileSystemIsSupported(IN EFI_DEVICE_PATH * DevicePath)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
IsParentDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * ParentDevicePath,IN EFI_DEVICE_PATH_PROTOCOL * ChildDevicePath)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
BdsLoadOptionMemMapList(IN OUT LIST_ENTRY * BdsLoadOptionList)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
BdsLoadOptionMemMapCreateDevicePath(IN CHAR16 * FileName,OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePathNodes)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
BdsLoadOptionMemMapUpdateDevicePath(IN EFI_DEVICE_PATH * OldDevicePath,IN CHAR16 * FileName,OUT EFI_DEVICE_PATH_PROTOCOL ** NewDevicePath)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
BdsLoadOptionMemMapIsSupported(IN EFI_DEVICE_PATH * DevicePath)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
BdsLoadOptionPxeList(IN OUT LIST_ENTRY * BdsLoadOptionList)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
BdsLoadOptionPxeCreateDevicePath(IN CHAR16 * FileName,OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePathNodes)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
BdsLoadOptionPxeUpdateDevicePath(IN EFI_DEVICE_PATH * OldDevicePath,IN CHAR16 * FileName,OUT EFI_DEVICE_PATH_PROTOCOL ** NewDevicePath)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
BdsLoadOptionPxeIsSupported(IN EFI_DEVICE_PATH * DevicePath)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
BdsLoadOptionTftpList(IN OUT LIST_ENTRY * BdsLoadOptionList)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
BdsLoadOptionTftpCreateDevicePath(IN CHAR16 * FileName,OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePathNodes)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
BdsLoadOptionTftpUpdateDevicePath(IN EFI_DEVICE_PATH * OldDevicePath,IN CHAR16 * FileName,OUT EFI_DEVICE_PATH_PROTOCOL ** NewDevicePath)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
BdsLoadOptionTftpIsSupported(IN EFI_DEVICE_PATH * DevicePath)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