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