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