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