]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BootOptionSupport.c
ArmPlatformPkg/Bds: Added update of Pxe boot option
[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 OUT BOOLEAN *RequestBootType
39 );
40
41 EFI_STATUS
42 BdsLoadOptionFileSystemUpdateDevicePath (
43 IN EFI_DEVICE_PATH *OldDevicePath,
44 IN CHAR16* FileName,
45 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath,
46 OUT BOOLEAN *RequestBootType
47 );
48
49 BOOLEAN
50 BdsLoadOptionFileSystemIsSupported (
51 IN EFI_DEVICE_PATH *DevicePath
52 );
53
54 EFI_STATUS
55 BdsLoadOptionMemMapList (
56 IN OUT LIST_ENTRY* BdsLoadOptionList
57 );
58
59 EFI_STATUS
60 BdsLoadOptionMemMapCreateDevicePath (
61 IN CHAR16* FileName,
62 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes,
63 OUT BOOLEAN *RequestBootType
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 OUT BOOLEAN *RequestBootType
72 );
73
74 BOOLEAN
75 BdsLoadOptionMemMapIsSupported (
76 IN EFI_DEVICE_PATH *DevicePath
77 );
78
79 EFI_STATUS
80 BdsLoadOptionPxeList (
81 IN OUT LIST_ENTRY* BdsLoadOptionList
82 );
83
84 EFI_STATUS
85 BdsLoadOptionPxeCreateDevicePath (
86 IN CHAR16* FileName,
87 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes,
88 OUT BOOLEAN *RequestBootType
89 );
90
91 EFI_STATUS
92 BdsLoadOptionPxeUpdateDevicePath (
93 IN EFI_DEVICE_PATH *OldDevicePath,
94 IN CHAR16* FileName,
95 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath,
96 OUT BOOLEAN *RequestBootType
97 );
98
99 BOOLEAN
100 BdsLoadOptionPxeIsSupported (
101 IN EFI_DEVICE_PATH *DevicePath
102 );
103
104 EFI_STATUS
105 BdsLoadOptionTftpList (
106 IN OUT LIST_ENTRY* BdsLoadOptionList
107 );
108
109 EFI_STATUS
110 BdsLoadOptionTftpCreateDevicePath (
111 IN CHAR16* FileName,
112 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes,
113 OUT BOOLEAN *RequestBootType
114 );
115
116 EFI_STATUS
117 BdsLoadOptionTftpUpdateDevicePath (
118 IN EFI_DEVICE_PATH *OldDevicePath,
119 IN CHAR16* FileName,
120 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath,
121 OUT BOOLEAN *RequestBootType
122 );
123
124 BOOLEAN
125 BdsLoadOptionTftpIsSupported (
126 IN EFI_DEVICE_PATH *DevicePath
127 );
128
129 BDS_LOAD_OPTION_SUPPORT BdsLoadOptionSupportList[] = {
130 {
131 BDS_DEVICE_FILESYSTEM,
132 BdsLoadOptionFileSystemList,
133 BdsLoadOptionFileSystemIsSupported,
134 BdsLoadOptionFileSystemCreateDevicePath,
135 BdsLoadOptionFileSystemUpdateDevicePath
136 },
137 {
138 BDS_DEVICE_MEMMAP,
139 BdsLoadOptionMemMapList,
140 BdsLoadOptionMemMapIsSupported,
141 BdsLoadOptionMemMapCreateDevicePath,
142 BdsLoadOptionMemMapUpdateDevicePath
143 },
144 {
145 BDS_DEVICE_PXE,
146 BdsLoadOptionPxeList,
147 BdsLoadOptionPxeIsSupported,
148 BdsLoadOptionPxeCreateDevicePath,
149 BdsLoadOptionPxeUpdateDevicePath
150 },
151 {
152 BDS_DEVICE_TFTP,
153 BdsLoadOptionTftpList,
154 BdsLoadOptionTftpIsSupported,
155 BdsLoadOptionTftpCreateDevicePath,
156 BdsLoadOptionTftpUpdateDevicePath
157 }
158 };
159
160 EFI_STATUS
161 BootDeviceListSupportedInit (
162 IN OUT LIST_ENTRY *SupportedDeviceList
163 )
164 {
165 UINTN Index;
166
167 // Initialize list of supported devices
168 InitializeListHead (SupportedDeviceList);
169
170 for (Index = 0; Index < BDS_DEVICE_MAX; Index++) {
171 BdsLoadOptionSupportList[Index].ListDevices (SupportedDeviceList);
172 }
173
174 return EFI_SUCCESS;
175 }
176
177 EFI_STATUS
178 BootDeviceListSupportedFree (
179 IN LIST_ENTRY *SupportedDeviceList,
180 IN BDS_SUPPORTED_DEVICE *Except
181 )
182 {
183 LIST_ENTRY *Entry;
184 BDS_SUPPORTED_DEVICE* SupportedDevice;
185
186 Entry = GetFirstNode (SupportedDeviceList);
187 while (Entry != SupportedDeviceList) {
188 SupportedDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
189 Entry = RemoveEntryList (Entry);
190 if (SupportedDevice != Except) {
191 FreePool (SupportedDevice);
192 }
193 }
194
195 return EFI_SUCCESS;
196 }
197
198 EFI_STATUS
199 BootDeviceGetDeviceSupport (
200 IN EFI_DEVICE_PATH *DevicePath,
201 OUT BDS_LOAD_OPTION_SUPPORT **DeviceSupport
202 )
203 {
204 UINTN Index;
205
206 // Find which supported device is the most appropriate
207 for (Index = 0; Index < BDS_DEVICE_MAX; Index++) {
208 if (BdsLoadOptionSupportList[Index].IsSupported (DevicePath)) {
209 *DeviceSupport = &BdsLoadOptionSupportList[Index];
210 return EFI_SUCCESS;
211 }
212 }
213
214 return EFI_UNSUPPORTED;
215 }
216
217 EFI_STATUS
218 BootDeviceGetType (
219 IN EFI_DEVICE_PATH* DevicePath,
220 OUT ARM_BDS_LOADER_TYPE *BootType,
221 OUT UINT32 *Attributes
222 )
223 {
224 EFI_STATUS Status;
225 BOOLEAN IsEfiApp;
226 BOOLEAN IsBootLoader;
227 BOOLEAN HasFDTSupport;
228 CHAR16* FileName;
229 EFI_DEVICE_PATH* PrevDevicePathNode;
230 EFI_DEVICE_PATH* DevicePathNode;
231 EFI_PHYSICAL_ADDRESS Image;
232 UINTN FileSize;
233 EFI_IMAGE_DOS_HEADER* DosHeader;
234 UINTN PeCoffHeaderOffset;
235 EFI_IMAGE_NT_HEADERS32* NtHeader;
236
237 //
238 // Check if the last node of the device path is a FilePath node
239 //
240 PrevDevicePathNode = NULL;
241 DevicePathNode = DevicePath;
242 while ((DevicePathNode != NULL) && !IsDevicePathEnd (DevicePathNode)) {
243 PrevDevicePathNode = DevicePathNode;
244 DevicePathNode = NextDevicePathNode (DevicePathNode);
245 }
246
247 if ((PrevDevicePathNode != NULL) &&
248 (PrevDevicePathNode->Type == MEDIA_DEVICE_PATH) &&
249 (PrevDevicePathNode->SubType == MEDIA_FILEPATH_DP))
250 {
251 FileName = ((FILEPATH_DEVICE_PATH*)PrevDevicePathNode)->PathName;
252 } else {
253 FileName = NULL;
254 }
255
256 if (FileName == NULL) {
257 Print(L"Is an EFI Application? ");
258 Status = GetHIInputBoolean (&IsEfiApp);
259 if (EFI_ERROR(Status)) {
260 return EFI_ABORTED;
261 }
262 } else if (HasFilePathEfiExtension(FileName)) {
263 IsEfiApp = TRUE;
264 } else {
265 // Check if the file exist
266 Status = BdsLoadImage (DevicePath, AllocateAnyPages, &Image, &FileSize);
267 if (!EFI_ERROR (Status)) {
268
269 DosHeader = (EFI_IMAGE_DOS_HEADER *)(UINTN) Image;
270 if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
271 //
272 // DOS image header is present,
273 // so read the PE header after the DOS image header.
274 //
275 PeCoffHeaderOffset = DosHeader->e_lfanew;
276 } else {
277 PeCoffHeaderOffset = 0;
278 }
279
280 //
281 // Check PE/COFF image.
282 //
283 NtHeader = (EFI_IMAGE_NT_HEADERS32 *)(UINTN) (Image + PeCoffHeaderOffset);
284 if (NtHeader->Signature != EFI_IMAGE_NT_SIGNATURE) {
285 IsEfiApp = FALSE;
286 } else {
287 IsEfiApp = TRUE;
288 }
289
290 // Free memory
291 gBS->FreePages (Image, EFI_SIZE_TO_PAGES(FileSize));
292 } else {
293 // If we did not manage to open it then ask for the type
294 Print(L"Is an EFI Application? ");
295 Status = GetHIInputBoolean (&IsEfiApp);
296 if (EFI_ERROR(Status)) {
297 return EFI_ABORTED;
298 }
299 }
300 }
301
302 if (IsEfiApp) {
303 Print(L"Is your application is an OS loader? ");
304 Status = GetHIInputBoolean (&IsBootLoader);
305 if (EFI_ERROR(Status)) {
306 return EFI_ABORTED;
307 }
308 if (!IsBootLoader) {
309 *Attributes |= LOAD_OPTION_CATEGORY_APP;
310 }
311 *BootType = BDS_LOADER_EFI_APPLICATION;
312 } else {
313 Print(L"Has FDT support? ");
314 Status = GetHIInputBoolean (&HasFDTSupport);
315 if (EFI_ERROR(Status)) {
316 return EFI_ABORTED;
317 }
318 if (HasFDTSupport) {
319 *BootType = BDS_LOADER_KERNEL_LINUX_FDT;
320 } else {
321 *BootType = BDS_LOADER_KERNEL_LINUX_ATAG;
322 }
323 }
324
325 return EFI_SUCCESS;
326 }
327
328 EFI_STATUS
329 BdsLoadOptionFileSystemList (
330 IN OUT LIST_ENTRY* BdsLoadOptionList
331 )
332 {
333 EFI_STATUS Status;
334 UINTN HandleCount;
335 EFI_HANDLE *HandleBuffer;
336 UINTN Index;
337 BDS_SUPPORTED_DEVICE *SupportedDevice;
338 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* FileProtocol;
339 EFI_FILE_HANDLE Fs;
340 UINTN Size;
341 EFI_FILE_SYSTEM_INFO* FsInfo;
342 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
343
344 // List all the Simple File System Protocols
345 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer);
346 if (EFI_ERROR (Status)) {
347 return Status;
348 }
349
350 for (Index = 0; Index < HandleCount; Index++) {
351 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
352 if (!EFI_ERROR(Status)) {
353 // Allocate BDS Supported Device structure
354 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool (sizeof(BDS_SUPPORTED_DEVICE));
355
356 FileProtocol = NULL;
357 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimpleFileSystemProtocolGuid, (VOID **)&FileProtocol);
358 ASSERT_EFI_ERROR(Status);
359
360 FileProtocol->OpenVolume (FileProtocol, &Fs);
361
362 // Generate a Description from the file system
363 Size = 0;
364 FsInfo = NULL;
365 Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo);
366 if (Status == EFI_BUFFER_TOO_SMALL) {
367 FsInfo = AllocatePool (Size);
368 Status = Fs->GetInfo (Fs, &gEfiFileSystemInfoGuid, &Size, FsInfo);
369 }
370 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"%s (%d MB)",FsInfo->VolumeLabel,(UINT32)(FsInfo->VolumeSize / (1024 * 1024)));
371 FreePool(FsInfo);
372 Fs->Close (Fs);
373
374 SupportedDevice->DevicePathProtocol = DevicePathProtocol;
375 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_FILESYSTEM];
376
377 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
378 }
379 }
380
381 return EFI_SUCCESS;
382 }
383
384 EFI_STATUS
385 BdsLoadOptionFileSystemCreateDevicePath (
386 IN CHAR16* FileName,
387 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes,
388 OUT BOOLEAN *RequestBootType
389 )
390 {
391 EFI_STATUS Status;
392 FILEPATH_DEVICE_PATH* FilePathDevicePath;
393 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];
394 UINTN BootFilePathSize;
395
396 Print(L"File path of the %s: ", FileName);
397 Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);
398 if (EFI_ERROR(Status)) {
399 return EFI_ABORTED;
400 }
401
402 BootFilePathSize = StrSize (BootFilePath);
403 if (BootFilePathSize == 2) {
404 *DevicePathNodes = NULL;
405 return EFI_NOT_FOUND;
406 }
407
408 // Create the FilePath Device Path node
409 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH);
410 FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
411 FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
412 SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
413 CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
414 SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize));
415 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)FilePathDevicePath;
416
417 return Status;
418 }
419
420 EFI_STATUS
421 BdsLoadOptionFileSystemUpdateDevicePath (
422 IN EFI_DEVICE_PATH *OldDevicePath,
423 IN CHAR16* FileName,
424 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath,
425 OUT BOOLEAN *RequestBootType
426 )
427 {
428 EFI_STATUS Status;
429 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];
430 UINTN BootFilePathSize;
431 FILEPATH_DEVICE_PATH* EndingDevicePath;
432 FILEPATH_DEVICE_PATH* FilePathDevicePath;
433 EFI_DEVICE_PATH* DevicePath;
434
435 DevicePath = DuplicateDevicePath (OldDevicePath);
436
437 EndingDevicePath = (FILEPATH_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);
438
439 Print(L"File path of the %s: ", FileName);
440 StrnCpy (BootFilePath, EndingDevicePath->PathName, BOOT_DEVICE_FILEPATH_MAX);
441 Status = EditHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);
442 if (EFI_ERROR(Status)) {
443 return Status;
444 }
445
446 BootFilePathSize = StrSize(BootFilePath);
447 if (BootFilePathSize == 2) {
448 *NewDevicePath = NULL;
449 return EFI_NOT_FOUND;
450 }
451
452 // Create the FilePath Device Path node
453 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)AllocatePool(SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
454 FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
455 FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
456 SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
457 CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
458
459 // Generate the new Device Path by replacing the last node by the updated node
460 SetDevicePathEndNode (EndingDevicePath);
461 *NewDevicePath = AppendDevicePathNode (DevicePath, (CONST EFI_DEVICE_PATH_PROTOCOL *)FilePathDevicePath);
462 FreePool(DevicePath);
463
464 return EFI_SUCCESS;
465 }
466
467 BOOLEAN
468 BdsLoadOptionFileSystemIsSupported (
469 IN EFI_DEVICE_PATH *DevicePath
470 )
471 {
472 EFI_DEVICE_PATH* DevicePathNode;
473
474 DevicePathNode = GetLastDevicePathNode (DevicePath);
475
476 return IS_DEVICE_PATH_NODE(DevicePathNode,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP);
477 }
478
479 STATIC
480 BOOLEAN
481 IsParentDevicePath (
482 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
483 IN EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath
484 )
485 {
486 UINTN ParentSize;
487 UINTN ChildSize;
488
489 ParentSize = GetDevicePathSize (ParentDevicePath);
490 ChildSize = GetDevicePathSize (ChildDevicePath);
491
492 if (ParentSize > ChildSize) {
493 return FALSE;
494 }
495
496 if (CompareMem (ParentDevicePath, ChildDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0) {
497 return FALSE;
498 }
499
500 return TRUE;
501 }
502
503 EFI_STATUS
504 BdsLoadOptionMemMapList (
505 IN OUT LIST_ENTRY* BdsLoadOptionList
506 )
507 {
508 EFI_STATUS Status;
509 UINTN HandleCount;
510 EFI_HANDLE *HandleBuffer;
511 UINTN DevicePathHandleCount;
512 EFI_HANDLE *DevicePathHandleBuffer;
513 BOOLEAN IsParent;
514 UINTN Index;
515 UINTN Index2;
516 BDS_SUPPORTED_DEVICE *SupportedDevice;
517 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
518 EFI_DEVICE_PATH* DevicePath;
519
520 // List all the BlockIo Protocols
521 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);
522 if (EFI_ERROR (Status)) {
523 return Status;
524 }
525
526 for (Index = 0; Index < HandleCount; Index++) {
527 // We only select the handle WITH a Device Path AND not part of Media (to avoid duplication with HardDisk, CDROM, etc)
528 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
529 if (!EFI_ERROR(Status)) {
530 // BlockIo is not part of Media Device Path
531 DevicePath = DevicePathProtocol;
532 while (!IsDevicePathEndType (DevicePath) && (DevicePathType (DevicePath) != MEDIA_DEVICE_PATH)) {
533 DevicePath = NextDevicePathNode (DevicePath);
534 }
535 if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) {
536 continue;
537 }
538
539 // Open all the handle supporting the DevicePath protocol and verify this handle has not got any child
540 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiDevicePathProtocolGuid, NULL, &DevicePathHandleCount, &DevicePathHandleBuffer);
541 ASSERT_EFI_ERROR (Status);
542 IsParent = FALSE;
543 for (Index2 = 0; (Index2 < DevicePathHandleCount) && !IsParent; Index2++) {
544 if (HandleBuffer[Index] != DevicePathHandleBuffer[Index2]) {
545 gBS->HandleProtocol (DevicePathHandleBuffer[Index2], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath);
546 if (IsParentDevicePath (DevicePathProtocol, DevicePath)) {
547 IsParent = TRUE;
548 }
549 }
550 }
551 if (IsParent) {
552 continue;
553 }
554
555 // Allocate BDS Supported Device structure
556 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
557
558 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], SupportedDevice->Description);
559 ASSERT_EFI_ERROR (Status);
560
561 SupportedDevice->DevicePathProtocol = DevicePathProtocol;
562 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_MEMMAP];
563
564 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
565 }
566 }
567
568 return EFI_SUCCESS;
569 }
570
571 EFI_STATUS
572 BdsLoadOptionMemMapCreateDevicePath (
573 IN CHAR16* FileName,
574 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes,
575 OUT BOOLEAN *RequestBootType
576 )
577 {
578 EFI_STATUS Status;
579 MEMMAP_DEVICE_PATH *MemMapDevicePath;
580 CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX];
581 CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX];
582
583 Print(L"Starting Address of the %s: ", FileName);
584 Status = GetHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX);
585 if (EFI_ERROR(Status)) {
586 return EFI_ABORTED;
587 }
588
589 Print(L"Ending Address of the %s: ", FileName);
590 Status = GetHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX);
591 if (EFI_ERROR(Status)) {
592 return EFI_ABORTED;
593 }
594
595 // Create the MemMap Device Path Node
596 MemMapDevicePath = (MEMMAP_DEVICE_PATH*)AllocatePool (sizeof(MEMMAP_DEVICE_PATH) + END_DEVICE_PATH_LENGTH);
597 MemMapDevicePath->Header.Type = HARDWARE_DEVICE_PATH;
598 MemMapDevicePath->Header.SubType = HW_MEMMAP_DP;
599 SetDevicePathNodeLength (MemMapDevicePath, sizeof(MEMMAP_DEVICE_PATH));
600 MemMapDevicePath->MemoryType = EfiBootServicesData;
601 MemMapDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress);
602 MemMapDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress);
603
604 // Set a Device Path End Node after the Memory Map Device Path Node
605 SetDevicePathEndNode (MemMapDevicePath + 1);
606 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)MemMapDevicePath;
607
608 return Status;
609 }
610
611 EFI_STATUS
612 BdsLoadOptionMemMapUpdateDevicePath (
613 IN EFI_DEVICE_PATH *OldDevicePath,
614 IN CHAR16* FileName,
615 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath,
616 OUT BOOLEAN *RequestBootType
617 )
618 {
619 EFI_STATUS Status;
620 CHAR16 StrStartingAddress[BOOT_DEVICE_ADDRESS_MAX];
621 CHAR16 StrEndingAddress[BOOT_DEVICE_ADDRESS_MAX];
622 MEMMAP_DEVICE_PATH* EndingDevicePath;
623 EFI_DEVICE_PATH* DevicePath;
624
625 DevicePath = DuplicateDevicePath (OldDevicePath);
626 EndingDevicePath = (MEMMAP_DEVICE_PATH*)GetLastDevicePathNode (DevicePath);
627
628 Print(L"Starting Address of the %s: ", FileName);
629 UnicodeSPrint (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->StartingAddress);
630 Status = EditHIInputStr (StrStartingAddress, BOOT_DEVICE_ADDRESS_MAX);
631 if (EFI_ERROR(Status)) {
632 return EFI_ABORTED;
633 }
634
635 Print(L"Ending Address of the %s: ", FileName);
636 UnicodeSPrint (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX, L"0x%X", (UINTN)EndingDevicePath->EndingAddress);
637 Status = EditHIInputStr (StrEndingAddress, BOOT_DEVICE_ADDRESS_MAX);
638 if (EFI_ERROR(Status)) {
639 return EFI_ABORTED;
640 }
641
642 EndingDevicePath->StartingAddress = StrHexToUint64 (StrStartingAddress);
643 EndingDevicePath->EndingAddress = StrHexToUint64 (StrEndingAddress);
644
645 if (EFI_ERROR(Status)) {
646 FreePool(DevicePath);
647 } else {
648 *NewDevicePath = DevicePath;
649 }
650
651 return Status;
652 }
653
654 BOOLEAN
655 BdsLoadOptionMemMapIsSupported (
656 IN EFI_DEVICE_PATH *DevicePath
657 )
658 {
659 EFI_DEVICE_PATH* DevicePathNode;
660
661 DevicePathNode = GetLastDevicePathNode (DevicePath);
662
663 return IS_DEVICE_PATH_NODE(DevicePathNode,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);
664 }
665
666 EFI_STATUS
667 BdsLoadOptionPxeList (
668 IN OUT LIST_ENTRY* BdsLoadOptionList
669 )
670 {
671 EFI_STATUS Status;
672 UINTN HandleCount;
673 EFI_HANDLE *HandleBuffer;
674 UINTN Index;
675 BDS_SUPPORTED_DEVICE *SupportedDevice;
676 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
677 EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;
678 CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];
679 EFI_MAC_ADDRESS *Mac;
680
681 // List all the PXE Protocols
682 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);
683 if (EFI_ERROR (Status)) {
684 return Status;
685 }
686
687 for (Index = 0; Index < HandleCount; Index++) {
688 // We only select the handle WITH a Device Path AND the PXE Protocol
689 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
690 if (!EFI_ERROR(Status)) {
691 // Allocate BDS Supported Device structure
692 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
693
694 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);
695 if (!EFI_ERROR(Status)) {
696 Mac = &SimpleNet->Mode->CurrentAddress;
697 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]);
698 } else {
699 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);
700 ASSERT_EFI_ERROR (Status);
701 }
702 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"PXE on %s",DeviceDescription);
703
704 SupportedDevice->DevicePathProtocol = DevicePathProtocol;
705 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_PXE];
706
707 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
708 }
709 }
710
711 return EFI_SUCCESS;
712 }
713
714 EFI_STATUS
715 BdsLoadOptionPxeCreateDevicePath (
716 IN CHAR16* FileName,
717 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes,
718 OUT BOOLEAN *RequestBootType
719 )
720 {
721 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);
722 SetDevicePathEndNode (*DevicePathNodes);
723
724 if (RequestBootType) {
725 *RequestBootType = FALSE;
726 }
727 return EFI_SUCCESS;
728 }
729
730 /**
731 Update the parameters of a Pxe boot option
732
733 @param[in] OldDevicePath Current complete device path of the Pxe boot option.
734 This has to be a valid complete Pxe boot option path.
735 @param[in] FileName Description of the file the path is asked for
736 @param[out] NewDevicePath Pointer to the new complete device path.
737
738 @retval EFI_SUCCESS Update completed
739 @retval EFI_OUT_OF_RESOURCES Fail to perform the update due to lack of resource
740 **/
741 EFI_STATUS
742 BdsLoadOptionPxeUpdateDevicePath (
743 IN EFI_DEVICE_PATH *OldDevicePath,
744 IN CHAR16* FileName,
745 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath,
746 OUT BOOLEAN *RequestBootType
747 )
748 {
749 //
750 // Make a copy of the complete device path that is made of :
751 // the device path of the device supporting the Pxe base code protocol
752 // followed by an end node.
753 //
754 *NewDevicePath = DuplicateDevicePath (OldDevicePath);
755 if (*NewDevicePath == NULL) {
756 return EFI_OUT_OF_RESOURCES;
757 } else {
758 return EFI_SUCCESS;
759 }
760 }
761
762 BOOLEAN
763 BdsLoadOptionPxeIsSupported (
764 IN EFI_DEVICE_PATH *DevicePath
765 )
766 {
767 EFI_STATUS Status;
768 EFI_HANDLE Handle;
769 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
770 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
771
772 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
773 if (EFI_ERROR(Status)) {
774 return FALSE;
775 }
776
777 if (!IsDevicePathEnd(RemainingDevicePath)) {
778 return FALSE;
779 }
780
781 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
782 if (EFI_ERROR (Status)) {
783 return FALSE;
784 } else {
785 return TRUE;
786 }
787 }
788
789 EFI_STATUS
790 BdsLoadOptionTftpList (
791 IN OUT LIST_ENTRY* BdsLoadOptionList
792 )
793 {
794 EFI_STATUS Status;
795 UINTN HandleCount;
796 EFI_HANDLE *HandleBuffer;
797 UINTN Index;
798 BDS_SUPPORTED_DEVICE *SupportedDevice;
799 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
800 EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;
801 CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];
802 EFI_MAC_ADDRESS *Mac;
803
804 // List all the PXE Protocols
805 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);
806 if (EFI_ERROR (Status)) {
807 return Status;
808 }
809
810 for (Index = 0; Index < HandleCount; Index++) {
811 // 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)
812 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
813 if (!EFI_ERROR(Status)) {
814 // Allocate BDS Supported Device structure
815 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
816
817 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);
818 if (!EFI_ERROR(Status)) {
819 Mac = &SimpleNet->Mode->CurrentAddress;
820 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]);
821 } else {
822 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);
823 ASSERT_EFI_ERROR (Status);
824 }
825 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"TFTP on %s",DeviceDescription);
826
827 SupportedDevice->DevicePathProtocol = DevicePathProtocol;
828 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_TFTP];
829
830 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
831 }
832 }
833
834 return EFI_SUCCESS;
835 }
836
837 EFI_STATUS
838 BdsLoadOptionTftpCreateDevicePath (
839 IN CHAR16* FileName,
840 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNodes,
841 OUT BOOLEAN *RequestBootType
842 )
843 {
844 EFI_STATUS Status;
845 BOOLEAN IsDHCP;
846 EFI_IP_ADDRESS LocalIp;
847 EFI_IP_ADDRESS RemoteIp;
848 IPv4_DEVICE_PATH* IPv4DevicePathNode;
849 FILEPATH_DEVICE_PATH* FilePathDevicePath;
850 CHAR16 BootFilePath[BOOT_DEVICE_FILEPATH_MAX];
851 UINTN BootFilePathSize;
852
853 Print(L"Get the IP address from DHCP: ");
854 Status = GetHIInputBoolean (&IsDHCP);
855 if (EFI_ERROR(Status)) {
856 return EFI_ABORTED;
857 }
858
859 if (!IsDHCP) {
860 Print(L"Get the static IP address: ");
861 Status = GetHIInputIP (&LocalIp);
862 if (EFI_ERROR(Status)) {
863 return EFI_ABORTED;
864 }
865 }
866
867 Print(L"Get the TFTP server IP address: ");
868 Status = GetHIInputIP (&RemoteIp);
869 if (EFI_ERROR(Status)) {
870 return EFI_ABORTED;
871 }
872
873 Print(L"File path of the %s : ", FileName);
874 Status = GetHIInputStr (BootFilePath, BOOT_DEVICE_FILEPATH_MAX);
875 if (EFI_ERROR(Status)) {
876 return EFI_ABORTED;
877 }
878
879 BootFilePathSize = StrSize(BootFilePath);
880 if (BootFilePathSize == 2) {
881 return EFI_NOT_FOUND;
882 }
883
884 // Allocate the memory for the IPv4 + File Path Device Path Nodes
885 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)AllocatePool(sizeof(IPv4_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize + END_DEVICE_PATH_LENGTH);
886
887 // Create the IPv4 Device Path
888 IPv4DevicePathNode->Header.Type = MESSAGING_DEVICE_PATH;
889 IPv4DevicePathNode->Header.SubType = MSG_IPv4_DP;
890 SetDevicePathNodeLength (&IPv4DevicePathNode->Header, sizeof(IPv4_DEVICE_PATH));
891 CopyMem (&IPv4DevicePathNode->LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));
892 CopyMem (&IPv4DevicePathNode->RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));
893 IPv4DevicePathNode->LocalPort = 0;
894 IPv4DevicePathNode->RemotePort = 0;
895 IPv4DevicePathNode->Protocol = EFI_IP_PROTO_TCP;
896 IPv4DevicePathNode->StaticIpAddress = (IsDHCP != TRUE);
897
898 // Create the FilePath Device Path node
899 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
900 FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
901 FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
902 SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
903 CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
904
905 // Set the End Device Path Node
906 SetDevicePathEndNode ((VOID*)((UINTN)FilePathDevicePath + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize));
907 *DevicePathNodes = (EFI_DEVICE_PATH_PROTOCOL*)IPv4DevicePathNode;
908
909 return Status;
910 }
911
912 EFI_STATUS
913 BdsLoadOptionTftpUpdateDevicePath (
914 IN EFI_DEVICE_PATH *OldDevicePath,
915 IN CHAR16* FileName,
916 OUT EFI_DEVICE_PATH_PROTOCOL **NewDevicePath,
917 OUT BOOLEAN *RequestBootType
918 )
919 {
920 ASSERT (0);
921 return EFI_UNSUPPORTED;
922 }
923
924 BOOLEAN
925 BdsLoadOptionTftpIsSupported (
926 IN EFI_DEVICE_PATH *DevicePath
927 )
928 {
929 EFI_STATUS Status;
930 EFI_HANDLE Handle;
931 EFI_DEVICE_PATH *RemainingDevicePath;
932 EFI_DEVICE_PATH *NextDevicePath;
933 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
934
935 Status = BdsConnectDevicePath (DevicePath, &Handle, &RemainingDevicePath);
936 if (EFI_ERROR(Status)) {
937 return FALSE;
938 }
939
940 // Validate the Remaining Device Path
941 if (IsDevicePathEnd(RemainingDevicePath)) {
942 return FALSE;
943 }
944 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&
945 !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {
946 return FALSE;
947 }
948 NextDevicePath = NextDevicePathNode (RemainingDevicePath);
949 if (IsDevicePathEnd(NextDevicePath)) {
950 return FALSE;
951 }
952 if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {
953 return FALSE;
954 }
955
956 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
957 if (EFI_ERROR (Status)) {
958 return FALSE;
959 } else {
960 return TRUE;
961 }
962 }