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