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