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