]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BootOptionSupport.c
ArmPlatformPkg/Bds: Change the GetHIInput/EditHIInput to always return a valid IP...
[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 BOOLEAN
462 BdsLoadOptionFileSystemIsSupported (
463 IN EFI_DEVICE_PATH *DevicePath
464 )
465 {
466 EFI_DEVICE_PATH* DevicePathNode;
467
468 DevicePathNode = GetLastDevicePathNode (DevicePath);
469
470 return IS_DEVICE_PATH_NODE(DevicePathNode,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP);
471 }
472
473 STATIC
474 BOOLEAN
475 IsParentDevicePath (
476 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
477 IN EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath
478 )
479 {
480 UINTN ParentSize;
481 UINTN ChildSize;
482
483 ParentSize = GetDevicePathSize (ParentDevicePath);
484 ChildSize = GetDevicePathSize (ChildDevicePath);
485
486 if (ParentSize > ChildSize) {
487 return FALSE;
488 }
489
490 if (CompareMem (ParentDevicePath, ChildDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0) {
491 return FALSE;
492 }
493
494 return TRUE;
495 }
496
497 EFI_STATUS
498 BdsLoadOptionMemMapList (
499 IN OUT LIST_ENTRY* BdsLoadOptionList
500 )
501 {
502 EFI_STATUS Status;
503 UINTN HandleCount;
504 EFI_HANDLE *HandleBuffer;
505 UINTN DevicePathHandleCount;
506 EFI_HANDLE *DevicePathHandleBuffer;
507 BOOLEAN IsParent;
508 UINTN Index;
509 UINTN Index2;
510 BDS_SUPPORTED_DEVICE *SupportedDevice;
511 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
512 EFI_DEVICE_PATH* DevicePath;
513
514 // List all the BlockIo Protocols
515 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);
516 if (EFI_ERROR (Status)) {
517 return Status;
518 }
519
520 for (Index = 0; Index < HandleCount; Index++) {
521 // We only select the handle WITH a Device Path AND not part of Media (to avoid duplication with HardDisk, CDROM, etc)
522 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
523 if (!EFI_ERROR(Status)) {
524 // BlockIo is not part of Media Device Path
525 DevicePath = DevicePathProtocol;
526 while (!IsDevicePathEndType (DevicePath) && (DevicePathType (DevicePath) != MEDIA_DEVICE_PATH)) {
527 DevicePath = NextDevicePathNode (DevicePath);
528 }
529 if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) {
530 continue;
531 }
532
533 // Open all the handle supporting the DevicePath protocol and verify this handle has not got any child
534 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &DevicePathHandleCount, &DevicePathHandleBuffer);
535 ASSERT_EFI_ERROR (Status);
536 IsParent = FALSE;
537 for (Index2 = 0; (Index2 < DevicePathHandleCount) && !IsParent; Index2++) {
538 if (HandleBuffer[Index] != DevicePathHandleBuffer[Index2]) {
539 gBS->HandleProtocol (DevicePathHandleBuffer[Index2], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
540 if (IsParentDevicePath (DevicePathProtocol, DevicePath)) {
541 IsParent = TRUE;
542 }
543 }
544 }
545 if (IsParent) {
546 continue;
547 }
548
549 // Allocate BDS Supported Device structure
550 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
551
552 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], SupportedDevice->Description);
553 ASSERT_EFI_ERROR (Status);
554
555 SupportedDevice->DevicePathProtocol = DevicePathProtocol;
556 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_MEMMAP];
557
558 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
559 }
560 }
561
562 return EFI_SUCCESS;
563 }
564
565 EFI_STATUS
566 BdsLoadOptionMemMapCreateDevicePath (
567 IN CHAR16* FileName,
568 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes
569 )
570 {
571 EFI_STATUS Status;
572 MEMMAP_DEVICE_PATH *MemMapDevicePath;
573 CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX];
574 CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX];
575
576 Print(L"Starting Address of the %s: ", FileName);
577 Status = GetHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX);
578 if (EFI_ERROR(Status)) {
579 return EFI_ABORTED;
580 }
581
582 Print(L"Ending Address of the %s: ", FileName);
583 Status = GetHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX);
584 if (EFI_ERROR(Status)) {
585 return EFI_ABORTED;
586 }
587
588 // Create the MemMap Device Path Node
589 MemMapDevicePath = (MEMMAP_DEVICE_PATH*)AllocatePool (sizeof(MEMMAP_DEVICE_PATH) + END_DEVICE_PATH_LENGTH);
590 MemMapDevicePath->Header.Type = HARDWARE_DEVICE_PATH;
591 MemMapDevicePath->Header.SubType = HW_MEMMAP_DP;
592 SetDevicePathNodeLength (MemMapDevicePath, sizeof(MEMMAP_DEVICE_PATH));
593 MemMapDevicePath->MemoryType = EfiBootServicesData;
594 MemMapDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress);
595 MemMapDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress);
596
597 // Set a Device Path End Node after the Memory Map Device Path Node
598 SetDevicePathEndNode (MemMapDevicePath + 1);
599 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)MemMapDevicePath;
600
601 return Status;
602 }
603
604 EFI_STATUS
605 BdsLoadOptionMemMapUpdateDevicePath (
606 IN EFI_DEVICE_PATH *OldDevicePath,
607 IN CHAR16* FileName,
608 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath
609 )
610 {
611 EFI_STATUS Status;
612 CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX];
613 CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX];
614 MEMMAP_DEVICE_PATH* EndingDevicePath;
615 EFI_DEVICE_PATH* DevicePath;
616
617 DevicePath = DuplicateDevicePath (OldDevicePath);
618 EndingDevicePath = (MEMMAP_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);
619
620 Print(L"Starting Address of the %s: ", FileName);
621 UnicodeSPrint (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->StartingAddress);
622 Status = EditHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX);
623 if (EFI_ERROR(Status)) {
624 return EFI_ABORTED;
625 }
626
627 Print(L"Ending Address of the %s: ", FileName);
628 UnicodeSPrint (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->EndingAddress);
629 Status = EditHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX);
630 if (EFI_ERROR(Status)) {
631 return EFI_ABORTED;
632 }
633
634 EndingDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress);
635 EndingDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress);
636
637 if (EFI_ERROR(Status)) {
638 FreePool(DevicePath);
639 } else {
640 *NewDevicePath = DevicePath;
641 }
642
643 return Status;
644 }
645
646 BOOLEAN
647 BdsLoadOptionMemMapIsSupported (
648 IN EFI_DEVICE_PATH *DevicePath
649 )
650 {
651 EFI_DEVICE_PATH* DevicePathNode;
652
653 DevicePathNode = GetLastDevicePathNode (DevicePath);
654
655 return IS_DEVICE_PATH_NODE(DevicePathNode,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);
656 }
657
658 EFI_STATUS
659 BdsLoadOptionPxeList (
660 IN OUT LIST_ENTRY* BdsLoadOptionList
661 )
662 {
663 EFI_STATUS Status;
664 UINTN HandleCount;
665 EFI_HANDLE *HandleBuffer;
666 UINTN Index;
667 BDS_SUPPORTED_DEVICE *SupportedDevice;
668 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
669 EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;
670 CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];
671 EFI_MAC_ADDRESS *Mac;
672
673 // List all the PXE Protocols
674 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);
675 if (EFI_ERROR (Status)) {
676 return Status;
677 }
678
679 for (Index = 0; Index < HandleCount; Index++) {
680 // We only select the handle WITH a Device Path AND the PXE Protocol
681 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
682 if (!EFI_ERROR(Status)) {
683 // Allocate BDS Supported Device structure
684 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
685
686 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);
687 if (!EFI_ERROR(Status)) {
688 Mac = &SimpleNet->Mode->CurrentAddress;
689 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]);
690 } else {
691 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);
692 ASSERT_EFI_ERROR (Status);
693 }
694 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"PXE on %s",DeviceDescription);
695
696 SupportedDevice->DevicePathProtocol = DevicePathProtocol;
697 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_PXE];
698
699 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
700 }
701 }
702
703 return EFI_SUCCESS;
704 }
705
706 EFI_STATUS
707 BdsLoadOptionPxeCreateDevicePath (
708 IN CHAR16* FileName,
709 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes
710 )
711 {
712 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);
713 SetDevicePathEndNode (*DevicePathNodes);
714
715 return EFI_SUCCESS;
716 }
717
718 /**
719 Update the parameters of a Pxe boot option
720
721 @param[in] OldDevicePath Current complete device path of the Pxe boot option.
722 This has to be a valid complete Pxe boot option path.
723 @param[in] FileName Description of the file the path is asked for
724 @param[out] NewDevicePath Pointer to the new complete device path.
725
726 @retval EFI_SUCCESS Update completed
727 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
728 **/
729 EFI_STATUS
730 BdsLoadOptionPxeUpdateDevicePath (
731 IN EFI_DEVICE_PATH *OldDevicePath,
732 IN CHAR16* FileName,
733 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath
734 )
735 {
736 //
737 // Make a copy of the complete device path that is made of :
738 // the device path of the device supporting the Pxe base code protocol
739 // followed by an end node.
740 //
741 *NewDevicePath = DuplicateDevicePath (OldDevicePath);
742 if (*NewDevicePath == NULL) {
743 return EFI_OUT_OF_RESOURCES;
744 } else {
745 return EFI_SUCCESS;
746 }
747 }
748
749 BOOLEAN
750 BdsLoadOptionPxeIsSupported (
751 IN EFI_DEVICE_PATH *DevicePath
752 )
753 {
754 EFI_STATUS Status;
755 EFI_HANDLE Handle;
756 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
757 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
758
759 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
760 if (EFI_ERROR(Status)) {
761 return FALSE;
762 }
763
764 if (!IsDevicePathEnd(RemainingDevicePath)) {
765 return FALSE;
766 }
767
768 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
769 if (EFI_ERROR (Status)) {
770 return FALSE;
771 } else {
772 return TRUE;
773 }
774 }
775
776 EFI_STATUS
777 BdsLoadOptionTftpList (
778 IN OUT LIST_ENTRY* BdsLoadOptionList
779 )
780 {
781 EFI_STATUS Status;
782 UINTN HandleCount;
783 EFI_HANDLE *HandleBuffer;
784 UINTN Index;
785 BDS_SUPPORTED_DEVICE *SupportedDevice;
786 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
787 EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;
788 CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];
789 EFI_MAC_ADDRESS *Mac;
790
791 // List all the PXE Protocols
792 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);
793 if (EFI_ERROR (Status)) {
794 return Status;
795 }
796
797 for (Index = 0; Index < HandleCount; Index++) {
798 // 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)
799 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
800 if (!EFI_ERROR(Status)) {
801 // Allocate BDS Supported Device structure
802 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
803
804 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);
805 if (!EFI_ERROR(Status)) {
806 Mac = &SimpleNet->Mode->CurrentAddress;
807 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]);
808 } else {
809 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);
810 ASSERT_EFI_ERROR (Status);
811 }
812 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"TFTP on %s",DeviceDescription);
813
814 SupportedDevice->DevicePathProtocol = DevicePathProtocol;
815 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_TFTP];
816
817 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
818 }
819 }
820
821 return EFI_SUCCESS;
822 }
823
824 EFI_STATUS
825 BdsLoadOptionTftpCreateDevicePath (
826 IN CHAR16* FileName,
827 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes
828 )
829 {
830 EFI_STATUS Status;
831 BOOLEAN IsDHCP;
832 EFI_IP_ADDRESS LocalIp;
833 EFI_IP_ADDRESS RemoteIp;
834 IPv4_DEVICE_PATH* IPv4DevicePathNode;
835 FILEPATH_DEVICE_PATH* FilePathDevicePath;
836 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];
837 UINTN BootFilePathSize;
838
839 Print(L"Get the IP address from DHCP: ");
840 Status = GetHIInputBoolean (&IsDHCP);
841 if (EFI_ERROR(Status)) {
842 return EFI_ABORTED;
843 }
844
845 if (!IsDHCP) {
846 Print(L"Get the static IP address: ");
847 Status = GetHIInputIP (&LocalIp);
848 if (EFI_ERROR(Status)) {
849 return EFI_ABORTED;
850 }
851 }
852
853 Print(L"Get the TFTP server IP address: ");
854 Status = GetHIInputIP (&RemoteIp);
855 if (EFI_ERROR(Status)) {
856 return EFI_ABORTED;
857 }
858
859 Print(L"File path of the %s : ", FileName);
860 Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);
861 if (EFI_ERROR(Status)) {
862 return EFI_ABORTED;
863 }
864
865 BootFilePathSize = StrSize(BootFilePath);
866 if (BootFilePathSize == 2) {
867 return EFI_NOT_FOUND;
868 }
869
870 // Allocate the memory for the IPv4 + File Path Device Path Nodes
871 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)AllocatePool(sizeof(IPv4_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH);
872
873 // Create the IPv4 Device Path
874 IPv4DevicePathNode->Header.Type = MESSAGING_DEVICE_PATH;
875 IPv4DevicePathNode->Header.SubType = MSG_IPv4_DP;
876 SetDevicePathNodeLength (&IPv4DevicePathNode->Header, sizeof(IPv4_DEVICE_PATH));
877 CopyMem (&IPv4DevicePathNode->LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));
878 CopyMem (&IPv4DevicePathNode->RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));
879 IPv4DevicePathNode->LocalPort = 0;
880 IPv4DevicePathNode->RemotePort = 0;
881 IPv4DevicePathNode->Protocol = EFI_IP_PROTO_TCP;
882 IPv4DevicePathNode->StaticIpAddress = (IsDHCP != TRUE);
883
884 // Create the FilePath Device Path node
885 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
886 FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
887 FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
888 SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
889 CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
890
891 // Set the End Device Path Node
892 SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize));
893 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)IPv4DevicePathNode;
894
895 return Status;
896 }
897
898 EFI_STATUS
899 BdsLoadOptionTftpUpdateDevicePath (
900 IN EFI_DEVICE_PATH *OldDevicePath,
901 IN CHAR16* FileName,
902 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath
903 )
904 {
905 ASSERT (0);
906 return EFI_UNSUPPORTED;
907 }
908
909 BOOLEAN
910 BdsLoadOptionTftpIsSupported (
911 IN EFI_DEVICE_PATH *DevicePath
912 )
913 {
914 EFI_STATUS Status;
915 EFI_HANDLE Handle;
916 EFI_DEVICE_PATH *RemainingDevicePath;
917 EFI_DEVICE_PATH *NextDevicePath;
918 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
919
920 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
921 if (EFI_ERROR(Status)) {
922 return FALSE;
923 }
924
925 // Validate the Remaining Device Path
926 if (IsDevicePathEnd(RemainingDevicePath)) {
927 return FALSE;
928 }
929 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&
930 !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {
931 return FALSE;
932 }
933 NextDevicePath = NextDevicePathNode (RemainingDevicePath);
934 if (IsDevicePathEnd(NextDevicePath)) {
935 return FALSE;
936 }
937 if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {
938 return FALSE;
939 }
940
941 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
942 if (EFI_ERROR (Status)) {
943 return FALSE;
944 } else {
945 return TRUE;
946 }
947 }