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