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