]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BootOptionSupport.c
7de2df4825b761c279f8ea91b5d6e1944a74c632
[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 ASSERT(0);
571 //TODO: Implement me
572 return EFI_SUCCESS;
573 }
574
575 BOOLEAN
576 BdsLoadOptionMemMapIsSupported (
577 IN BDS_LOAD_OPTION* BdsLoadOption
578 )
579 {
580 EFI_DEVICE_PATH* DevicePathNode;
581
582 DevicePathNode = GetLastDevicePathNode (BdsLoadOption->FilePathList);
583
584 return IS_DEVICE_PATH_NODE(DevicePathNode,HARDWARE_DEVICE_PATH,HW_MEMMAP_DP);
585 }
586
587 EFI_STATUS
588 BdsLoadOptionPxeList (
589 IN OUT LIST_ENTRY* BdsLoadOptionList
590 )
591 {
592 EFI_STATUS Status;
593 UINTN HandleCount;
594 EFI_HANDLE *HandleBuffer;
595 UINTN Index;
596 BDS_SUPPORTED_DEVICE *SupportedDevice;
597 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
598 EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;
599 CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];
600 EFI_MAC_ADDRESS *Mac;
601
602 // List all the PXE Protocols
603 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);
604 if (EFI_ERROR (Status)) {
605 return Status;
606 }
607
608 for (Index = 0; Index < HandleCount; Index++) {
609 // We only select the handle WITH a Device Path AND the PXE Protocol
610 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
611 if (!EFI_ERROR(Status)) {
612 // Allocate BDS Supported Device structure
613 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
614
615 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);
616 if (!EFI_ERROR(Status)) {
617 Mac = &SimpleNet->Mode->CurrentAddress;
618 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]);
619 } else {
620 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);
621 ASSERT_EFI_ERROR (Status);
622 }
623 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"PXE on %s",DeviceDescription);
624
625 SupportedDevice->DevicePathProtocol = DevicePathProtocol;
626 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_PXE];
627
628 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
629 }
630 }
631
632 return EFI_SUCCESS;
633 }
634
635 EFI_STATUS
636 BdsLoadOptionPxeCreateDevicePath (
637 IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
638 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
639 OUT BDS_LOADER_TYPE *BootType,
640 OUT UINT32 *Attributes
641 )
642 {
643 *DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL *) AllocatePool (END_DEVICE_PATH_LENGTH);
644 SetDevicePathEndNode (*DevicePathNode);
645 *BootType = BDS_LOADER_EFI_APPLICATION;
646 return EFI_SUCCESS;
647 }
648
649 EFI_STATUS
650 BdsLoadOptionPxeUpdateDevicePath (
651 IN BDS_LOAD_OPTION *BootOption,
652 OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
653 OUT BDS_LOADER_TYPE *BootType,
654 OUT UINT32 *Attributes
655 )
656 {
657 ASSERT (0);
658 return EFI_SUCCESS;
659 }
660
661 BOOLEAN
662 BdsLoadOptionPxeIsSupported (
663 IN BDS_LOAD_OPTION* BdsLoadOption
664 )
665 {
666 EFI_STATUS Status;
667 EFI_HANDLE Handle;
668 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
669 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
670
671 Status = BdsConnectDevicePath (BdsLoadOption->FilePathList, &Handle, &RemainingDevicePath);
672 if (EFI_ERROR(Status)) {
673 return FALSE;
674 }
675
676 if (!IsDevicePathEnd(RemainingDevicePath)) {
677 return FALSE;
678 }
679
680 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
681 if (EFI_ERROR (Status)) {
682 return FALSE;
683 } else {
684 return TRUE;
685 }
686 }
687
688 EFI_STATUS
689 BdsLoadOptionTftpList (
690 IN OUT LIST_ENTRY* BdsLoadOptionList
691 )
692 {
693 EFI_STATUS Status;
694 UINTN HandleCount;
695 EFI_HANDLE *HandleBuffer;
696 UINTN Index;
697 BDS_SUPPORTED_DEVICE *SupportedDevice;
698 EFI_DEVICE_PATH_PROTOCOL* DevicePathProtocol;
699 EFI_SIMPLE_NETWORK_PROTOCOL* SimpleNet;
700 CHAR16 DeviceDescription[BOOT_DEVICE_DESCRIPTION_MAX];
701 EFI_MAC_ADDRESS *Mac;
702
703 // List all the PXE Protocols
704 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiPxeBaseCodeProtocolGuid, NULL, &HandleCount, &HandleBuffer);
705 if (EFI_ERROR (Status)) {
706 return Status;
707 }
708
709 for (Index = 0; Index < HandleCount; Index++) {
710 // 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)
711 Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
712 if (!EFI_ERROR(Status)) {
713 // Allocate BDS Supported Device structure
714 SupportedDevice = (BDS_SUPPORTED_DEVICE*)AllocatePool(sizeof(BDS_SUPPORTED_DEVICE));
715
716 Status = gBS->LocateProtocol (&gEfiSimpleNetworkProtocolGuid, NULL, (VOID **)&SimpleNet);
717 if (!EFI_ERROR(Status)) {
718 Mac = &SimpleNet->Mode->CurrentAddress;
719 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]);
720 } else {
721 Status = GenerateDeviceDescriptionName (HandleBuffer[Index], DeviceDescription);
722 ASSERT_EFI_ERROR (Status);
723 }
724 UnicodeSPrint (SupportedDevice->Description,BOOT_DEVICE_DESCRIPTION_MAX,L"TFP on %s",DeviceDescription);
725
726 SupportedDevice->DevicePathProtocol = DevicePathProtocol;
727 SupportedDevice->Support = &BdsLoadOptionSupportList[BDS_DEVICE_TFTP];
728
729 InsertTailList (BdsLoadOptionList,&SupportedDevice->Link);
730 }
731 }
732
733 return EFI_SUCCESS;
734 }
735
736 EFI_STATUS
737 BdsLoadOptionTftpCreateDevicePath (
738 IN BDS_SUPPORTED_DEVICE* BdsLoadOption,
739 OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
740 OUT BDS_LOADER_TYPE *BootType,
741 OUT UINT32 *Attributes
742 )
743 {
744 EFI_STATUS Status;
745 BOOLEAN IsDHCP;
746 EFI_IP_ADDRESS LocalIp;
747 EFI_IP_ADDRESS RemoteIp;
748 IPv4_DEVICE_PATH* IPv4DevicePathNode;
749 FILEPATH_DEVICE_PATH* FilePathDevicePath;
750 CHAR8 AsciiBootFilePath[BOOT_DEVICE_FILEPATH_MAX];
751 CHAR16* BootFilePath;
752 UINTN BootFilePathSize;
753
754 Print(L"Get the IP address from DHCP: ");
755 Status = GetHIInputBoolean (&IsDHCP);
756 if (EFI_ERROR(Status)) {
757 return EFI_ABORTED;
758 }
759
760 if (!IsDHCP) {
761 Print(L"Get the static IP address: ");
762 Status = GetHIInputIP (&LocalIp);
763 if (EFI_ERROR(Status)) {
764 return EFI_ABORTED;
765 }
766 }
767
768 Print(L"Get the TFTP server IP address: ");
769 Status = GetHIInputIP (&RemoteIp);
770 if (EFI_ERROR(Status)) {
771 return EFI_ABORTED;
772 }
773
774 Print(L"File path of the EFI Application or the kernel: ");
775 Status = GetHIInputAscii (AsciiBootFilePath,BOOT_DEVICE_FILEPATH_MAX);
776 if (EFI_ERROR(Status)) {
777 return EFI_ABORTED;
778 }
779
780 // Convert Ascii into Unicode
781 BootFilePath = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootFilePath) * sizeof(CHAR16));
782 AsciiStrToUnicodeStr (AsciiBootFilePath, BootFilePath);
783 BootFilePathSize = StrSize(BootFilePath);
784
785 // Allocate the memory for the IPv4 + File Path Device Path Nodes
786 IPv4DevicePathNode = (IPv4_DEVICE_PATH*)AllocatePool(sizeof(IPv4_DEVICE_PATH) + SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
787
788 // Create the IPv4 Device Path
789 IPv4DevicePathNode->Header.Type = MESSAGING_DEVICE_PATH;
790 IPv4DevicePathNode->Header.SubType = MSG_IPv4_DP;
791 SetDevicePathNodeLength (&IPv4DevicePathNode->Header, sizeof(IPv4_DEVICE_PATH));
792 CopyMem (&IPv4DevicePathNode->LocalIpAddress, &LocalIp.v4, sizeof (EFI_IPv4_ADDRESS));
793 CopyMem (&IPv4DevicePathNode->RemoteIpAddress, &RemoteIp.v4, sizeof (EFI_IPv4_ADDRESS));
794 IPv4DevicePathNode->LocalPort = 0;
795 IPv4DevicePathNode->RemotePort = 0;
796 IPv4DevicePathNode->Protocol = EFI_IP_PROTO_TCP;
797 IPv4DevicePathNode->StaticIpAddress = (IsDHCP != TRUE);
798
799 // Create the FilePath Device Path node
800 FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1);
801 FilePathDevicePath->Header.Type = MEDIA_DEVICE_PATH;
802 FilePathDevicePath->Header.SubType = MEDIA_FILEPATH_DP;
803 SetDevicePathNodeLength (FilePathDevicePath, SIZE_OF_FILEPATH_DEVICE_PATH + BootFilePathSize);
804 CopyMem (FilePathDevicePath->PathName, BootFilePath, BootFilePathSize);
805 FreePool (BootFilePath);
806
807 Status = BootDeviceGetType (NULL, BootType, Attributes);
808 if (EFI_ERROR(Status)) {
809 FreePool (IPv4DevicePathNode);
810 } else {
811 *DevicePathNode = (EFI_DEVICE_PATH_PROTOCOL*)IPv4DevicePathNode;
812 }
813
814 return Status;
815 }
816
817 EFI_STATUS
818 BdsLoadOptionTftpUpdateDevicePath (
819 IN BDS_LOAD_OPTION *BootOption,
820 OUT EFI_DEVICE_PATH_PROTOCOL** NewDevicePath,
821 OUT BDS_LOADER_TYPE *BootType,
822 OUT UINT32 *Attributes
823 )
824 {
825 ASSERT (0);
826 return EFI_SUCCESS;
827 }
828
829 BOOLEAN
830 BdsLoadOptionTftpIsSupported (
831 IN BDS_LOAD_OPTION* BdsLoadOption
832 )
833 {
834 EFI_STATUS Status;
835 EFI_HANDLE Handle;
836 EFI_DEVICE_PATH *RemainingDevicePath;
837 EFI_DEVICE_PATH *NextDevicePath;
838 EFI_PXE_BASE_CODE_PROTOCOL *PxeBcProtocol;
839
840 Status = BdsConnectDevicePath (BdsLoadOption->FilePathList, &Handle, &RemainingDevicePath);
841 if (EFI_ERROR(Status)) {
842 return FALSE;
843 }
844
845 // Validate the Remaining Device Path
846 if (IsDevicePathEnd(RemainingDevicePath)) {
847 return FALSE;
848 }
849 if (!IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP) &&
850 !IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv6_DP)) {
851 return FALSE;
852 }
853 NextDevicePath = NextDevicePathNode (RemainingDevicePath);
854 if (IsDevicePathEnd(NextDevicePath)) {
855 return FALSE;
856 }
857 if (!IS_DEVICE_PATH_NODE(NextDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)) {
858 return FALSE;
859 }
860
861 Status = gBS->HandleProtocol (Handle, &gEfiPxeBaseCodeProtocolGuid, (VOID **)&PxeBcProtocol);
862 if (EFI_ERROR (Status)) {
863 return FALSE;
864 } else {
865 return TRUE;
866 }
867 }