]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - ArmPlatformPkg/Bds/BootOptionSupport.c
ARM Packages: Removed trailing spaces
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootOptionSupport.c
... / ...
CommitLineData
1/** @file\r
2*\r
3* Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
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
36 IN CHAR16* FileName,\r
37 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
38 );\r
39\r
40EFI_STATUS\r
41BdsLoadOptionFileSystemUpdateDevicePath (\r
42 IN EFI_DEVICE_PATH *OldDevicePath,\r
43 IN CHAR16* FileName,\r
44 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
45 );\r
46\r
47BOOLEAN\r
48BdsLoadOptionFileSystemIsSupported (\r
49 IN EFI_DEVICE_PATH *DevicePath\r
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
59 IN CHAR16* FileName,\r
60 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
61 );\r
62\r
63EFI_STATUS\r
64BdsLoadOptionMemMapUpdateDevicePath (\r
65 IN EFI_DEVICE_PATH *OldDevicePath,\r
66 IN CHAR16* FileName,\r
67 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
68 );\r
69\r
70BOOLEAN\r
71BdsLoadOptionMemMapIsSupported (\r
72 IN EFI_DEVICE_PATH *DevicePath\r
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
82 IN CHAR16* FileName,\r
83 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
84 );\r
85\r
86EFI_STATUS\r
87BdsLoadOptionPxeUpdateDevicePath (\r
88 IN EFI_DEVICE_PATH *OldDevicePath,\r
89 IN CHAR16* FileName,\r
90 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
91 );\r
92\r
93BOOLEAN\r
94BdsLoadOptionPxeIsSupported (\r
95 IN EFI_DEVICE_PATH *DevicePath\r
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
105 IN CHAR16* FileName,\r
106 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
107 );\r
108\r
109EFI_STATUS\r
110BdsLoadOptionTftpUpdateDevicePath (\r
111 IN EFI_DEVICE_PATH *OldDevicePath,\r
112 IN CHAR16* FileName,\r
113 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
114 );\r
115\r
116BOOLEAN\r
117BdsLoadOptionTftpIsSupported (\r
118 IN EFI_DEVICE_PATH *DevicePath\r
119 );\r
120\r
121BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList[] = {\r
122 {\r
123 BDS_DEVICE_FILESYSTEM,\r
124 BdsLoadOptionFileSystemList,\r
125 BdsLoadOptionFileSystemIsSupported,\r
126 BdsLoadOptionFileSystemCreateDevicePath,\r
127 BdsLoadOptionFileSystemUpdateDevicePath,\r
128 TRUE\r
129 },\r
130 {\r
131 BDS_DEVICE_MEMMAP,\r
132 BdsLoadOptionMemMapList,\r
133 BdsLoadOptionMemMapIsSupported,\r
134 BdsLoadOptionMemMapCreateDevicePath,\r
135 BdsLoadOptionMemMapUpdateDevicePath,\r
136 TRUE\r
137 },\r
138 {\r
139 BDS_DEVICE_PXE,\r
140 BdsLoadOptionPxeList,\r
141 BdsLoadOptionPxeIsSupported,\r
142 BdsLoadOptionPxeCreateDevicePath,\r
143 BdsLoadOptionPxeUpdateDevicePath,\r
144 FALSE\r
145 },\r
146 {\r
147 BDS_DEVICE_TFTP,\r
148 BdsLoadOptionTftpList,\r
149 BdsLoadOptionTftpIsSupported,\r
150 BdsLoadOptionTftpCreateDevicePath,\r
151 BdsLoadOptionTftpUpdateDevicePath,\r
152 TRUE\r
153 }\r
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
167 BdsLoadOptionSupportList[Index].ListDevices (SupportedDeviceList);\r
168 }\r
169\r
170 return EFI_SUCCESS;\r
171}\r
172\r
173EFI_STATUS\r
174BootDeviceListSupportedFree (\r
175 IN LIST_ENTRY *SupportedDeviceList,\r
176 IN BDS_SUPPORTED_DEVICE *Except\r
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
186 if (SupportedDevice != Except) {\r
187 FreePool (SupportedDevice);\r
188 }\r
189 }\r
190\r
191 return EFI_SUCCESS;\r
192}\r
193\r
194EFI_STATUS\r
195BootDeviceGetDeviceSupport (\r
196 IN EFI_DEVICE_PATH *DevicePath,\r
197 OUT BDS_LOAD_OPTION_SUPPORT **DeviceSupport\r
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
204 if (BdsLoadOptionSupportList[Index].IsSupported (DevicePath)) {\r
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
213EFI_STATUS\r
214BootDeviceGetType (\r
215 IN EFI_DEVICE_PATH* DevicePath,\r
216 OUT ARM_BDS_LOADER_TYPE *BootType,\r
217 OUT UINT32 *Attributes\r
218 )\r
219{\r
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
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
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
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
350 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool (sizeof(BDS_SUPPORTED_DEVICE));\r
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
382 IN CHAR16* FileName,\r
383 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
384 )\r
385{\r
386 EFI_STATUS Status;\r
387 FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
388 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
389 UINTN BootFilePathSize;\r
390\r
391 Print(L"File path of the %s: ", FileName);\r
392 Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);\r
393 if (EFI_ERROR(Status)) {\r
394 return EFI_ABORTED;\r
395 }\r
396\r
397 BootFilePathSize = StrSize (BootFilePath);\r
398 if (BootFilePathSize == 2) {\r
399 *DevicePathNodes = NULL;\r
400 return EFI_NOT_FOUND;\r
401 }\r
402\r
403 // Create the FilePath Device Path node\r
404 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH);\r
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
409 SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize));\r
410 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)FilePathDevicePath;\r
411\r
412 return Status;\r
413}\r
414\r
415EFI_STATUS\r
416BdsLoadOptionFileSystemUpdateDevicePath (\r
417 IN EFI_DEVICE_PATH *OldDevicePath,\r
418 IN CHAR16* FileName,\r
419 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
420 )\r
421{\r
422 EFI_STATUS Status;\r
423 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
424 UINTN BootFilePathSize;\r
425 FILEPATH_DEVICE_PATH* EndingDevicePath;\r
426 FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
427 EFI_DEVICE_PATH* DevicePath;\r
428\r
429 DevicePath = DuplicateDevicePath (OldDevicePath);\r
430\r
431 EndingDevicePath = (FILEPATH_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);\r
432\r
433 Print(L"File path of the %s: ", FileName);\r
434 StrnCpy (BootFilePath, EndingDevicePath->PathName, BOOT_DEVICE_FILEPATH_MAX);\r
435 Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);\r
436 if (EFI_ERROR(Status)) {\r
437 return Status;\r
438 }\r
439\r
440 BootFilePathSize = StrSize(BootFilePath);\r
441 if (BootFilePathSize == 2) {\r
442 *NewDevicePath = NULL;\r
443 return EFI_NOT_FOUND;\r
444 }\r
445\r
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
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
458 return EFI_SUCCESS;\r
459}\r
460\r
461/**\r
462 Check if a boot option path is a file system boot option path or not.\r
463\r
464 The device specified by the beginning of the path has to support the Simple File\r
465 System protocol. Furthermore, the remaining part of the path has to be composed of\r
466 a single node of type MEDIA_DEVICE_PATH and sub-type MEDIA_FILEPATH_DP.\r
467\r
468 @param[in] DevicePath Complete device path of a boot option.\r
469\r
470 @retval FALSE The boot option path has not been identified as that of a\r
471 file system boot option.\r
472 @retval TRUE The boot option path is a file system boot option.\r
473**/\r
474BOOLEAN\r
475BdsLoadOptionFileSystemIsSupported (\r
476 IN EFI_DEVICE_PATH *DevicePath\r
477 )\r
478{\r
479 EFI_STATUS Status;\r
480 EFI_HANDLE Handle;\r
481 EFI_DEVICE_PATH *RemainingDevicePath;\r
482 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileProtocol;\r
483\r
484 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
485 if (EFI_ERROR (Status)) {\r
486 return FALSE;\r
487 }\r
488\r
489 Status = gBS->HandleProtocol (\r
490 Handle,\r
491 &gEfiSimpleFileSystemProtocolGuid,\r
492 (VOID **)(&FileProtocol)\r
493 );\r
494 if (EFI_ERROR (Status)) {\r
495 return FALSE;\r
496 }\r
497\r
498 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, MEDIA_DEVICE_PATH, MEDIA_FILEPATH_DP))\r
499 return FALSE;\r
500\r
501 return TRUE;\r
502}\r
503\r
504STATIC\r
505BOOLEAN\r
506IsParentDevicePath (\r
507 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
508 IN EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath\r
509 )\r
510{\r
511 UINTN ParentSize;\r
512 UINTN ChildSize;\r
513\r
514 ParentSize = GetDevicePathSize (ParentDevicePath);\r
515 ChildSize = GetDevicePathSize (ChildDevicePath);\r
516\r
517 if (ParentSize > ChildSize) {\r
518 return FALSE;\r
519 }\r
520\r
521 if (CompareMem (ParentDevicePath, ChildDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0) {\r
522 return FALSE;\r
523 }\r
524\r
525 return TRUE;\r
526}\r
527\r
528EFI_STATUS\r
529BdsLoadOptionMemMapList (\r
530 IN OUT LIST_ENTRY* BdsLoadOptionList\r
531 )\r
532{\r
533 EFI_STATUS Status;\r
534 UINTN HandleCount;\r
535 EFI_HANDLE *HandleBuffer;\r
536 UINTN DevicePathHandleCount;\r
537 EFI_HANDLE *DevicePathHandleBuffer;\r
538 BOOLEAN IsParent;\r
539 UINTN Index;\r
540 UINTN Index2;\r
541 BDS_SUPPORTED_DEVICE *SupportedDevice;\r
542 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;\r
543 EFI_DEVICE_PATH* DevicePath;\r
544\r
545 // List all the BlockIo Protocols\r
546 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
547 if (EFI_ERROR (Status)) {\r
548 return Status;\r
549 }\r
550\r
551 for (Index = 0; Index < HandleCount; Index++) {\r
552 // We only select the handle WITH a Device Path AND not part of Media (to avoid duplication with HardDisk, CDROM, etc)\r
553 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
554 if (!EFI_ERROR(Status)) {\r
555 // BlockIo is not part of Media Device Path\r
556 DevicePath = DevicePathProtocol;\r
557 while (!IsDevicePathEndType (DevicePath) && (DevicePathType (DevicePath) != MEDIA_DEVICE_PATH)) {\r
558 DevicePath = NextDevicePathNode (DevicePath);\r
559 }\r
560 if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) {\r
561 continue;\r
562 }\r
563\r
564 // Open all the handle supporting the DevicePath protocol and verify this handle has not got any child\r
565 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &DevicePathHandleCount, &DevicePathHandleBuffer);\r
566 ASSERT_EFI_ERROR (Status);\r
567 IsParent = FALSE;\r
568 for (Index2 = 0; (Index2 < DevicePathHandleCount) && !IsParent; Index2++) {\r
569 if (HandleBuffer[Index] != DevicePathHandleBuffer[Index2]) {\r
570 gBS->HandleProtocol (DevicePathHandleBuffer[Index2], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);\r
571 if (IsParentDevicePath (DevicePathProtocol, DevicePath)) {\r
572 IsParent = TRUE;\r
573 }\r
574 }\r
575 }\r
576 if (IsParent) {\r
577 continue;\r
578 }\r
579\r
580 // Allocate BDS Supported Device structure\r
581 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));\r
582\r
583 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], SupportedDevice->Description);\r
584 ASSERT_EFI_ERROR (Status);\r
585\r
586 SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
587 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_MEMMAP];\r
588\r
589 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
590 }\r
591 }\r
592\r
593 return EFI_SUCCESS;\r
594}\r
595\r
596EFI_STATUS\r
597BdsLoadOptionMemMapCreateDevicePath (\r
598 IN CHAR16* FileName,\r
599 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
600 )\r
601{\r
602 EFI_STATUS Status;\r
603 MEMMAP_DEVICE_PATH *MemMapDevicePath;\r
604 CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX];\r
605 CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX];\r
606\r
607 Print(L"Starting Address of the %s: ", FileName);\r
608 Status = GetHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX);\r
609 if (EFI_ERROR(Status)) {\r
610 return EFI_ABORTED;\r
611 }\r
612\r
613 Print(L"Ending Address of the %s: ", FileName);\r
614 Status = GetHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX);\r
615 if (EFI_ERROR(Status)) {\r
616 return EFI_ABORTED;\r
617 }\r
618\r
619 // Create the MemMap Device Path Node\r
620 MemMapDevicePath = (MEMMAP_DEVICE_PATH*)AllocatePool (sizeof(MEMMAP_DEVICE_PATH) + END_DEVICE_PATH_LENGTH);\r
621 MemMapDevicePath->Header.Type = HARDWARE_DEVICE_PATH;\r
622 MemMapDevicePath->Header.SubType = HW_MEMMAP_DP;\r
623 SetDevicePathNodeLength (MemMapDevicePath, sizeof(MEMMAP_DEVICE_PATH));\r
624 MemMapDevicePath->MemoryType = EfiBootServicesData;\r
625 MemMapDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress);\r
626 MemMapDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress);\r
627\r
628 // Set a Device Path End Node after the Memory Map Device Path Node\r
629 SetDevicePathEndNode (MemMapDevicePath + 1);\r
630 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)MemMapDevicePath;\r
631\r
632 return Status;\r
633}\r
634\r
635EFI_STATUS\r
636BdsLoadOptionMemMapUpdateDevicePath (\r
637 IN EFI_DEVICE_PATH *OldDevicePath,\r
638 IN CHAR16* FileName,\r
639 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
640 )\r
641{\r
642 EFI_STATUS Status;\r
643 CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX];\r
644 CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX];\r
645 MEMMAP_DEVICE_PATH* EndingDevicePath;\r
646 EFI_DEVICE_PATH* DevicePath;\r
647\r
648 DevicePath = DuplicateDevicePath (OldDevicePath);\r
649 EndingDevicePath = (MEMMAP_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);\r
650\r
651 Print(L"Starting Address of the %s: ", FileName);\r
652 UnicodeSPrint (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->StartingAddress);\r
653 Status = EditHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX);\r
654 if (EFI_ERROR(Status)) {\r
655 return EFI_ABORTED;\r
656 }\r
657\r
658 Print(L"Ending Address of the %s: ", FileName);\r
659 UnicodeSPrint (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->EndingAddress);\r
660 Status = EditHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX);\r
661 if (EFI_ERROR(Status)) {\r
662 return EFI_ABORTED;\r
663 }\r
664\r
665 EndingDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress);\r
666 EndingDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress);\r
667\r
668 if (EFI_ERROR(Status)) {\r
669 FreePool(DevicePath);\r
670 } else {\r
671 *NewDevicePath = DevicePath;\r
672 }\r
673\r
674 return Status;\r
675}\r
676\r
677/**\r
678 Check if a boot option path is a memory map boot option path or not.\r
679\r
680 The device specified by the beginning of the path has to support the BlockIo\r
681 protocol. Furthermore, the remaining part of the path has to be composed of\r
682 a single node of type HARDWARE_DEVICE_PATH and sub-type HW_MEMMAP_DP.\r
683\r
684 @param[in] DevicePath Complete device path of a boot option.\r
685\r
686 @retval FALSE The boot option path has not been identified as that of a\r
687 memory map boot option.\r
688 @retval TRUE The boot option path is a a memory map boot option.\r
689**/\r
690BOOLEAN\r
691BdsLoadOptionMemMapIsSupported (\r
692 IN EFI_DEVICE_PATH *DevicePath\r
693 )\r
694{\r
695 EFI_STATUS Status;\r
696 EFI_HANDLE Handle;\r
697 EFI_DEVICE_PATH *RemainingDevicePath;\r
698 EFI_BLOCK_IO_PROTOCOL *BlockIoProtocol;\r
699\r
700 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
701 if (EFI_ERROR (Status)) {\r
702 return FALSE;\r
703 }\r
704\r
705 Status = gBS->HandleProtocol (\r
706 Handle,\r
707 &gEfiBlockIoProtocolGuid,\r
708 (VOID **)(&BlockIoProtocol)\r
709 );\r
710 if (EFI_ERROR (Status)) {\r
711 return FALSE;\r
712 }\r
713\r
714 if (!IS_DEVICE_PATH_NODE (RemainingDevicePath, HARDWARE_DEVICE_PATH, HW_MEMMAP_DP))\r
715 return FALSE;\r
716\r
717 return TRUE;\r
718}\r
719\r
720EFI_STATUS\r
721BdsLoadOptionPxeList (\r
722 IN OUT LIST_ENTRY* BdsLoadOptionList\r
723 )\r
724{\r
725 EFI_STATUS Status;\r
726 UINTN HandleCount;\r
727 EFI_HANDLE *HandleBuffer;\r
728 UINTN Index;\r
729 BDS_SUPPORTED_DEVICE *SupportedDevice;\r
730 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;\r
731 EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;\r
732 CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
733 EFI_MAC_ADDRESS *Mac;\r
734\r
735 // List all the PXE Protocols\r
736 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
737 if (EFI_ERROR (Status)) {\r
738 return Status;\r
739 }\r
740\r
741 for (Index = 0; Index < HandleCount; Index++) {\r
742 // We only select the handle WITH a Device Path AND the PXE Protocol\r
743 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
744 if (!EFI_ERROR(Status)) {\r
745 // Allocate BDS Supported Device structure\r
746 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));\r
747\r
748 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);\r
749 if (!EFI_ERROR(Status)) {\r
750 Mac = &SimpleNet->Mode->CurrentAddress;\r
751 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
752 } else {\r
753 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);\r
754 ASSERT_EFI_ERROR (Status);\r
755 }\r
756 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"PXE on %s",DeviceDescription);\r
757\r
758 SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
759 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_PXE];\r
760\r
761 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
762 }\r
763 }\r
764\r
765 return EFI_SUCCESS;\r
766}\r
767\r
768EFI_STATUS\r
769BdsLoadOptionPxeCreateDevicePath (\r
770 IN CHAR16* FileName,\r
771 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
772 )\r
773{\r
774 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);\r
775 SetDevicePathEndNode (*DevicePathNodes);\r
776\r
777 return EFI_SUCCESS;\r
778}\r
779\r
780/**\r
781 Update the parameters of a Pxe boot option\r
782\r
783 @param[in] OldDevicePath Current complete device path of the Pxe boot option.\r
784 This has to be a valid complete Pxe boot option path.\r
785 @param[in] FileName Description of the file the path is asked for\r
786 @param[out] NewDevicePath Pointer to the new complete device path.\r
787\r
788 @retval EFI_SUCCESS Update completed\r
789 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource\r
790**/\r
791EFI_STATUS\r
792BdsLoadOptionPxeUpdateDevicePath (\r
793 IN EFI_DEVICE_PATH *OldDevicePath,\r
794 IN CHAR16* FileName,\r
795 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
796 )\r
797{\r
798 //\r
799 // Make a copy of the complete device path that is made of :\r
800 // the device path of the device supporting the Pxe base code protocol\r
801 // followed by an end node.\r
802 //\r
803 *NewDevicePath = DuplicateDevicePath (OldDevicePath);\r
804 if (*NewDevicePath == NULL) {\r
805 return EFI_OUT_OF_RESOURCES;\r
806 } else {\r
807 return EFI_SUCCESS;\r
808 }\r
809}\r
810\r
811BOOLEAN\r
812BdsLoadOptionPxeIsSupported (\r
813 IN EFI_DEVICE_PATH *DevicePath\r
814 )\r
815{\r
816 EFI_STATUS Status;\r
817 EFI_HANDLE Handle;\r
818 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;\r
819 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;\r
820\r
821 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
822 if (EFI_ERROR(Status)) {\r
823 return FALSE;\r
824 }\r
825\r
826 if (!IsDevicePathEnd(RemainingDevicePath)) {\r
827 return FALSE;\r
828 }\r
829\r
830 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
831 if (EFI_ERROR (Status)) {\r
832 return FALSE;\r
833 } else {\r
834 return TRUE;\r
835 }\r
836}\r
837\r
838EFI_STATUS\r
839BdsLoadOptionTftpList (\r
840 IN OUT LIST_ENTRY* BdsLoadOptionList\r
841 )\r
842{\r
843 EFI_STATUS Status;\r
844 UINTN HandleCount;\r
845 EFI_HANDLE *HandleBuffer;\r
846 UINTN Index;\r
847 BDS_SUPPORTED_DEVICE *SupportedDevice;\r
848 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;\r
849 EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;\r
850 CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
851 EFI_MAC_ADDRESS *Mac;\r
852\r
853 // List all the PXE Protocols\r
854 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);\r
855 if (EFI_ERROR (Status)) {\r
856 return Status;\r
857 }\r
858\r
859 for (Index = 0; Index < HandleCount; Index++) {\r
860 // 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
861 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);\r
862 if (!EFI_ERROR(Status)) {\r
863 // Allocate BDS Supported Device structure\r
864 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));\r
865\r
866 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);\r
867 if (!EFI_ERROR(Status)) {\r
868 Mac = &SimpleNet->Mode->CurrentAddress;\r
869 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
870 } else {\r
871 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);\r
872 ASSERT_EFI_ERROR (Status);\r
873 }\r
874 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"TFTP on %s",DeviceDescription);\r
875\r
876 SupportedDevice->DevicePathProtocol = DevicePathProtocol;\r
877 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_TFTP];\r
878\r
879 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);\r
880 }\r
881 }\r
882\r
883 return EFI_SUCCESS;\r
884}\r
885\r
886EFI_STATUS\r
887BdsLoadOptionTftpCreateDevicePath (\r
888 IN CHAR16* FileName,\r
889 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes\r
890 )\r
891{\r
892 EFI_STATUS Status;\r
893 BOOLEAN IsDHCP;\r
894 EFI_IP_ADDRESS LocalIp;\r
895 EFI_IP_ADDRESS RemoteIp;\r
896 IPv4_DEVICE_PATH* IPv4DevicePathNode;\r
897 FILEPATH_DEVICE_PATH* FilePathDevicePath;\r
898 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
899 UINTN BootFilePathSize;\r
900\r
901 Print(L"Get the IP address from DHCP: ");\r
902 Status = GetHIInputBoolean (&IsDHCP);\r
903 if (EFI_ERROR(Status)) {\r
904 return EFI_ABORTED;\r
905 }\r
906\r
907 if (!IsDHCP) {\r
908 Print(L"Get the static IP address: ");\r
909 Status = GetHIInputIP (&LocalIp);\r
910 if (EFI_ERROR(Status)) {\r
911 return EFI_ABORTED;\r
912 }\r
913 }\r
914\r
915 Print(L"Get the TFTP server IP address: ");\r
916 Status = GetHIInputIP (&RemoteIp);\r
917 if (EFI_ERROR(Status)) {\r
918 return EFI_ABORTED;\r
919 }\r
920\r
921 Print(L"File path of the %s : ", FileName);\r
922 Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);\r
923 if (EFI_ERROR(Status)) {\r
924 return EFI_ABORTED;\r
925 }\r
926\r
927 BootFilePathSize = StrSize(BootFilePath);\r
928 if (BootFilePathSize == 2) {\r
929 return EFI_NOT_FOUND;\r
930 }\r
931\r
932 // Allocate the memory for the IPv4 + File Path Device Path Nodes\r
933 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)AllocatePool(sizeof(IPv4_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH);\r
934\r
935 // Create the IPv4 Device Path\r
936 IPv4DevicePathNode->Header.Type = MESSAGING_DEVICE_PATH;\r
937 IPv4DevicePathNode->Header.SubType = MSG_IPv4_DP;\r
938 SetDevicePathNodeLength (&IPv4DevicePathNode->Header, sizeof(IPv4_DEVICE_PATH));\r
939 CopyMem (&IPv4DevicePathNode->LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
940 CopyMem (&IPv4DevicePathNode->RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
941 IPv4DevicePathNode->LocalPort = 0;\r
942 IPv4DevicePathNode->RemotePort = 0;\r
943 IPv4DevicePathNode->Protocol = EFI_IP_PROTO_TCP;\r
944 IPv4DevicePathNode->StaticIpAddress = (IsDHCP != TRUE);\r
945\r
946 // Create the FilePath Device Path node\r
947 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);\r
948 FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;\r
949 FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;\r
950 SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);\r
951 CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);\r
952\r
953 // Set the End Device Path Node\r
954 SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize));\r
955 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)IPv4DevicePathNode;\r
956\r
957 return Status;\r
958}\r
959\r
960/**\r
961 Update the parameters of a TFTP boot option\r
962\r
963 The function asks sequentially to update the IPv4 parameters as well as the boot file path,\r
964 providing the previously set value if any.\r
965\r
966 @param[in] OldDevicePath Current complete device path of the Tftp boot option.\r
967 This has to be a valid complete Tftp boot option path.\r
968 By complete, we mean that it is not only the Tftp\r
969 specific end part built by the\r
970 "BdsLoadOptionTftpCreateDevicePath()" function.\r
971 This path is handled as read only.\r
972 @param[in] FileName Description of the file the path is asked for\r
973 @param[out] NewDevicePath Pointer to the new complete device path.\r
974\r
975 @retval EFI_SUCCESS Update completed\r
976 @retval EFI_ABORTED Update aborted by the user\r
977 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource\r
978**/\r
979EFI_STATUS\r
980BdsLoadOptionTftpUpdateDevicePath (\r
981 IN EFI_DEVICE_PATH *OldDevicePath,\r
982 IN CHAR16 *FileName,\r
983 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath\r
984 )\r
985{\r
986 EFI_STATUS Status;\r
987 EFI_DEVICE_PATH *DevicePath;\r
988 EFI_DEVICE_PATH *DevicePathNode;\r
989 UINT8 *Ipv4NodePtr;\r
990 IPv4_DEVICE_PATH Ipv4Node;\r
991 BOOLEAN IsDHCP;\r
992 EFI_IP_ADDRESS OldIp;\r
993 EFI_IP_ADDRESS LocalIp;\r
994 EFI_IP_ADDRESS RemoteIp;\r
995 UINT8 *FileNodePtr;\r
996 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];\r
997 UINTN PathSize;\r
998 UINTN BootFilePathSize;\r
999 FILEPATH_DEVICE_PATH *NewFilePathNode;\r
1000\r
1001 Ipv4NodePtr = NULL;\r
1002\r
1003 //\r
1004 // Make a copy of the complete device path that is made of :\r
1005 // the device path of the device that support the Simple Network protocol\r
1006 // followed by an IPv4 node (type IPv4_DEVICE_PATH),\r
1007 // followed by a file path node (type FILEPATH_DEVICE_PATH) and ended up\r
1008 // by an end node. The IPv6 case is not handled yet.\r
1009 //\r
1010\r
1011 DevicePath = DuplicateDevicePath (OldDevicePath);\r
1012 if (DevicePath == NULL) {\r
1013 Status = EFI_OUT_OF_RESOURCES;\r
1014 goto ErrorExit;\r
1015 }\r
1016\r
1017 //\r
1018 // Because of the check done by "BdsLoadOptionTftpIsSupported()" prior to the\r
1019 // call to this function, we know that the device path ends with an IPv4 node\r
1020 // followed by a file path node and finally an end node. To get the address of\r
1021 // the last IPv4 node, we loop over the whole device path, noting down the\r
1022 // address of each encountered IPv4 node.\r
1023 //\r
1024\r
1025 for (DevicePathNode = DevicePath;\r
1026 !IsDevicePathEnd (DevicePathNode);\r
1027 DevicePathNode = NextDevicePathNode (DevicePathNode))\r
1028 {\r
1029 if (IS_DEVICE_PATH_NODE (DevicePathNode, MESSAGING_DEVICE_PATH, MSG_IPv4_DP)) {\r
1030 Ipv4NodePtr = (UINT8*)DevicePathNode;\r
1031 }\r
1032 }\r
1033\r
1034 // Copy for alignment of the IPv4 node data\r
1035 CopyMem (&Ipv4Node, Ipv4NodePtr, sizeof (IPv4_DEVICE_PATH));\r
1036\r
1037 Print (L"Get the IP address from DHCP: ");\r
1038 Status = GetHIInputBoolean (&IsDHCP);\r
1039 if (EFI_ERROR (Status)) {\r
1040 goto ErrorExit;\r
1041 }\r
1042\r
1043 if (!IsDHCP) {\r
1044 Print (L"Local static IP address: ");\r
1045 if (Ipv4Node.StaticIpAddress) {\r
1046 // Copy local IPv4 address into IPv4 or IPv6 union\r
1047 CopyMem (&OldIp.v4, &Ipv4Node.LocalIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
1048\r
1049 Status = EditHIInputIP (&OldIp, &LocalIp);\r
1050 } else {\r
1051 Status = GetHIInputIP (&LocalIp);\r
1052 }\r
1053 if (EFI_ERROR (Status)) {\r
1054 goto ErrorExit;\r
1055 }\r
1056 }\r
1057\r
1058 Print (L"TFTP server IP address: ");\r
1059 // Copy remote IPv4 address into IPv4 or IPv6 union\r
1060 CopyMem (&OldIp.v4, &Ipv4Node.RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS));\r
1061\r
1062 Status = EditHIInputIP (&OldIp, &RemoteIp);\r
1063 if (EFI_ERROR (Status)) {\r
1064 goto ErrorExit;\r
1065 }\r
1066\r
1067 // Get the path of the boot file and its size in number of bytes\r
1068 FileNodePtr = Ipv4NodePtr + sizeof (IPv4_DEVICE_PATH);\r
1069 BootFilePathSize = DevicePathNodeLength (FileNodePtr) - SIZE_OF_FILEPATH_DEVICE_PATH;\r
1070\r
1071 //\r
1072 // Ask for update of the boot file path\r
1073 //\r
1074 do {\r
1075 // Copy for 2-byte alignment of the Unicode string\r
1076 CopyMem (\r
1077 BootFilePath, FileNodePtr + SIZE_OF_FILEPATH_DEVICE_PATH,\r
1078 MIN (BootFilePathSize, BOOT_DEVICE_FILEPATH_MAX)\r
1079 );\r
1080 BootFilePath[BOOT_DEVICE_FILEPATH_MAX - 1] = L'\0';\r
1081\r
1082 Print (L"File path of the %s: ", FileName);\r
1083 Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);\r
1084 if (EFI_ERROR (Status)) {\r
1085 goto ErrorExit;\r
1086 }\r
1087 PathSize = StrSize (BootFilePath);\r
1088 if (PathSize > 2) {\r
1089 break;\r
1090 }\r
1091 // Empty string, give the user another try\r
1092 Print (L"Empty string - Invalid path\n");\r
1093 } while (PathSize <= 2) ;\r
1094\r
1095 //\r
1096 // Update the IPv4 node. IPv6 case not handled yet.\r
1097 //\r
1098 if (IsDHCP == TRUE) {\r
1099 Ipv4Node.StaticIpAddress = FALSE;\r
1100 } else {\r
1101 Ipv4Node.StaticIpAddress = TRUE;\r
1102 }\r
1103 CopyMem (&Ipv4Node.LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
1104 CopyMem (&Ipv4Node.RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));\r
1105 CopyMem (Ipv4NodePtr, &Ipv4Node, sizeof (IPv4_DEVICE_PATH));\r
1106\r
1107 //\r
1108 // Create the new file path node\r
1109 //\r
1110 NewFilePathNode = (FILEPATH_DEVICE_PATH*)AllocatePool (\r
1111 SIZE_OF_FILEPATH_DEVICE_PATH +\r
1112 PathSize\r
1113 );\r
1114 NewFilePathNode->Header.Type = MEDIA_DEVICE_PATH;\r
1115 NewFilePathNode->Header.SubType = MEDIA_FILEPATH_DP;\r
1116 SetDevicePathNodeLength (\r
1117 NewFilePathNode,\r
1118 SIZE_OF_FILEPATH_DEVICE_PATH + PathSize\r
1119 );\r
1120 CopyMem (NewFilePathNode->PathName, BootFilePath, PathSize);\r
1121\r
1122 //\r
1123 // Generate the new Device Path by replacing the file path node at address\r
1124 // "FileNodePtr" by the new one "NewFilePathNode" and return its address.\r
1125 //\r
1126 SetDevicePathEndNode (FileNodePtr);\r
1127 *NewDevicePath = AppendDevicePathNode (\r
1128 DevicePath,\r
1129 (CONST EFI_DEVICE_PATH_PROTOCOL*)NewFilePathNode\r
1130 );\r
1131\r
1132ErrorExit:\r
1133 if (DevicePath != NULL) {\r
1134 FreePool (DevicePath) ;\r
1135 }\r
1136\r
1137 return Status;\r
1138}\r
1139\r
1140BOOLEAN\r
1141BdsLoadOptionTftpIsSupported (\r
1142 IN EFI_DEVICE_PATH *DevicePath\r
1143 )\r
1144{\r
1145 EFI_STATUS Status;\r
1146 EFI_HANDLE Handle;\r
1147 EFI_DEVICE_PATH *RemainingDevicePath;\r
1148 EFI_DEVICE_PATH *NextDevicePath;\r
1149 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;\r
1150\r
1151 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);\r
1152 if (EFI_ERROR(Status)) {\r
1153 return FALSE;\r
1154 }\r
1155\r
1156 // Validate the Remaining Device Path\r
1157 if (IsDevicePathEnd(RemainingDevicePath)) {\r
1158 return FALSE;\r
1159 }\r
1160 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&\r
1161 !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {\r
1162 return FALSE;\r
1163 }\r
1164 NextDevicePath = NextDevicePathNode (RemainingDevicePath);\r
1165 if (IsDevicePathEnd(NextDevicePath)) {\r
1166 return FALSE;\r
1167 }\r
1168 if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {\r
1169 return FALSE;\r
1170 }\r
1171\r
1172 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);\r
1173 if (EFI_ERROR (Status)) {\r
1174 return FALSE;\r
1175 } else {\r
1176 return TRUE;\r
1177 }\r
1178}\r