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