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