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