]> git.proxmox.com Git - mirror_edk2.git/blob - Vlv2TbltDevicePkg/Override/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c
3034853695645fe9505018f32c737d4d10d4b864
[mirror_edk2.git] / Vlv2TbltDevicePkg / Override / IntelFrameworkModulePkg / Library / GenericBdsLib / BdsBoot.c
1 /** @file
2 BDS Lib functions which relate with create or process the boot option.
3
4 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "InternalBdsLib.h"
10 #include "String.h"
11 #include <Library/NetLib.h>
12 #include "Library/DebugLib.h"
13
14 BOOLEAN mEnumBootDevice = FALSE;
15 EFI_HII_HANDLE gBdsLibStringPackHandle = NULL;
16
17 /**
18
19 End Perf entry of BDS
20
21 @param Event The triggered event.
22 @param Context Context for this event.
23
24 **/
25 VOID
26 EFIAPI
27 BmEndOfBdsPerfCode (
28 IN EFI_EVENT Event,
29 IN VOID *Context
30 )
31 {
32 //
33 // Record the performance data for End of BDS
34 //
35 PERF_END(NULL, "BDS", NULL, 0);
36
37 return ;
38 }
39
40 /**
41 The constructor function register UNI strings into imageHandle.
42
43 It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
44
45 @param ImageHandle The firmware allocated handle for the EFI image.
46 @param SystemTable A pointer to the EFI System Table.
47
48 @retval EFI_SUCCESS The constructor successfully added string package.
49 @retval Other value The constructor can't add string package.
50
51 **/
52 EFI_STATUS
53 EFIAPI
54 GenericBdsLibConstructor (
55 IN EFI_HANDLE ImageHandle,
56 IN EFI_SYSTEM_TABLE *SystemTable
57 )
58 {
59
60 gBdsLibStringPackHandle = HiiAddPackages (
61 &gBdsLibStringPackageGuid,
62 ImageHandle,
63 GenericBdsLibStrings,
64 NULL
65 );
66
67 ASSERT (gBdsLibStringPackHandle != NULL);
68
69 return EFI_SUCCESS;
70 }
71
72 /**
73 Deletete the Boot Option from EFI Variable. The Boot Order Arrray
74 is also updated.
75
76 @param OptionNumber The number of Boot option want to be deleted.
77 @param BootOrder The Boot Order array.
78 @param BootOrderSize The size of the Boot Order Array.
79
80 @retval EFI_SUCCESS The Boot Option Variable was found and removed
81 @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible
82 @retval EFI_NOT_FOUND The Boot Option Variable was not found
83 **/
84 EFI_STATUS
85 EFIAPI
86 BdsDeleteBootOption (
87 IN UINTN OptionNumber,
88 IN OUT UINT16 *BootOrder,
89 IN OUT UINTN *BootOrderSize
90 )
91 {
92 CHAR16 BootOption[9];
93 UINTN Index;
94 EFI_STATUS Status;
95
96 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);
97 Status = gRT->SetVariable (
98 BootOption,
99 &gEfiGlobalVariableGuid,
100 0,
101 0,
102 NULL
103 );
104 //
105 // Deleting variable with existing variable implementation shouldn't fail.
106 //
107 ASSERT_EFI_ERROR (Status);
108
109 //
110 // adjust boot order array
111 //
112 for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {
113 if (BootOrder[Index] == OptionNumber) {
114 CopyMem (&BootOrder[Index], &BootOrder[Index+1], *BootOrderSize - (Index+1) * sizeof (UINT16));
115 *BootOrderSize -= sizeof (UINT16);
116 break;
117 }
118 }
119
120 return Status;
121 }
122 /**
123
124 Translate the first n characters of an Ascii string to
125 Unicode characters. The count n is indicated by parameter
126 Size. If Size is greater than the length of string, then
127 the entire string is translated.
128
129
130 @param AStr Pointer to input Ascii string.
131 @param Size The number of characters to translate.
132 @param UStr Pointer to output Unicode string buffer.
133
134 **/
135 VOID
136 AsciiToUnicodeSize (
137 IN UINT8 *AStr,
138 IN UINTN Size,
139 OUT UINT16 *UStr
140 )
141 {
142 UINTN Idx;
143
144 Idx = 0;
145 while (AStr[Idx] != 0) {
146 UStr[Idx] = (CHAR16) AStr[Idx];
147 if (Idx == Size) {
148 break;
149 }
150
151 Idx++;
152 }
153 UStr[Idx] = 0;
154 }
155
156 /**
157 Build Legacy Device Name String according.
158
159 @param CurBBSEntry BBS Table.
160 @param Index Index.
161 @param BufSize The buffer size.
162 @param BootString The output string.
163
164 **/
165 VOID
166 BdsBuildLegacyDevNameString (
167 IN BBS_TABLE *CurBBSEntry,
168 IN UINTN Index,
169 IN UINTN BufSize,
170 OUT CHAR16 *BootString
171 )
172 {
173 CHAR16 *Fmt;
174 CHAR16 *Type;
175 UINT8 *StringDesc;
176 CHAR16 Temp[80];
177
178 switch (Index) {
179 //
180 // Primary Master
181 //
182 case 1:
183 Fmt = L"Primary Master %s";
184 break;
185
186 //
187 // Primary Slave
188 //
189 case 2:
190 Fmt = L"Primary Slave %s";
191 break;
192
193 //
194 // Secondary Master
195 //
196 case 3:
197 Fmt = L"Secondary Master %s";
198 break;
199
200 //
201 // Secondary Slave
202 //
203 case 4:
204 Fmt = L"Secondary Slave %s";
205 break;
206
207 default:
208 Fmt = L"%s";
209 break;
210 }
211
212 switch (CurBBSEntry->DeviceType) {
213 case BBS_FLOPPY:
214 Type = L"Floppy";
215 break;
216
217 case BBS_HARDDISK:
218 Type = L"Harddisk";
219 break;
220
221 case BBS_CDROM:
222 Type = L"CDROM";
223 break;
224
225 case BBS_PCMCIA:
226 Type = L"PCMCIAe";
227 break;
228
229 case BBS_USB:
230 Type = L"USB";
231 break;
232
233 case BBS_EMBED_NETWORK:
234 Type = L"Network";
235 break;
236
237 case BBS_BEV_DEVICE:
238 Type = L"BEVe";
239 break;
240
241 case BBS_UNKNOWN:
242 default:
243 Type = L"Unknown";
244 break;
245 }
246 //
247 // If current BBS entry has its description then use it.
248 //
249 StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
250 if (NULL != StringDesc) {
251 //
252 // Only get fisrt 32 characters, this is suggested by BBS spec
253 //
254 AsciiToUnicodeSize (StringDesc, 32, Temp);
255 Fmt = L"%s";
256 Type = Temp;
257 }
258
259 //
260 // BbsTable 16 entries are for onboard IDE.
261 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
262 //
263 if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {
264 Fmt = L"%s %d";
265 UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
266 } else {
267 UnicodeSPrint (BootString, BufSize, Fmt, Type);
268 }
269 }
270
271 /**
272
273 Create a legacy boot option for the specified entry of
274 BBS table, save it as variable, and append it to the boot
275 order list.
276
277
278 @param CurrentBbsEntry Pointer to current BBS table.
279 @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS
280 @param Index Index of the specified entry in BBS table.
281 @param BootOrderList On input, the original boot order list.
282 On output, the new boot order list attached with the
283 created node.
284 @param BootOrderListSize On input, the original size of boot order list.
285 On output, the size of new boot order list.
286
287 @retval EFI_SUCCESS Boot Option successfully created.
288 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
289 @retval Other Error occurs while setting variable.
290
291 **/
292 EFI_STATUS
293 BdsCreateLegacyBootOption (
294 IN BBS_TABLE *CurrentBbsEntry,
295 IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath,
296 IN UINTN Index,
297 IN OUT UINT16 **BootOrderList,
298 IN OUT UINTN *BootOrderListSize
299 )
300 {
301 EFI_STATUS Status;
302 UINT16 CurrentBootOptionNo;
303 UINT16 BootString[10];
304 CHAR16 BootDesc[100];
305 CHAR8 HelpString[100];
306 UINT16 *NewBootOrderList;
307 UINTN BufferSize;
308 UINTN StringLen;
309 VOID *Buffer;
310 UINT8 *Ptr;
311 UINT16 CurrentBbsDevPathSize;
312 UINTN BootOrderIndex;
313 UINTN BootOrderLastIndex;
314 UINTN ArrayIndex;
315 BOOLEAN IndexNotFound;
316 BBS_BBS_DEVICE_PATH *NewBbsDevPathNode;
317
318 if ((*BootOrderList) == NULL) {
319 CurrentBootOptionNo = 0;
320 } else {
321 for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {
322 IndexNotFound = TRUE;
323 for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {
324 if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {
325 IndexNotFound = FALSE;
326 break;
327 }
328 }
329
330 if (!IndexNotFound) {
331 continue;
332 } else {
333 break;
334 }
335 }
336
337 CurrentBootOptionNo = (UINT16) ArrayIndex;
338 }
339
340 UnicodeSPrint (
341 BootString,
342 sizeof (BootString),
343 L"Boot%04x",
344 CurrentBootOptionNo
345 );
346
347 BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);
348
349 //
350 // Create new BBS device path node with description string
351 //
352 UnicodeStrToAsciiStr (BootDesc, HelpString);
353
354 StringLen = AsciiStrLen (HelpString);
355 NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
356 if (NewBbsDevPathNode == NULL) {
357 return EFI_OUT_OF_RESOURCES;
358 }
359 CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH));
360 CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1);
361 SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
362
363 //
364 // Create entire new CurrentBbsDevPath with end node
365 //
366 CurrentBbsDevPath = AppendDevicePathNode (
367 NULL,
368 (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode
369 );
370 if (CurrentBbsDevPath == NULL) {
371 FreePool (NewBbsDevPathNode);
372 return EFI_OUT_OF_RESOURCES;
373 }
374
375 CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));
376
377 BufferSize = sizeof (UINT32) +
378 sizeof (UINT16) +
379 StrSize (BootDesc) +
380 CurrentBbsDevPathSize +
381 sizeof (BBS_TABLE) +
382 sizeof (UINT16);
383
384 Buffer = AllocateZeroPool (BufferSize);
385 if (Buffer == NULL) {
386 FreePool (NewBbsDevPathNode);
387 FreePool (CurrentBbsDevPath);
388 return EFI_OUT_OF_RESOURCES;
389 }
390
391 Ptr = (UINT8 *) Buffer;
392
393 *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
394 Ptr += sizeof (UINT32);
395
396 *((UINT16 *) Ptr) = CurrentBbsDevPathSize;
397 Ptr += sizeof (UINT16);
398
399 CopyMem (
400 Ptr,
401 BootDesc,
402 StrSize (BootDesc)
403 );
404 Ptr += StrSize (BootDesc);
405
406 CopyMem (
407 Ptr,
408 CurrentBbsDevPath,
409 CurrentBbsDevPathSize
410 );
411 Ptr += CurrentBbsDevPathSize;
412
413 CopyMem (
414 Ptr,
415 CurrentBbsEntry,
416 sizeof (BBS_TABLE)
417 );
418
419 Ptr += sizeof (BBS_TABLE);
420 *((UINT16 *) Ptr) = (UINT16) Index;
421
422 Status = gRT->SetVariable (
423 BootString,
424 &gEfiGlobalVariableGuid,
425 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
426 BufferSize,
427 Buffer
428 );
429
430 FreePool (Buffer);
431
432 Buffer = NULL;
433
434 NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));
435 if (NULL == NewBootOrderList) {
436 FreePool (NewBbsDevPathNode);
437 FreePool (CurrentBbsDevPath);
438 return EFI_OUT_OF_RESOURCES;
439 }
440
441 if (*BootOrderList != NULL) {
442 CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);
443 FreePool (*BootOrderList);
444 }
445
446 BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16));
447 NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo;
448 *BootOrderListSize += sizeof (UINT16);
449 *BootOrderList = NewBootOrderList;
450
451 FreePool (NewBbsDevPathNode);
452 FreePool (CurrentBbsDevPath);
453 return Status;
454 }
455
456 /**
457 Check if the boot option is a legacy one.
458
459 @param BootOptionVar The boot option data payload.
460 @param BbsEntry The BBS Table.
461 @param BbsIndex The table index.
462
463 @retval TRUE It is a legacy boot option.
464 @retval FALSE It is not a legacy boot option.
465
466 **/
467 BOOLEAN
468 BdsIsLegacyBootOption (
469 IN UINT8 *BootOptionVar,
470 OUT BBS_TABLE **BbsEntry,
471 OUT UINT16 *BbsIndex
472 )
473 {
474 UINT8 *Ptr;
475 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
476 BOOLEAN Ret;
477 UINT16 DevPathLen;
478
479 Ptr = BootOptionVar;
480 Ptr += sizeof (UINT32);
481 DevPathLen = *(UINT16 *) Ptr;
482 Ptr += sizeof (UINT16);
483 Ptr += StrSize ((UINT16 *) Ptr);
484 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
485 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
486 Ptr += DevPathLen;
487 *BbsEntry = (BBS_TABLE *) Ptr;
488 Ptr += sizeof (BBS_TABLE);
489 *BbsIndex = *(UINT16 *) Ptr;
490 Ret = TRUE;
491 } else {
492 *BbsEntry = NULL;
493 Ret = FALSE;
494 }
495
496 return Ret;
497 }
498
499 /**
500 Delete all the invalid legacy boot options.
501
502 @retval EFI_SUCCESS All invalide legacy boot options are deleted.
503 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
504 @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
505 **/
506 EFI_STATUS
507 EFIAPI
508 BdsDeleteAllInvalidLegacyBootOptions (
509 VOID
510 )
511 {
512 UINT16 *BootOrder;
513 UINT8 *BootOptionVar;
514 UINTN BootOrderSize;
515 UINTN BootOptionSize;
516 EFI_STATUS Status;
517 UINT16 HddCount;
518 UINT16 BbsCount;
519 HDD_INFO *LocalHddInfo;
520 BBS_TABLE *LocalBbsTable;
521 BBS_TABLE *BbsEntry;
522 UINT16 BbsIndex;
523 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
524 UINTN Index;
525 UINT16 BootOption[10];
526 UINT16 BootDesc[100];
527 BOOLEAN DescStringMatch;
528
529 Status = EFI_SUCCESS;
530 BootOrder = NULL;
531 BootOrderSize = 0;
532 HddCount = 0;
533 BbsCount = 0;
534 LocalHddInfo = NULL;
535 LocalBbsTable = NULL;
536 BbsEntry = NULL;
537
538 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
539 if (EFI_ERROR (Status)) {
540 return Status;
541 }
542
543 BootOrder = BdsLibGetVariableAndSize (
544 L"BootOrder",
545 &gEfiGlobalVariableGuid,
546 &BootOrderSize
547 );
548 if (BootOrder == NULL) {
549 return EFI_NOT_FOUND;
550 }
551
552 LegacyBios->GetBbsInfo (
553 LegacyBios,
554 &HddCount,
555 &LocalHddInfo,
556 &BbsCount,
557 &LocalBbsTable
558 );
559
560 Index = 0;
561 while (Index < BootOrderSize / sizeof (UINT16)) {
562 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
563 BootOptionVar = BdsLibGetVariableAndSize (
564 BootOption,
565 &gEfiGlobalVariableGuid,
566 &BootOptionSize
567 );
568 if (NULL == BootOptionVar) {
569 BootOptionSize = 0;
570 Status = gRT->GetVariable (
571 BootOption,
572 &gEfiGlobalVariableGuid,
573 NULL,
574 &BootOptionSize,
575 BootOptionVar
576 );
577 if (Status == EFI_NOT_FOUND) {
578 //
579 // Update BootOrder
580 //
581 BdsDeleteBootOption (
582 BootOrder[Index],
583 BootOrder,
584 &BootOrderSize
585 );
586 continue;
587 } else {
588 FreePool (BootOrder);
589 return EFI_OUT_OF_RESOURCES;
590 }
591 }
592
593 //
594 // Skip Non-Legacy boot option
595 //
596 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {
597 if (BootOptionVar!= NULL) {
598 FreePool (BootOptionVar);
599 }
600 Index++;
601 continue;
602 }
603
604 if (BbsIndex < BbsCount) {
605 //
606 // Check if BBS Description String is changed
607 //
608 DescStringMatch = FALSE;
609 BdsBuildLegacyDevNameString (
610 &LocalBbsTable[BbsIndex],
611 BbsIndex,
612 sizeof (BootDesc),
613 BootDesc
614 );
615
616 if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {
617 DescStringMatch = TRUE;
618 }
619
620 if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||
621 (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&
622 (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&
623 DescStringMatch) {
624 Index++;
625 continue;
626 }
627 }
628
629 if (BootOptionVar != NULL) {
630 FreePool (BootOptionVar);
631 }
632 //
633 // should delete
634 //
635 BdsDeleteBootOption (
636 BootOrder[Index],
637 BootOrder,
638 &BootOrderSize
639 );
640 }
641
642 //
643 // Adjust the number of boot options.
644 //
645 Status = gRT->SetVariable (
646 L"BootOrder",
647 &gEfiGlobalVariableGuid,
648 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
649 BootOrderSize,
650 BootOrder
651 );
652 //
653 // Shrinking variable with existing variable implementation shouldn't fail.
654 //
655 ASSERT_EFI_ERROR (Status);
656 FreePool (BootOrder);
657
658 return Status;
659 }
660
661 /**
662 Find all legacy boot option by device type.
663
664 @param BootOrder The boot order array.
665 @param BootOptionNum The number of boot option.
666 @param DevType Device type.
667 @param DevName Device name.
668 @param Attribute The boot option attribute.
669 @param BbsIndex The BBS table index.
670 @param OptionNumber The boot option index.
671
672 @retval TRUE The Legacy boot option is found.
673 @retval FALSE The legacy boot option is not found.
674
675 **/
676 BOOLEAN
677 BdsFindLegacyBootOptionByDevTypeAndName (
678 IN UINT16 *BootOrder,
679 IN UINTN BootOptionNum,
680 IN UINT16 DevType,
681 IN CHAR16 *DevName,
682 OUT UINT32 *Attribute,
683 OUT UINT16 *BbsIndex,
684 OUT UINT16 *OptionNumber
685 )
686 {
687 UINTN Index;
688 CHAR16 BootOption[9];
689 UINTN BootOptionSize;
690 UINT8 *BootOptionVar;
691 BBS_TABLE *BbsEntry;
692 BOOLEAN Found;
693
694 BbsEntry = NULL;
695 Found = FALSE;
696
697 if (NULL == BootOrder) {
698 return Found;
699 }
700
701 //
702 // Loop all boot option from variable
703 //
704 for (Index = 0; Index < BootOptionNum; Index++) {
705 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]);
706 BootOptionVar = BdsLibGetVariableAndSize (
707 BootOption,
708 &gEfiGlobalVariableGuid,
709 &BootOptionSize
710 );
711 if (NULL == BootOptionVar) {
712 continue;
713 }
714
715 //
716 // Skip Non-legacy boot option
717 //
718 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {
719 FreePool (BootOptionVar);
720 continue;
721 }
722
723 if (
724 (BbsEntry->DeviceType != DevType) ||
725 (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0)
726 ) {
727 FreePool (BootOptionVar);
728 continue;
729 }
730
731 *Attribute = *(UINT32 *) BootOptionVar;
732 *OptionNumber = BootOrder[Index];
733 Found = TRUE;
734 FreePool (BootOptionVar);
735 break;
736 }
737
738 return Found;
739 }
740
741 /**
742 Create a legacy boot option.
743
744 @param BbsItem The BBS Table entry.
745 @param Index Index of the specified entry in BBS table.
746 @param BootOrderList The boot order list.
747 @param BootOrderListSize The size of boot order list.
748
749 @retval EFI_OUT_OF_RESOURCE No enough memory.
750 @retval EFI_SUCCESS The function complete successfully.
751 @return Other value if the legacy boot option is not created.
752
753 **/
754 EFI_STATUS
755 BdsCreateOneLegacyBootOption (
756 IN BBS_TABLE *BbsItem,
757 IN UINTN Index,
758 IN OUT UINT16 **BootOrderList,
759 IN OUT UINTN *BootOrderListSize
760 )
761 {
762 BBS_BBS_DEVICE_PATH BbsDevPathNode;
763 EFI_STATUS Status;
764 EFI_DEVICE_PATH_PROTOCOL *DevPath;
765
766 DevPath = NULL;
767
768 //
769 // Create device path node.
770 //
771 BbsDevPathNode.Header.Type = BBS_DEVICE_PATH;
772 BbsDevPathNode.Header.SubType = BBS_BBS_DP;
773 SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
774 BbsDevPathNode.DeviceType = BbsItem->DeviceType;
775 CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));
776
777 DevPath = AppendDevicePathNode (
778 NULL,
779 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode
780 );
781 if (NULL == DevPath) {
782 return EFI_OUT_OF_RESOURCES;
783 }
784
785 Status = BdsCreateLegacyBootOption (
786 BbsItem,
787 DevPath,
788 Index,
789 BootOrderList,
790 BootOrderListSize
791 );
792 BbsItem->BootPriority = 0x00;
793
794 FreePool (DevPath);
795
796 return Status;
797 }
798
799 /**
800 Add the legacy boot options from BBS table if they do not exist.
801
802 @retval EFI_SUCCESS The boot options are added successfully
803 or they are already in boot options.
804 @retval EFI_NOT_FOUND No legacy boot options is found.
805 @retval EFI_OUT_OF_RESOURCE No enough memory.
806 @return Other value LegacyBoot options are not added.
807 **/
808 EFI_STATUS
809 EFIAPI
810 BdsAddNonExistingLegacyBootOptions (
811 VOID
812 )
813 {
814 UINT16 *BootOrder;
815 UINTN BootOrderSize;
816 EFI_STATUS Status;
817 CHAR16 Desc[100];
818 UINT16 HddCount;
819 UINT16 BbsCount;
820 HDD_INFO *LocalHddInfo;
821 BBS_TABLE *LocalBbsTable;
822 UINT16 BbsIndex;
823 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
824 UINT16 Index;
825 UINT32 Attribute;
826 UINT16 OptionNumber;
827 BOOLEAN Exist;
828
829 HddCount = 0;
830 BbsCount = 0;
831 LocalHddInfo = NULL;
832 LocalBbsTable = NULL;
833
834 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
835 if (EFI_ERROR (Status)) {
836 return Status;
837 }
838
839 LegacyBios->GetBbsInfo (
840 LegacyBios,
841 &HddCount,
842 &LocalHddInfo,
843 &BbsCount,
844 &LocalBbsTable
845 );
846
847 BootOrder = BdsLibGetVariableAndSize (
848 L"BootOrder",
849 &gEfiGlobalVariableGuid,
850 &BootOrderSize
851 );
852 if (BootOrder == NULL) {
853 BootOrderSize = 0;
854 }
855
856 for (Index = 0; Index < BbsCount; Index++) {
857 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
858 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
859 ) {
860 continue;
861 }
862
863 BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc);
864
865 Exist = BdsFindLegacyBootOptionByDevTypeAndName (
866 BootOrder,
867 BootOrderSize / sizeof (UINT16),
868 LocalBbsTable[Index].DeviceType,
869 Desc,
870 &Attribute,
871 &BbsIndex,
872 &OptionNumber
873 );
874 if (!Exist) {
875 //
876 // Not found such type of legacy device in boot options or we found but it's disabled
877 // so we have to create one and put it to the tail of boot order list
878 //
879 Status = BdsCreateOneLegacyBootOption (
880 &LocalBbsTable[Index],
881 Index,
882 &BootOrder,
883 &BootOrderSize
884 );
885 if (!EFI_ERROR (Status)) {
886 ASSERT (BootOrder != NULL);
887 BbsIndex = Index;
888 OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1];
889 }
890 }
891
892 ASSERT (BbsIndex == Index);
893 }
894
895 Status = gRT->SetVariable (
896 L"BootOrder",
897 &gEfiGlobalVariableGuid,
898 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
899 BootOrderSize,
900 BootOrder
901 );
902 if (BootOrder != NULL) {
903 FreePool (BootOrder);
904 }
905
906 return Status;
907 }
908
909 /**
910 Fill the device order buffer.
911
912 @param BbsTable The BBS table.
913 @param BbsType The BBS Type.
914 @param BbsCount The BBS Count.
915 @param Buf device order buffer.
916
917 @return The device order buffer.
918
919 **/
920 UINT16 *
921 BdsFillDevOrderBuf (
922 IN BBS_TABLE *BbsTable,
923 IN BBS_TYPE BbsType,
924 IN UINTN BbsCount,
925 OUT UINT16 *Buf
926 )
927 {
928 UINTN Index;
929
930 for (Index = 0; Index < BbsCount; Index++) {
931 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
932 continue;
933 }
934
935 if (BbsTable[Index].DeviceType != BbsType) {
936 continue;
937 }
938
939 *Buf = (UINT16) (Index & 0xFF);
940 Buf++;
941 }
942
943 return Buf;
944 }
945
946 /**
947 Create the device order buffer.
948
949 @param BbsTable The BBS table.
950 @param BbsCount The BBS Count.
951
952 @retval EFI_SUCCES The buffer is created and the EFI variable named
953 VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid is
954 set correctly.
955 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
956 @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
957 because of hardware error.
958 **/
959 EFI_STATUS
960 BdsCreateDevOrder (
961 IN BBS_TABLE *BbsTable,
962 IN UINT16 BbsCount
963 )
964 {
965 UINTN Index;
966 UINTN FDCount;
967 UINTN HDCount;
968 UINTN CDCount;
969 UINTN NETCount;
970 UINTN BEVCount;
971 UINTN TotalSize;
972 UINTN HeaderSize;
973 LEGACY_DEV_ORDER_ENTRY *DevOrder;
974 LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
975 EFI_STATUS Status;
976
977 FDCount = 0;
978 HDCount = 0;
979 CDCount = 0;
980 NETCount = 0;
981 BEVCount = 0;
982 TotalSize = 0;
983 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
984 DevOrder = NULL;
985 Status = EFI_SUCCESS;
986
987 //
988 // Count all boot devices
989 //
990 for (Index = 0; Index < BbsCount; Index++) {
991 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
992 continue;
993 }
994
995 switch (BbsTable[Index].DeviceType) {
996 case BBS_FLOPPY:
997 FDCount++;
998 break;
999
1000 case BBS_HARDDISK:
1001 HDCount++;
1002 break;
1003
1004 case BBS_CDROM:
1005 CDCount++;
1006 break;
1007
1008 case BBS_EMBED_NETWORK:
1009 NETCount++;
1010 break;
1011
1012 case BBS_BEV_DEVICE:
1013 BEVCount++;
1014 break;
1015
1016 default:
1017 break;
1018 }
1019 }
1020
1021 TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
1022 TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
1023 TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
1024 TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
1025 TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
1026
1027 //
1028 // Create buffer to hold all boot device order
1029 //
1030 DevOrder = AllocateZeroPool (TotalSize);
1031 if (NULL == DevOrder) {
1032 return EFI_OUT_OF_RESOURCES;
1033 }
1034 DevOrderPtr = DevOrder;
1035
1036 DevOrderPtr->BbsType = BBS_FLOPPY;
1037 DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));
1038 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);
1039
1040 DevOrderPtr->BbsType = BBS_HARDDISK;
1041 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
1042 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);
1043
1044 DevOrderPtr->BbsType = BBS_CDROM;
1045 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
1046 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);
1047
1048 DevOrderPtr->BbsType = BBS_EMBED_NETWORK;
1049 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
1050 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);
1051
1052 DevOrderPtr->BbsType = BBS_BEV_DEVICE;
1053 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
1054 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);
1055
1056 ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder));
1057
1058 //
1059 // Save device order for legacy boot device to variable.
1060 //
1061 Status = gRT->SetVariable (
1062 VAR_LEGACY_DEV_ORDER,
1063 &gEfiLegacyDevOrderVariableGuid,
1064 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1065 TotalSize,
1066 DevOrder
1067 );
1068 FreePool (DevOrder);
1069
1070 return Status;
1071 }
1072
1073 /**
1074 Add the legacy boot devices from BBS table into
1075 the legacy device boot order.
1076
1077 @retval EFI_SUCCESS The boot devices are added successfully.
1078 @retval EFI_NOT_FOUND The legacy boot devices are not found.
1079 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
1080 @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
1081 because of hardware error.
1082 **/
1083 EFI_STATUS
1084 EFIAPI
1085 BdsUpdateLegacyDevOrder (
1086 VOID
1087 )
1088 {
1089 LEGACY_DEV_ORDER_ENTRY *DevOrder;
1090 LEGACY_DEV_ORDER_ENTRY *NewDevOrder;
1091 LEGACY_DEV_ORDER_ENTRY *Ptr;
1092 LEGACY_DEV_ORDER_ENTRY *NewPtr;
1093 UINTN DevOrderSize;
1094 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
1095 EFI_STATUS Status;
1096 UINT16 HddCount;
1097 UINT16 BbsCount;
1098 HDD_INFO *LocalHddInfo;
1099 BBS_TABLE *LocalBbsTable;
1100 UINTN Index;
1101 UINTN Index2;
1102 UINTN *Idx;
1103 UINTN FDCount;
1104 UINTN HDCount;
1105 UINTN CDCount;
1106 UINTN NETCount;
1107 UINTN BEVCount;
1108 UINTN TotalSize;
1109 UINTN HeaderSize;
1110 UINT16 *NewFDPtr;
1111 UINT16 *NewHDPtr;
1112 UINT16 *NewCDPtr;
1113 UINT16 *NewNETPtr;
1114 UINT16 *NewBEVPtr;
1115 UINT16 *NewDevPtr;
1116 UINTN FDIndex;
1117 UINTN HDIndex;
1118 UINTN CDIndex;
1119 UINTN NETIndex;
1120 UINTN BEVIndex;
1121
1122 Idx = NULL;
1123 FDCount = 0;
1124 HDCount = 0;
1125 CDCount = 0;
1126 NETCount = 0;
1127 BEVCount = 0;
1128 TotalSize = 0;
1129 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
1130 FDIndex = 0;
1131 HDIndex = 0;
1132 CDIndex = 0;
1133 NETIndex = 0;
1134 BEVIndex = 0;
1135 NewDevPtr = NULL;
1136
1137 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
1138 if (EFI_ERROR (Status)) {
1139 return Status;
1140 }
1141
1142 Status = LegacyBios->GetBbsInfo (
1143 LegacyBios,
1144 &HddCount,
1145 &LocalHddInfo,
1146 &BbsCount,
1147 &LocalBbsTable
1148 );
1149 if (EFI_ERROR (Status)) {
1150 return Status;
1151 }
1152
1153 DevOrder = BdsLibGetVariableAndSize (
1154 VAR_LEGACY_DEV_ORDER,
1155 &gEfiLegacyDevOrderVariableGuid,
1156 &DevOrderSize
1157 );
1158 if (NULL == DevOrder) {
1159 return BdsCreateDevOrder (LocalBbsTable, BbsCount);
1160 }
1161 //
1162 // First we figure out how many boot devices with same device type respectively
1163 //
1164 for (Index = 0; Index < BbsCount; Index++) {
1165 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
1166 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
1167 ) {
1168 continue;
1169 }
1170
1171 switch (LocalBbsTable[Index].DeviceType) {
1172 case BBS_FLOPPY:
1173 FDCount++;
1174 break;
1175
1176 case BBS_HARDDISK:
1177 HDCount++;
1178 break;
1179
1180 case BBS_CDROM:
1181 CDCount++;
1182 break;
1183
1184 case BBS_EMBED_NETWORK:
1185 NETCount++;
1186 break;
1187
1188 case BBS_BEV_DEVICE:
1189 BEVCount++;
1190 break;
1191
1192 default:
1193 break;
1194 }
1195 }
1196
1197 TotalSize += (HeaderSize + FDCount * sizeof (UINT16));
1198 TotalSize += (HeaderSize + HDCount * sizeof (UINT16));
1199 TotalSize += (HeaderSize + CDCount * sizeof (UINT16));
1200 TotalSize += (HeaderSize + NETCount * sizeof (UINT16));
1201 TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));
1202
1203 NewDevOrder = AllocateZeroPool (TotalSize);
1204 if (NULL == NewDevOrder) {
1205 return EFI_OUT_OF_RESOURCES;
1206 }
1207
1208
1209
1210 //
1211 // copy FD
1212 //
1213 Ptr = DevOrder;
1214 NewPtr = NewDevOrder;
1215 NewPtr->BbsType = Ptr->BbsType;
1216 NewPtr->Length = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
1217 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
1218 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
1219 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1220 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY
1221 ) {
1222 continue;
1223 }
1224
1225 NewPtr->Data[FDIndex] = Ptr->Data[Index];
1226 FDIndex++;
1227 }
1228 NewFDPtr = NewPtr->Data;
1229
1230 //
1231 // copy HD
1232 //
1233 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
1234 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
1235 NewPtr->BbsType = Ptr->BbsType;
1236 NewPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
1237 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
1238 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
1239 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1240 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
1241 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK
1242 ) {
1243 continue;
1244 }
1245
1246 NewPtr->Data[HDIndex] = Ptr->Data[Index];
1247 HDIndex++;
1248 }
1249 NewHDPtr = NewPtr->Data;
1250
1251 //
1252 // copy CD
1253 //
1254 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
1255 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
1256 NewPtr->BbsType = Ptr->BbsType;
1257 NewPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
1258 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
1259 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
1260 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1261 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
1262 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM
1263 ) {
1264 continue;
1265 }
1266
1267 NewPtr->Data[CDIndex] = Ptr->Data[Index];
1268 CDIndex++;
1269 }
1270 NewCDPtr = NewPtr->Data;
1271
1272 //
1273 // copy NET
1274 //
1275 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
1276 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
1277 NewPtr->BbsType = Ptr->BbsType;
1278 NewPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
1279 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
1280 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
1281 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1282 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
1283 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK
1284 ) {
1285 continue;
1286 }
1287
1288 NewPtr->Data[NETIndex] = Ptr->Data[Index];
1289 NETIndex++;
1290 }
1291 NewNETPtr = NewPtr->Data;
1292
1293 //
1294 // copy BEV
1295 //
1296 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
1297 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
1298 NewPtr->BbsType = Ptr->BbsType;
1299 NewPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
1300 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
1301 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
1302 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1303 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
1304 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE
1305 ) {
1306 continue;
1307 }
1308
1309 NewPtr->Data[BEVIndex] = Ptr->Data[Index];
1310 BEVIndex++;
1311 }
1312 NewBEVPtr = NewPtr->Data;
1313
1314 for (Index = 0; Index < BbsCount; Index++) {
1315 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
1316 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
1317 ) {
1318 continue;
1319 }
1320
1321 switch (LocalBbsTable[Index].DeviceType) {
1322 case BBS_FLOPPY:
1323 Idx = &FDIndex;
1324 NewDevPtr = NewFDPtr;
1325 break;
1326
1327 case BBS_HARDDISK:
1328 Idx = &HDIndex;
1329 NewDevPtr = NewHDPtr;
1330 break;
1331
1332 case BBS_CDROM:
1333 Idx = &CDIndex;
1334 NewDevPtr = NewCDPtr;
1335 break;
1336
1337 case BBS_EMBED_NETWORK:
1338 Idx = &NETIndex;
1339 NewDevPtr = NewNETPtr;
1340 break;
1341
1342 case BBS_BEV_DEVICE:
1343 Idx = &BEVIndex;
1344 NewDevPtr = NewBEVPtr;
1345 break;
1346
1347 default:
1348 Idx = NULL;
1349 break;
1350 }
1351 //
1352 // at this point we have copied those valid indexes to new buffer
1353 // and we should check if there is any new appeared boot device
1354 //
1355 if (Idx != NULL) {
1356 for (Index2 = 0; Index2 < *Idx; Index2++) {
1357 if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {
1358 break;
1359 }
1360 }
1361
1362 if (Index2 == *Idx) {
1363 //
1364 // Index2 == *Idx means we didn't find Index
1365 // so Index is a new appeared device's index in BBS table
1366 // insert it before disabled indexes.
1367 //
1368 for (Index2 = 0; Index2 < *Idx; Index2++) {
1369 if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {
1370 break;
1371 }
1372 }
1373 CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16));
1374 NewDevPtr[Index2] = (UINT16) (Index & 0xFF);
1375 (*Idx)++;
1376 }
1377 }
1378 }
1379
1380 FreePool (DevOrder);
1381
1382 Status = gRT->SetVariable (
1383 VAR_LEGACY_DEV_ORDER,
1384 &gEfiLegacyDevOrderVariableGuid,
1385 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1386 TotalSize,
1387 NewDevOrder
1388 );
1389 FreePool (NewDevOrder);
1390
1391 return Status;
1392 }
1393
1394 /**
1395 Set Boot Priority for specified device type.
1396
1397 @param DeviceType The device type.
1398 @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
1399 @param LocalBbsTable The BBS table.
1400 @param Priority The prority table.
1401
1402 @retval EFI_SUCCESS The function completes successfully.
1403 @retval EFI_NOT_FOUND Failed to find device.
1404 @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
1405
1406 **/
1407 EFI_STATUS
1408 BdsSetBootPriority4SameTypeDev (
1409 IN UINT16 DeviceType,
1410 IN UINTN BbsIndex,
1411 IN OUT BBS_TABLE *LocalBbsTable,
1412 IN OUT UINT16 *Priority
1413 )
1414 {
1415 LEGACY_DEV_ORDER_ENTRY *DevOrder;
1416 LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
1417 UINTN DevOrderSize;
1418 UINTN Index;
1419
1420 DevOrder = BdsLibGetVariableAndSize (
1421 VAR_LEGACY_DEV_ORDER,
1422 &gEfiLegacyDevOrderVariableGuid,
1423 &DevOrderSize
1424 );
1425 if (NULL == DevOrder) {
1426 return EFI_OUT_OF_RESOURCES;
1427 }
1428
1429 DevOrderPtr = DevOrder;
1430 while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {
1431 if (DevOrderPtr->BbsType == DeviceType) {
1432 break;
1433 }
1434
1435 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length);
1436 }
1437
1438 if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {
1439 FreePool (DevOrder);
1440 return EFI_NOT_FOUND;
1441 }
1442
1443 if (BbsIndex != (UINTN) -1) {
1444 LocalBbsTable[BbsIndex].BootPriority = *Priority;
1445 (*Priority)++;
1446 }
1447 //
1448 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
1449 //
1450 for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {
1451 if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {
1452 //
1453 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
1454 //
1455 } else if (DevOrderPtr->Data[Index] != BbsIndex) {
1456 LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;
1457 (*Priority)++;
1458 }
1459 }
1460
1461 FreePool (DevOrder);
1462 return EFI_SUCCESS;
1463 }
1464
1465 /**
1466 Print the BBS Table.
1467
1468 @param LocalBbsTable The BBS table.
1469 @param BbsCount The count of entry in BBS table.
1470 **/
1471 VOID
1472 PrintBbsTable (
1473 IN BBS_TABLE *LocalBbsTable,
1474 IN UINT16 BbsCount
1475 )
1476 {
1477 UINT16 Idx;
1478
1479 DEBUG ((DEBUG_ERROR, "\n"));
1480 DEBUG ((DEBUG_ERROR, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
1481 DEBUG ((DEBUG_ERROR, "=============================================\n"));
1482 for (Idx = 0; Idx < BbsCount; Idx++) {
1483 if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) ||
1484 (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) ||
1485 (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY)
1486 ) {
1487 continue;
1488 }
1489
1490 DEBUG (
1491 (DEBUG_ERROR,
1492 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
1493 (UINTN) Idx,
1494 (UINTN) LocalBbsTable[Idx].BootPriority,
1495 (UINTN) LocalBbsTable[Idx].Bus,
1496 (UINTN) LocalBbsTable[Idx].Device,
1497 (UINTN) LocalBbsTable[Idx].Function,
1498 (UINTN) LocalBbsTable[Idx].Class,
1499 (UINTN) LocalBbsTable[Idx].SubClass,
1500 (UINTN) LocalBbsTable[Idx].DeviceType,
1501 (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,
1502 (UINTN) LocalBbsTable[Idx].BootHandlerSegment,
1503 (UINTN) LocalBbsTable[Idx].BootHandlerOffset,
1504 (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),
1505 (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset))
1506 );
1507 }
1508
1509 DEBUG ((DEBUG_ERROR, "\n"));
1510 }
1511
1512 /**
1513 Set the boot priority for BBS entries based on boot option entry and boot order.
1514
1515 @param Entry The boot option is to be checked for refresh BBS table.
1516
1517 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
1518 @retval EFI_NOT_FOUND BBS entries can't be found.
1519 @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
1520 **/
1521 EFI_STATUS
1522 EFIAPI
1523 BdsRefreshBbsTableForBoot (
1524 IN BDS_COMMON_OPTION *Entry
1525 )
1526 {
1527 EFI_STATUS Status;
1528 UINT16 BbsIndex;
1529 UINT16 HddCount;
1530 UINT16 BbsCount;
1531 HDD_INFO *LocalHddInfo;
1532 BBS_TABLE *LocalBbsTable;
1533 UINT16 DevType;
1534 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
1535 UINTN Index;
1536 UINT16 Priority;
1537 UINT16 *BootOrder;
1538 UINTN BootOrderSize;
1539 UINT8 *BootOptionVar;
1540 UINTN BootOptionSize;
1541 CHAR16 BootOption[9];
1542 UINT8 *Ptr;
1543 UINT16 DevPathLen;
1544 EFI_DEVICE_PATH_PROTOCOL *DevPath;
1545 UINT16 *DeviceType;
1546 UINTN DeviceTypeCount;
1547 UINTN DeviceTypeIndex;
1548
1549 HddCount = 0;
1550 BbsCount = 0;
1551 LocalHddInfo = NULL;
1552 LocalBbsTable = NULL;
1553 DevType = BBS_UNKNOWN;
1554
1555 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
1556 if (EFI_ERROR (Status)) {
1557 return Status;
1558 }
1559
1560 LegacyBios->GetBbsInfo (
1561 LegacyBios,
1562 &HddCount,
1563 &LocalHddInfo,
1564 &BbsCount,
1565 &LocalBbsTable
1566 );
1567 //
1568 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
1569 // We will set them according to the settings setup by user
1570 //
1571 for (Index = 0; Index < BbsCount; Index++) {
1572 if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) ||
1573 (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) ||
1574 (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) {
1575 LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
1576 }
1577 }
1578 //
1579 // boot priority always starts at 0
1580 //
1581 Priority = 0;
1582 if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) {
1583 //
1584 // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.
1585 //
1586 DevType = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType;
1587 BbsIndex = *(UINT16 *) ((BBS_TABLE *) Entry->LoadOptions + 1);
1588 Status = BdsSetBootPriority4SameTypeDev (
1589 DevType,
1590 BbsIndex,
1591 LocalBbsTable,
1592 &Priority
1593 );
1594 if (EFI_ERROR (Status)) {
1595 return Status;
1596 }
1597 }
1598 //
1599 // we have to set the boot priority for other BBS entries with different device types
1600 //
1601 BootOrder = BdsLibGetVariableAndSize (
1602 L"BootOrder",
1603 &gEfiGlobalVariableGuid,
1604 &BootOrderSize
1605 );
1606 DeviceType = AllocatePool (BootOrderSize + sizeof (UINT16));
1607 ASSERT (DeviceType != NULL);
1608
1609 DeviceType[0] = DevType;
1610 DeviceTypeCount = 1;
1611 for (Index = 0; ((BootOrder != NULL) && (Index < BootOrderSize / sizeof (UINT16))); Index++) {
1612 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
1613 BootOptionVar = BdsLibGetVariableAndSize (
1614 BootOption,
1615 &gEfiGlobalVariableGuid,
1616 &BootOptionSize
1617 );
1618 if (NULL == BootOptionVar) {
1619 continue;
1620 }
1621
1622 Ptr = BootOptionVar;
1623
1624 Ptr += sizeof (UINT32);
1625 DevPathLen = *(UINT16 *) Ptr;
1626 Ptr += sizeof (UINT16);
1627 Ptr += StrSize ((UINT16 *) Ptr);
1628 DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
1629 if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {
1630 FreePool (BootOptionVar);
1631 continue;
1632 }
1633
1634 Ptr += DevPathLen;
1635 DevType = ((BBS_TABLE *) Ptr)->DeviceType;
1636 for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) {
1637 if (DeviceType[DeviceTypeIndex] == DevType) {
1638 break;
1639 }
1640 }
1641 if (DeviceTypeIndex < DeviceTypeCount) {
1642 //
1643 // We don't want to process twice for a device type
1644 //
1645 FreePool (BootOptionVar);
1646 continue;
1647 }
1648
1649 DeviceType[DeviceTypeCount] = DevType;
1650 DeviceTypeCount++;
1651
1652 Status = BdsSetBootPriority4SameTypeDev (
1653 DevType,
1654 (UINTN) -1,
1655 LocalBbsTable,
1656 &Priority
1657 );
1658 FreePool (BootOptionVar);
1659 if (EFI_ERROR (Status)) {
1660 break;
1661 }
1662 }
1663
1664 FreePool (DeviceType);
1665
1666 if (BootOrder != NULL) {
1667 FreePool (BootOrder);
1668 }
1669
1670 DEBUG_CODE_BEGIN();
1671 PrintBbsTable (LocalBbsTable, BbsCount);
1672 DEBUG_CODE_END();
1673
1674 return Status;
1675 }
1676
1677 /**
1678 Boot the legacy system with the boot option
1679
1680 @param Option The legacy boot option which have BBS device path
1681
1682 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
1683 legacy boot.
1684 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
1685
1686 **/
1687 EFI_STATUS
1688 BdsLibDoLegacyBoot (
1689 IN BDS_COMMON_OPTION *Option
1690 )
1691 {
1692 EFI_STATUS Status;
1693 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
1694 EFI_EVENT LegacyBootEvent;
1695
1696 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
1697 if (EFI_ERROR (Status)) {
1698 //
1699 // If no LegacyBios protocol we do not support legacy boot
1700 //
1701 return EFI_UNSUPPORTED;
1702 }
1703 //
1704 // Notes: if we separate the int 19, then we don't need to refresh BBS
1705 //
1706 BdsRefreshBbsTableForBoot (Option);
1707
1708 //
1709 // Write boot to OS performance data for legacy boot.
1710 //
1711 PERF_CODE (
1712 //
1713 // Create an event to be signalled when Legacy Boot occurs to write performance data.
1714 //
1715 Status = EfiCreateEventLegacyBootEx(
1716 TPL_NOTIFY,
1717 BmEndOfBdsPerfCode,
1718 NULL,
1719 &LegacyBootEvent
1720 );
1721 ASSERT_EFI_ERROR (Status);
1722 );
1723
1724 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));
1725 return LegacyBios->LegacyBoot (
1726 LegacyBios,
1727 (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
1728 Option->LoadOptionsSize,
1729 Option->LoadOptions
1730 );
1731 }
1732
1733 /**
1734 Internal function to check if the input boot option is a valid EFI NV Boot####.
1735
1736 @param OptionToCheck Boot option to be checked.
1737
1738 @retval TRUE This boot option matches a valid EFI NV Boot####.
1739 @retval FALSE If not.
1740
1741 **/
1742 BOOLEAN
1743 IsBootOptionValidNVVarialbe (
1744 IN BDS_COMMON_OPTION *OptionToCheck
1745 )
1746 {
1747 LIST_ENTRY TempList;
1748 BDS_COMMON_OPTION *BootOption;
1749 BOOLEAN Valid;
1750 CHAR16 OptionName[20];
1751
1752 Valid = FALSE;
1753
1754 InitializeListHead (&TempList);
1755 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToCheck->BootCurrent);
1756
1757 BootOption = BdsLibVariableToOption (&TempList, OptionName);
1758 if (BootOption == NULL) {
1759 return FALSE;
1760 }
1761
1762 //
1763 // If the Boot Option Number and Device Path matches, OptionToCheck matches a
1764 // valid EFI NV Boot####.
1765 //
1766 if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) &&
1767 (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0))
1768 {
1769 Valid = TRUE;
1770 }
1771
1772 FreePool (BootOption);
1773
1774 return Valid;
1775 }
1776
1777 /**
1778 Check whether a USB device match the specified USB Class device path. This
1779 function follows "Load Option Processing" behavior in UEFI specification.
1780
1781 @param UsbIo USB I/O protocol associated with the USB device.
1782 @param UsbClass The USB Class device path to match.
1783
1784 @retval TRUE The USB device match the USB Class device path.
1785 @retval FALSE The USB device does not match the USB Class device path.
1786
1787 **/
1788 BOOLEAN
1789 BdsMatchUsbClass (
1790 IN EFI_USB_IO_PROTOCOL *UsbIo,
1791 IN USB_CLASS_DEVICE_PATH *UsbClass
1792 )
1793 {
1794 EFI_STATUS Status;
1795 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
1796 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
1797 UINT8 DeviceClass;
1798 UINT8 DeviceSubClass;
1799 UINT8 DeviceProtocol;
1800
1801 if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
1802 (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
1803 return FALSE;
1804 }
1805
1806 //
1807 // Check Vendor Id and Product Id.
1808 //
1809 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
1810 if (EFI_ERROR (Status)) {
1811 return FALSE;
1812 }
1813
1814 if ((UsbClass->VendorId != 0xffff) &&
1815 (UsbClass->VendorId != DevDesc.IdVendor)) {
1816 return FALSE;
1817 }
1818
1819 if ((UsbClass->ProductId != 0xffff) &&
1820 (UsbClass->ProductId != DevDesc.IdProduct)) {
1821 return FALSE;
1822 }
1823
1824 DeviceClass = DevDesc.DeviceClass;
1825 DeviceSubClass = DevDesc.DeviceSubClass;
1826 DeviceProtocol = DevDesc.DeviceProtocol;
1827 if (DeviceClass == 0) {
1828 //
1829 // If Class in Device Descriptor is set to 0, use the Class, SubClass and
1830 // Protocol in Interface Descriptor instead.
1831 //
1832 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
1833 if (EFI_ERROR (Status)) {
1834 return FALSE;
1835 }
1836
1837 DeviceClass = IfDesc.InterfaceClass;
1838 DeviceSubClass = IfDesc.InterfaceSubClass;
1839 DeviceProtocol = IfDesc.InterfaceProtocol;
1840 }
1841
1842 //
1843 // Check Class, SubClass and Protocol.
1844 //
1845 if ((UsbClass->DeviceClass != 0xff) &&
1846 (UsbClass->DeviceClass != DeviceClass)) {
1847 return FALSE;
1848 }
1849
1850 if ((UsbClass->DeviceSubClass != 0xff) &&
1851 (UsbClass->DeviceSubClass != DeviceSubClass)) {
1852 return FALSE;
1853 }
1854
1855 if ((UsbClass->DeviceProtocol != 0xff) &&
1856 (UsbClass->DeviceProtocol != DeviceProtocol)) {
1857 return FALSE;
1858 }
1859
1860 return TRUE;
1861 }
1862
1863 /**
1864 Check whether a USB device match the specified USB WWID device path. This
1865 function follows "Load Option Processing" behavior in UEFI specification.
1866
1867 @param UsbIo USB I/O protocol associated with the USB device.
1868 @param UsbWwid The USB WWID device path to match.
1869
1870 @retval TRUE The USB device match the USB WWID device path.
1871 @retval FALSE The USB device does not match the USB WWID device path.
1872
1873 **/
1874 BOOLEAN
1875 BdsMatchUsbWwid (
1876 IN EFI_USB_IO_PROTOCOL *UsbIo,
1877 IN USB_WWID_DEVICE_PATH *UsbWwid
1878 )
1879 {
1880 EFI_STATUS Status;
1881 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
1882 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
1883 UINT16 *LangIdTable;
1884 UINT16 TableSize;
1885 UINT16 Index;
1886 CHAR16 *CompareStr;
1887 UINTN CompareLen;
1888 CHAR16 *SerialNumberStr;
1889 UINTN Length;
1890
1891 if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
1892 (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP )){
1893 return FALSE;
1894 }
1895
1896 //
1897 // Check Vendor Id and Product Id.
1898 //
1899 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
1900 if (EFI_ERROR (Status)) {
1901 return FALSE;
1902 }
1903 if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
1904 (DevDesc.IdProduct != UsbWwid->ProductId)) {
1905 return FALSE;
1906 }
1907
1908 //
1909 // Check Interface Number.
1910 //
1911 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
1912 if (EFI_ERROR (Status)) {
1913 return FALSE;
1914 }
1915 if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
1916 return FALSE;
1917 }
1918
1919 //
1920 // Check Serial Number.
1921 //
1922 if (DevDesc.StrSerialNumber == 0) {
1923 return FALSE;
1924 }
1925
1926 //
1927 // Get all supported languages.
1928 //
1929 TableSize = 0;
1930 LangIdTable = NULL;
1931 Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
1932 if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
1933 return FALSE;
1934 }
1935
1936 //
1937 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
1938 //
1939 CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
1940 CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
1941 if (CompareStr[CompareLen - 1] == L'\0') {
1942 CompareLen--;
1943 }
1944
1945 //
1946 // Compare serial number in each supported language.
1947 //
1948 for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
1949 SerialNumberStr = NULL;
1950 Status = UsbIo->UsbGetStringDescriptor (
1951 UsbIo,
1952 LangIdTable[Index],
1953 DevDesc.StrSerialNumber,
1954 &SerialNumberStr
1955 );
1956 if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
1957 continue;
1958 }
1959
1960 Length = StrLen (SerialNumberStr);
1961 if ((Length >= CompareLen) &&
1962 (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
1963 FreePool (SerialNumberStr);
1964 return TRUE;
1965 }
1966
1967 FreePool (SerialNumberStr);
1968 }
1969
1970 return FALSE;
1971 }
1972
1973 /**
1974 Find a USB device path which match the specified short-form device path start
1975 with USB Class or USB WWID device path and load the boot file then return the
1976 image handle. If ParentDevicePath is NULL, this function will search in all USB
1977 devices of the platform. If ParentDevicePath is not NULL,this function will only
1978 search in its child devices.
1979
1980 @param ParentDevicePath The device path of the parent.
1981 @param ShortFormDevicePath The USB Class or USB WWID device path to match.
1982
1983 @return The image Handle if find load file from specified short-form device path
1984 or NULL if not found.
1985
1986 **/
1987 EFI_HANDLE *
1988 BdsFindUsbDevice (
1989 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
1990 IN EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath
1991 )
1992 {
1993 EFI_STATUS Status;
1994 UINTN UsbIoHandleCount;
1995 EFI_HANDLE *UsbIoHandleBuffer;
1996 EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
1997 EFI_USB_IO_PROTOCOL *UsbIo;
1998 UINTN Index;
1999 UINTN ParentSize;
2000 UINTN Size;
2001 EFI_HANDLE ImageHandle;
2002 EFI_HANDLE Handle;
2003 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
2004 EFI_DEVICE_PATH_PROTOCOL *NextDevicePath;
2005
2006 FullDevicePath = NULL;
2007 ImageHandle = NULL;
2008
2009 //
2010 // Get all UsbIo Handles.
2011 //
2012 UsbIoHandleCount = 0;
2013 UsbIoHandleBuffer = NULL;
2014 Status = gBS->LocateHandleBuffer (
2015 ByProtocol,
2016 &gEfiUsbIoProtocolGuid,
2017 NULL,
2018 &UsbIoHandleCount,
2019 &UsbIoHandleBuffer
2020 );
2021 if (EFI_ERROR (Status) || (UsbIoHandleCount == 0) || (UsbIoHandleBuffer == NULL)) {
2022 return NULL;
2023 }
2024
2025 ParentSize = (ParentDevicePath == NULL) ? 0 : GetDevicePathSize (ParentDevicePath);
2026 for (Index = 0; Index < UsbIoHandleCount; Index++) {
2027 //
2028 // Get the Usb IO interface.
2029 //
2030 Status = gBS->HandleProtocol(
2031 UsbIoHandleBuffer[Index],
2032 &gEfiUsbIoProtocolGuid,
2033 (VOID **) &UsbIo
2034 );
2035 if (EFI_ERROR (Status)) {
2036 continue;
2037 }
2038
2039 UsbIoDevicePath = DevicePathFromHandle (UsbIoHandleBuffer[Index]);
2040 if (UsbIoDevicePath == NULL) {
2041 continue;
2042 }
2043
2044 if (ParentDevicePath != NULL) {
2045 //
2046 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
2047 //
2048 Size = GetDevicePathSize (UsbIoDevicePath);
2049 if ((Size < ParentSize) ||
2050 (CompareMem (UsbIoDevicePath, ParentDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0)) {
2051 continue;
2052 }
2053 }
2054
2055 if (BdsMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ShortFormDevicePath) ||
2056 BdsMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ShortFormDevicePath)) {
2057 //
2058 // Try to find if there is the boot file in this DevicePath
2059 //
2060 NextDevicePath = NextDevicePathNode (ShortFormDevicePath);
2061 if (!IsDevicePathEnd (NextDevicePath)) {
2062 FullDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePath);
2063 //
2064 // Connect the full device path, so that Simple File System protocol
2065 // could be installed for this USB device.
2066 //
2067 BdsLibConnectDevicePath (FullDevicePath);
2068 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
2069 Status = gBS->LoadImage (
2070 TRUE,
2071 gImageHandle,
2072 FullDevicePath,
2073 NULL,
2074 0,
2075 &ImageHandle
2076 );
2077 FreePool (FullDevicePath);
2078 } else {
2079 FullDevicePath = UsbIoDevicePath;
2080 Status = EFI_NOT_FOUND;
2081 }
2082
2083 //
2084 // If we didn't find an image directly, we need to try as if it is a removable device boot option
2085 // and load the image according to the default boot behavior for removable device.
2086 //
2087 if (EFI_ERROR (Status)) {
2088 //
2089 // check if there is a bootable removable media could be found in this device path ,
2090 // and get the bootable media handle
2091 //
2092 Handle = BdsLibGetBootableHandle(UsbIoDevicePath);
2093 if (Handle == NULL) {
2094 continue;
2095 }
2096 //
2097 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
2098 // machinename is ia32, ia64, x64, ...
2099 //
2100 FullDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
2101 if (FullDevicePath != NULL) {
2102 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
2103 Status = gBS->LoadImage (
2104 TRUE,
2105 gImageHandle,
2106 FullDevicePath,
2107 NULL,
2108 0,
2109 &ImageHandle
2110 );
2111 if (EFI_ERROR (Status)) {
2112 //
2113 // The DevicePath failed, and it's not a valid
2114 // removable media device.
2115 //
2116 continue;
2117 }
2118 } else {
2119 continue;
2120 }
2121 }
2122 break;
2123 }
2124 }
2125
2126 FreePool (UsbIoHandleBuffer);
2127 return ImageHandle;
2128 }
2129
2130 /**
2131 Expand USB Class or USB WWID device path node to be full device path of a USB
2132 device in platform then load the boot file on this full device path and return the
2133 image handle.
2134
2135 This function support following 4 cases:
2136 1) Boot Option device path starts with a USB Class or USB WWID device path,
2137 and there is no Media FilePath device path in the end.
2138 In this case, it will follow Removable Media Boot Behavior.
2139 2) Boot Option device path starts with a USB Class or USB WWID device path,
2140 and ended with Media FilePath device path.
2141 3) Boot Option device path starts with a full device path to a USB Host Controller,
2142 contains a USB Class or USB WWID device path node, while not ended with Media
2143 FilePath device path. In this case, it will follow Removable Media Boot Behavior.
2144 4) Boot Option device path starts with a full device path to a USB Host Controller,
2145 contains a USB Class or USB WWID device path node, and ended with Media
2146 FilePath device path.
2147
2148 @param DevicePath The Boot Option device path.
2149
2150 @return The image handle of boot file, or NULL if there is no boot file found in
2151 the specified USB Class or USB WWID device path.
2152
2153 **/
2154 EFI_HANDLE *
2155 BdsExpandUsbShortFormDevicePath (
2156 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
2157 )
2158 {
2159 EFI_HANDLE *ImageHandle;
2160 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
2161 EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath;
2162
2163 //
2164 // Search for USB Class or USB WWID device path node.
2165 //
2166 ShortFormDevicePath = NULL;
2167 ImageHandle = NULL;
2168 TempDevicePath = DevicePath;
2169 while (!IsDevicePathEnd (TempDevicePath)) {
2170 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
2171 ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
2172 (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
2173 ShortFormDevicePath = TempDevicePath;
2174 break;
2175 }
2176 TempDevicePath = NextDevicePathNode (TempDevicePath);
2177 }
2178
2179 if (ShortFormDevicePath == NULL) {
2180 //
2181 // No USB Class or USB WWID device path node found, do nothing.
2182 //
2183 return NULL;
2184 }
2185
2186 if (ShortFormDevicePath == DevicePath) {
2187 //
2188 // Boot Option device path starts with USB Class or USB WWID device path.
2189 //
2190 ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
2191 if (ImageHandle == NULL) {
2192 //
2193 // Failed to find a match in existing devices, connect the short form USB
2194 // device path and try again.
2195 //
2196 BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath);
2197 ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
2198 }
2199 } else {
2200 //
2201 // Boot Option device path contains USB Class or USB WWID device path node.
2202 //
2203
2204 //
2205 // Prepare the parent device path for search.
2206 //
2207 TempDevicePath = DuplicateDevicePath (DevicePath);
2208 ASSERT (TempDevicePath != NULL);
2209 SetDevicePathEndNode (((UINT8 *) TempDevicePath) + ((UINTN) ShortFormDevicePath - (UINTN) DevicePath));
2210
2211 //
2212 // The USB Host Controller device path is already in Boot Option device path
2213 // and USB Bus driver already support RemainingDevicePath starts with USB
2214 // Class or USB WWID device path, so just search in existing USB devices and
2215 // doesn't perform ConnectController here.
2216 //
2217 ImageHandle = BdsFindUsbDevice (TempDevicePath, ShortFormDevicePath);
2218 FreePool (TempDevicePath);
2219 }
2220
2221 return ImageHandle;
2222 }
2223
2224 /**
2225 Process the boot option follow the UEFI specification and
2226 special treat the legacy boot option with BBS_DEVICE_PATH.
2227
2228 @param Option The boot option need to be processed
2229 @param DevicePath The device path which describe where to load the
2230 boot image or the legacy BBS device path to boot
2231 the legacy OS
2232 @param ExitDataSize The size of exit data.
2233 @param ExitData Data returned when Boot image failed.
2234
2235 @retval EFI_SUCCESS Boot from the input boot option successfully.
2236 @retval EFI_NOT_FOUND If the Device Path is not found in the system
2237
2238 **/
2239 EFI_STATUS
2240 EFIAPI
2241 BdsLibBootViaBootOption (
2242 IN BDS_COMMON_OPTION *Option,
2243 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
2244 OUT UINTN *ExitDataSize,
2245 OUT CHAR16 **ExitData OPTIONAL
2246 )
2247 {
2248 EFI_STATUS Status;
2249 EFI_STATUS StatusLogo;
2250 EFI_HANDLE Handle;
2251 EFI_HANDLE ImageHandle;
2252 EFI_DEVICE_PATH_PROTOCOL *FilePath;
2253 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
2254 EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;
2255 EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
2256 LIST_ENTRY TempBootLists;
2257 EFI_BOOT_LOGO_PROTOCOL *BootLogo;
2258
2259 *ExitDataSize = 0;
2260 *ExitData = NULL;
2261
2262 //
2263 // Notes: this code can be remove after the s3 script table
2264 // hook on the event EVT_SIGNAL_READY_TO_BOOT or
2265 // EVT_SIGNAL_LEGACY_BOOT
2266 //
2267 Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save);
2268 if (!EFI_ERROR (Status)) {
2269 AcpiS3Save->S3Save (AcpiS3Save, NULL);
2270 }
2271 //
2272 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
2273 // full device path
2274 //
2275 WorkingDevicePath = NULL;
2276 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
2277 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
2278 WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (
2279 (HARDDRIVE_DEVICE_PATH *)DevicePath
2280 );
2281 if (WorkingDevicePath != NULL) {
2282 DevicePath = WorkingDevicePath;
2283 }
2284 }
2285
2286 //
2287 // Set Boot Current
2288 //
2289 if (IsBootOptionValidNVVarialbe (Option)) {
2290 //
2291 // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid.
2292 // In this case, "BootCurrent" is not created.
2293 // Only create the BootCurrent variable when it points to a valid Boot#### variable.
2294 //
2295 SetVariableAndReportStatusCodeOnError (
2296 L"BootCurrent",
2297 &gEfiGlobalVariableGuid,
2298 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2299 sizeof (UINT16),
2300 &Option->BootCurrent
2301 );
2302 }
2303
2304 //
2305 // Report Status Code to indicate ReadyToBoot event will be signalled
2306 //
2307 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
2308
2309 //
2310 // Signal the EVT_SIGNAL_READY_TO_BOOT event
2311 //
2312 EfiSignalEventReadyToBoot();
2313
2314 //
2315 // Expand USB Class or USB WWID device path node to be full device path of a USB
2316 // device in platform then load the boot file on this full device path and get the
2317 // image handle.
2318 //
2319 ImageHandle = BdsExpandUsbShortFormDevicePath (DevicePath);
2320
2321 //
2322 // Adjust the different type memory page number just before booting
2323 // and save the updated info into the variable for next boot to use
2324 //
2325 BdsSetMemoryTypeInformationVariable ();
2326
2327 //
2328 // By expanding the USB Class or WWID device path, the ImageHandle has returnned.
2329 // Here get the ImageHandle for the non USB class or WWID device path.
2330 //
2331 if (ImageHandle == NULL) {
2332 ASSERT (Option->DevicePath != NULL);
2333 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
2334 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
2335 ) {
2336 //
2337 // Check to see if we should legacy BOOT. If yes then do the legacy boot
2338 //
2339 return BdsLibDoLegacyBoot (Option);
2340 }
2341
2342 //
2343 // If the boot option point to Internal FV shell, make sure it is valid
2344 //
2345 Status = BdsLibUpdateFvFileDevicePath (&DevicePath, &gUefiShellFileGuid);
2346 if (!EFI_ERROR(Status)) {
2347 if (Option->DevicePath != NULL) {
2348 FreePool(Option->DevicePath);
2349 }
2350 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
2351 ASSERT(Option->DevicePath != NULL);
2352 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
2353 //
2354 // Update the shell boot option
2355 //
2356 InitializeListHead (&TempBootLists);
2357 BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
2358
2359 //
2360 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
2361 //
2362 FreePool (DevicePath);
2363 DevicePath = Option->DevicePath;
2364 }
2365
2366 DEBUG_CODE_BEGIN();
2367
2368 if (Option->Description == NULL) {
2369 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting from unknown device path\n"));
2370 } else {
2371 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));
2372 }
2373
2374 DEBUG_CODE_END();
2375
2376 //
2377 // Report status code for OS Loader LoadImage.
2378 //
2379 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
2380 Status = gBS->LoadImage (
2381 TRUE,
2382 gImageHandle,
2383 DevicePath,
2384 NULL,
2385 0,
2386 &ImageHandle
2387 );
2388
2389 //
2390 // If we didn't find an image directly, we need to try as if it is a removable device boot option
2391 // and load the image according to the default boot behavior for removable device.
2392 //
2393 if (EFI_ERROR (Status)) {
2394 //
2395 // check if there is a bootable removable media could be found in this device path ,
2396 // and get the bootable media handle
2397 //
2398 Handle = BdsLibGetBootableHandle(DevicePath);
2399 if (Handle != NULL) {
2400 //
2401 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
2402 // machinename is ia32, ia64, x64, ...
2403 //
2404 FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
2405 if (FilePath != NULL) {
2406 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
2407 Status = gBS->LoadImage (
2408 TRUE,
2409 gImageHandle,
2410 FilePath,
2411 NULL,
2412 0,
2413 &ImageHandle
2414 );
2415 }
2416 }
2417 }
2418 }
2419 //
2420 // Provide the image with it's load options
2421 //
2422 if ((ImageHandle == NULL) || (EFI_ERROR(Status))) {
2423 //
2424 // Report Status Code to indicate that the failure to load boot option
2425 //
2426 REPORT_STATUS_CODE (
2427 EFI_ERROR_CODE | EFI_ERROR_MINOR,
2428 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)
2429 );
2430 goto Done;
2431 }
2432
2433 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
2434 ASSERT_EFI_ERROR (Status);
2435
2436 if (Option->LoadOptionsSize != 0) {
2437 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
2438 ImageInfo->LoadOptions = Option->LoadOptions;
2439 }
2440
2441 //
2442 // Clean to NULL because the image is loaded directly from the firmwares boot manager.
2443 //
2444 ImageInfo->ParentHandle = NULL;
2445
2446 //
2447 // Before calling the image, enable the Watchdog Timer for
2448 // the 5 Minute period
2449 //
2450 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
2451
2452 //
2453 // Write boot to OS performance data for UEFI boot
2454 //
2455 PERF_CODE (
2456 BmEndOfBdsPerfCode (NULL, NULL);
2457 );
2458
2459 //
2460 // Report status code for OS Loader StartImage.
2461 //
2462 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
2463
2464 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
2465 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
2466 if (EFI_ERROR (Status)) {
2467 //
2468 // Report Status Code to indicate that boot failure
2469 //
2470 REPORT_STATUS_CODE (
2471 EFI_ERROR_CODE | EFI_ERROR_MINOR,
2472 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
2473 );
2474 }
2475
2476 //
2477 // Clear the Watchdog Timer after the image returns
2478 //
2479 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
2480
2481 Done:
2482 //
2483 // Set Logo status invalid after trying one boot option
2484 //
2485 BootLogo = NULL;
2486 StatusLogo = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
2487 if (!EFI_ERROR (StatusLogo) && (BootLogo != NULL)) {
2488 BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
2489 }
2490
2491 //
2492 // Clear Boot Current
2493 // Deleting variable with current implementation shouldn't fail.
2494 //
2495 gRT->SetVariable (
2496 L"BootCurrent",
2497 &gEfiGlobalVariableGuid,
2498 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2499 0,
2500 NULL
2501 );
2502
2503 return Status;
2504 }
2505
2506
2507 /**
2508 Expand a device path that starts with a hard drive media device path node to be a
2509 full device path that includes the full hardware path to the device. We need
2510 to do this so it can be booted. As an optimization the front match (the part point
2511 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
2512 so a connect all is not required on every boot. All successful history device path
2513 which point to partition node (the front part) will be saved.
2514
2515 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
2516 drive media device path.
2517 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
2518 cannot be found.
2519
2520 **/
2521 EFI_DEVICE_PATH_PROTOCOL *
2522 EFIAPI
2523 BdsExpandPartitionPartialDevicePathToFull (
2524 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
2525 )
2526 {
2527 EFI_STATUS Status;
2528 UINTN BlockIoHandleCount;
2529 EFI_HANDLE *BlockIoBuffer;
2530 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
2531 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
2532 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2533 UINTN Index;
2534 UINTN InstanceNum;
2535 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
2536 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
2537 UINTN CachedDevicePathSize;
2538 BOOLEAN DeviceExist;
2539 BOOLEAN NeedAdjust;
2540 EFI_DEVICE_PATH_PROTOCOL *Instance;
2541 UINTN Size;
2542
2543 FullDevicePath = NULL;
2544 //
2545 // Check if there is prestore HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
2546 // If exist, search the front path which point to partition node in the variable instants.
2547 // If fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, reconnect all and search in all system
2548 //
2549 GetVariable2 (
2550 HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
2551 &gHdBootDevicePathVariablGuid,
2552 (VOID **) &CachedDevicePath,
2553 &CachedDevicePathSize
2554 );
2555
2556 //
2557 // Delete the invalid HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
2558 //
2559 if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
2560 FreePool (CachedDevicePath);
2561 CachedDevicePath = NULL;
2562 Status = gRT->SetVariable (
2563 HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
2564 &gHdBootDevicePathVariablGuid,
2565 0,
2566 0,
2567 NULL
2568 );
2569 ASSERT_EFI_ERROR (Status);
2570 }
2571
2572 if (CachedDevicePath != NULL) {
2573 TempNewDevicePath = CachedDevicePath;
2574 DeviceExist = FALSE;
2575 NeedAdjust = FALSE;
2576 do {
2577 //
2578 // Check every instance of the variable
2579 // First, check whether the instance contain the partition node, which is needed for distinguishing multi
2580 // partial partition boot option. Second, check whether the instance could be connected.
2581 //
2582 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
2583 if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {
2584 //
2585 // Connect the device path instance, the device path point to hard drive media device path node
2586 // e.g. ACPI() /PCI()/ATA()/Partition()
2587 //
2588 Status = BdsLibConnectDevicePath (Instance);
2589 if (!EFI_ERROR (Status)) {
2590 DeviceExist = TRUE;
2591 break;
2592 }
2593 }
2594 //
2595 // Come here means the first instance is not matched
2596 //
2597 NeedAdjust = TRUE;
2598 FreePool(Instance);
2599 } while (TempNewDevicePath != NULL);
2600
2601 if (DeviceExist) {
2602 //
2603 // Find the matched device path.
2604 // Append the file path information from the boot option and return the fully expanded device path.
2605 //
2606 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
2607 FullDevicePath = AppendDevicePath (Instance, DevicePath);
2608
2609 //
2610 // Adjust the HD_BOOT_DEVICE_PATH_VARIABLE_NAME instances sequence if the matched one is not first one.
2611 //
2612 if (NeedAdjust) {
2613 //
2614 // First delete the matched instance.
2615 //
2616 TempNewDevicePath = CachedDevicePath;
2617 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );
2618 FreePool (TempNewDevicePath);
2619
2620 //
2621 // Second, append the remaining path after the matched instance
2622 //
2623 TempNewDevicePath = CachedDevicePath;
2624 CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );
2625 FreePool (TempNewDevicePath);
2626 //
2627 // Save the matching Device Path so we don't need to do a connect all next time
2628 // Failure to set the variable only impacts the performance when next time expanding the short-form device path.
2629 //
2630 Status = gRT->SetVariable (
2631 HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
2632 &gHdBootDevicePathVariablGuid,
2633 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
2634 GetDevicePathSize (CachedDevicePath),
2635 CachedDevicePath
2636 );
2637 }
2638
2639 FreePool (Instance);
2640 FreePool (CachedDevicePath);
2641 return FullDevicePath;
2642 }
2643 }
2644
2645 //
2646 // If we get here we fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, and now we need
2647 // to search all devices in the system for a matched partition
2648 //
2649 BdsLibConnectAllDriversToAllControllers ();
2650 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
2651 if (EFI_ERROR (Status) || BlockIoHandleCount == 0 || BlockIoBuffer == NULL) {
2652 //
2653 // If there was an error or there are no device handles that support
2654 // the BLOCK_IO Protocol, then return.
2655 //
2656 return NULL;
2657 }
2658 //
2659 // Loop through all the device handles that support the BLOCK_IO Protocol
2660 //
2661 for (Index = 0; Index < BlockIoHandleCount; Index++) {
2662
2663 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
2664 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
2665 continue;
2666 }
2667
2668 if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {
2669 //
2670 // Find the matched partition device path
2671 //
2672 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
2673 FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
2674
2675 //
2676 // Save the matched partition device path in HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
2677 //
2678 if (CachedDevicePath != NULL) {
2679 //
2680 // Save the matched partition device path as first instance of HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
2681 //
2682 if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
2683 TempNewDevicePath = CachedDevicePath;
2684 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
2685 FreePool(TempNewDevicePath);
2686 }
2687
2688 if (CachedDevicePath != NULL) {
2689 TempNewDevicePath = CachedDevicePath;
2690 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
2691 FreePool(TempNewDevicePath);
2692 } else {
2693 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
2694 }
2695
2696 //
2697 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
2698 // If the user try to boot many OS in different HDs or partitions, in theory,
2699 // the HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable maybe become larger and larger.
2700 //
2701 InstanceNum = 0;
2702 ASSERT (CachedDevicePath != NULL);
2703 TempNewDevicePath = CachedDevicePath;
2704 while (!IsDevicePathEnd (TempNewDevicePath)) {
2705 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
2706 //
2707 // Parse one instance
2708 //
2709 while (!IsDevicePathEndType (TempNewDevicePath)) {
2710 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
2711 }
2712 InstanceNum++;
2713 //
2714 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
2715 //
2716 if (InstanceNum >= 12) {
2717 SetDevicePathEndNode (TempNewDevicePath);
2718 break;
2719 }
2720 }
2721 } else {
2722 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
2723 }
2724
2725 //
2726 // Save the matching Device Path so we don't need to do a connect all next time
2727 // Failure to set the variable only impacts the performance when next time expanding the short-form device path.
2728 //
2729 Status = gRT->SetVariable (
2730 HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
2731 &gHdBootDevicePathVariablGuid,
2732 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
2733 GetDevicePathSize (CachedDevicePath),
2734 CachedDevicePath
2735 );
2736
2737 break;
2738 }
2739 }
2740
2741 if (CachedDevicePath != NULL) {
2742 FreePool (CachedDevicePath);
2743 }
2744 if (BlockIoBuffer != NULL) {
2745 FreePool (BlockIoBuffer);
2746 }
2747 return FullDevicePath;
2748 }
2749
2750 /**
2751 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
2752 instances, has the same partition node with HardDriveDevicePath device path
2753
2754 @param BlockIoDevicePath Multi device path instances which need to check
2755 @param HardDriveDevicePath A device path which starts with a hard drive media
2756 device path.
2757
2758 @retval TRUE There is a matched device path instance.
2759 @retval FALSE There is no matched device path instance.
2760
2761 **/
2762 BOOLEAN
2763 EFIAPI
2764 MatchPartitionDevicePathNode (
2765 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
2766 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
2767 )
2768 {
2769 HARDDRIVE_DEVICE_PATH *TmpHdPath;
2770 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2771 BOOLEAN Match;
2772 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;
2773
2774 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
2775 return FALSE;
2776 }
2777
2778 //
2779 // Make PreviousDevicePath == the device path node before the end node
2780 //
2781 DevicePath = BlockIoDevicePath;
2782 BlockIoHdDevicePathNode = NULL;
2783
2784 //
2785 // find the partition device path node
2786 //
2787 while (!IsDevicePathEnd (DevicePath)) {
2788 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
2789 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
2790 ) {
2791 BlockIoHdDevicePathNode = DevicePath;
2792 break;
2793 }
2794
2795 DevicePath = NextDevicePathNode (DevicePath);
2796 }
2797
2798 if (BlockIoHdDevicePathNode == NULL) {
2799 return FALSE;
2800 }
2801 //
2802 // See if the harddrive device path in blockio matches the orig Hard Drive Node
2803 //
2804 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
2805 Match = FALSE;
2806
2807 //
2808 // Check for the match
2809 //
2810 if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&
2811 (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {
2812 switch (TmpHdPath->SignatureType) {
2813 case SIGNATURE_TYPE_GUID:
2814 Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature);
2815 break;
2816 case SIGNATURE_TYPE_MBR:
2817 Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));
2818 break;
2819 default:
2820 Match = FALSE;
2821 break;
2822 }
2823 }
2824
2825 return Match;
2826 }
2827
2828 /**
2829 Delete the boot option associated with the handle passed in.
2830
2831 @param Handle The handle which present the device path to create
2832 boot option
2833
2834 @retval EFI_SUCCESS Delete the boot option success
2835 @retval EFI_NOT_FOUND If the Device Path is not found in the system
2836 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
2837 @retval Other Error return value from SetVariable()
2838
2839 **/
2840 EFI_STATUS
2841 BdsLibDeleteOptionFromHandle (
2842 IN EFI_HANDLE Handle
2843 )
2844 {
2845 UINT16 *BootOrder;
2846 UINT8 *BootOptionVar;
2847 UINTN BootOrderSize;
2848 UINTN BootOptionSize;
2849 EFI_STATUS Status;
2850 UINTN Index;
2851 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
2852 UINTN DevicePathSize;
2853 UINTN OptionDevicePathSize;
2854 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2855 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
2856 UINT8 *TempPtr;
2857
2858 Status = EFI_SUCCESS;
2859 BootOrder = NULL;
2860 BootOrderSize = 0;
2861
2862 //
2863 // Check "BootOrder" variable, if no, means there is no any boot order.
2864 //
2865 BootOrder = BdsLibGetVariableAndSize (
2866 L"BootOrder",
2867 &gEfiGlobalVariableGuid,
2868 &BootOrderSize
2869 );
2870 if (BootOrder == NULL) {
2871 return EFI_NOT_FOUND;
2872 }
2873
2874 //
2875 // Convert device handle to device path protocol instance
2876 //
2877 DevicePath = DevicePathFromHandle (Handle);
2878 if (DevicePath == NULL) {
2879 return EFI_NOT_FOUND;
2880 }
2881 DevicePathSize = GetDevicePathSize (DevicePath);
2882
2883 //
2884 // Loop all boot order variable and find the matching device path
2885 //
2886 Index = 0;
2887 while (Index < BootOrderSize / sizeof (UINT16)) {
2888 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
2889 BootOptionVar = BdsLibGetVariableAndSize (
2890 BootOption,
2891 &gEfiGlobalVariableGuid,
2892 &BootOptionSize
2893 );
2894
2895 if (BootOptionVar == NULL) {
2896 FreePool (BootOrder);
2897 return EFI_OUT_OF_RESOURCES;
2898 }
2899
2900 if (!ValidateOption(BootOptionVar, BootOptionSize)) {
2901 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
2902 FreePool (BootOptionVar);
2903 Index++;
2904 continue;
2905 }
2906
2907 TempPtr = BootOptionVar;
2908 TempPtr += sizeof (UINT32) + sizeof (UINT16);
2909 TempPtr += StrSize ((CHAR16 *) TempPtr);
2910 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
2911 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
2912
2913 //
2914 // Check whether the device path match
2915 //
2916 if ((OptionDevicePathSize == DevicePathSize) &&
2917 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
2918 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
2919 FreePool (BootOptionVar);
2920 break;
2921 }
2922
2923 FreePool (BootOptionVar);
2924 Index++;
2925 }
2926
2927 //
2928 // Adjust number of boot option for "BootOrder" variable.
2929 //
2930 Status = gRT->SetVariable (
2931 L"BootOrder",
2932 &gEfiGlobalVariableGuid,
2933 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
2934 BootOrderSize,
2935 BootOrder
2936 );
2937 //
2938 // Shrinking variable with existing variable implementation shouldn't fail.
2939 //
2940 ASSERT_EFI_ERROR (Status);
2941
2942 FreePool (BootOrder);
2943
2944 return Status;
2945 }
2946
2947
2948 /**
2949 Delete all invalid EFI boot options.
2950
2951 @retval EFI_SUCCESS Delete all invalid boot option success
2952 @retval EFI_NOT_FOUND Variable "BootOrder" is not found
2953 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
2954 @retval Other Error return value from SetVariable()
2955
2956 **/
2957 EFI_STATUS
2958 BdsDeleteAllInvalidEfiBootOption (
2959 VOID
2960 )
2961 {
2962 UINT16 *BootOrder;
2963 UINT8 *BootOptionVar;
2964 UINTN BootOrderSize;
2965 UINTN BootOptionSize;
2966 EFI_STATUS Status;
2967 UINTN Index;
2968 UINTN Index2;
2969 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
2970 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
2971 UINT8 *TempPtr;
2972 CHAR16 *Description;
2973 BOOLEAN Corrupted;
2974
2975 Status = EFI_SUCCESS;
2976 BootOrder = NULL;
2977 Description = NULL;
2978 OptionDevicePath = NULL;
2979 BootOrderSize = 0;
2980 Corrupted = FALSE;
2981
2982 //
2983 // Check "BootOrder" variable firstly, this variable hold the number of boot options
2984 //
2985 BootOrder = BdsLibGetVariableAndSize (
2986 L"BootOrder",
2987 &gEfiGlobalVariableGuid,
2988 &BootOrderSize
2989 );
2990 if (NULL == BootOrder) {
2991 return EFI_NOT_FOUND;
2992 }
2993
2994 Index = 0;
2995 while (Index < BootOrderSize / sizeof (UINT16)) {
2996 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
2997 BootOptionVar = BdsLibGetVariableAndSize (
2998 BootOption,
2999 &gEfiGlobalVariableGuid,
3000 &BootOptionSize
3001 );
3002 if (NULL == BootOptionVar) {
3003 FreePool (BootOrder);
3004 return EFI_OUT_OF_RESOURCES;
3005 }
3006
3007 if (!ValidateOption(BootOptionVar, BootOptionSize)) {
3008 Corrupted = TRUE;
3009 } else {
3010 TempPtr = BootOptionVar;
3011 TempPtr += sizeof (UINT32) + sizeof (UINT16);
3012 Description = (CHAR16 *) TempPtr;
3013 TempPtr += StrSize ((CHAR16 *) TempPtr);
3014 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
3015
3016 //
3017 // Skip legacy boot option (BBS boot device)
3018 //
3019 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
3020 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
3021 FreePool (BootOptionVar);
3022 Index++;
3023 continue;
3024 }
3025 }
3026
3027 if (Corrupted || !BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) {
3028 //
3029 // Delete this invalid boot option "Boot####"
3030 //
3031 Status = gRT->SetVariable (
3032 BootOption,
3033 &gEfiGlobalVariableGuid,
3034 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
3035 0,
3036 NULL
3037 );
3038 //
3039 // Deleting variable with current variable implementation shouldn't fail.
3040 //
3041 ASSERT_EFI_ERROR (Status);
3042 //
3043 // Mark this boot option in boot order as deleted
3044 //
3045 BootOrder[Index] = 0xffff;
3046 Corrupted = FALSE;
3047 }
3048
3049 FreePool (BootOptionVar);
3050 Index++;
3051 }
3052
3053 //
3054 // Adjust boot order array
3055 //
3056 Index2 = 0;
3057 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
3058 if (BootOrder[Index] != 0xffff) {
3059 BootOrder[Index2] = BootOrder[Index];
3060 Index2 ++;
3061 }
3062 }
3063 Status = gRT->SetVariable (
3064 L"BootOrder",
3065 &gEfiGlobalVariableGuid,
3066 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
3067 Index2 * sizeof (UINT16),
3068 BootOrder
3069 );
3070 //
3071 // Shrinking variable with current variable implementation shouldn't fail.
3072 //
3073 ASSERT_EFI_ERROR (Status);
3074
3075 FreePool (BootOrder);
3076
3077 return Status;
3078 }
3079
3080
3081 /**
3082 For EFI boot option, BDS separate them as six types:
3083 1. Network - The boot option points to the SimpleNetworkProtocol device.
3084 Bds will try to automatically create this type boot option when enumerate.
3085 2. Shell - The boot option points to internal flash shell.
3086 Bds will try to automatically create this type boot option when enumerate.
3087 3. Removable BlockIo - The boot option only points to the removable media
3088 device, like USB flash disk, DVD, Floppy etc.
3089 These device should contain a *removable* blockIo
3090 protocol in their device handle.
3091 Bds will try to automatically create this type boot option
3092 when enumerate.
3093 4. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
3094 like HardDisk.
3095 These device should contain a *fixed* blockIo
3096 protocol in their device handle.
3097 BDS will skip fixed blockIo devices, and NOT
3098 automatically create boot option for them. But BDS
3099 will help to delete those fixed blockIo boot option,
3100 whose description rule conflict with other auto-created
3101 boot options.
3102 5. Non-BlockIo Simplefile - The boot option points to a device whose handle
3103 has SimpleFileSystem Protocol, but has no blockio
3104 protocol. These devices do not offer blockIo
3105 protocol, but BDS still can get the
3106 \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem
3107 Protocol.
3108 6. File - The boot option points to a file. These boot options are usually
3109 created by user manually or OS loader. BDS will not delete or modify
3110 these boot options.
3111
3112 This function will enumerate all possible boot device in the system, and
3113 automatically create boot options for Network, Shell, Removable BlockIo,
3114 and Non-BlockIo Simplefile devices.
3115 It will only execute once of every boot.
3116
3117 @param BdsBootOptionList The header of the link list which indexed all
3118 current boot options
3119
3120 @retval EFI_SUCCESS Finished all the boot device enumerate and create
3121 the boot option base on that boot device
3122
3123 @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create the boot option list
3124 **/
3125 EFI_STATUS
3126 EFIAPI
3127 BdsLibEnumerateAllBootOption (
3128 IN OUT LIST_ENTRY *BdsBootOptionList
3129 )
3130 {
3131 EFI_STATUS Status;
3132 UINT16 FloppyNumber;
3133 UINT16 HarddriveNumber;
3134 UINT16 CdromNumber;
3135 UINT16 UsbNumber;
3136 UINT16 MiscNumber;
3137 UINT16 ScsiNumber;
3138 UINT16 NonBlockNumber;
3139 UINTN NumberBlockIoHandles;
3140 EFI_HANDLE *BlockIoHandles;
3141 EFI_BLOCK_IO_PROTOCOL *BlkIo;
3142 BOOLEAN Removable[2];
3143 UINTN RemovableIndex;
3144 UINTN Index;
3145 UINTN NumOfLoadFileHandles;
3146 EFI_HANDLE *LoadFileHandles;
3147 UINTN FvHandleCount;
3148 EFI_HANDLE *FvHandleBuffer;
3149 EFI_FV_FILETYPE Type;
3150 UINTN Size;
3151 EFI_FV_FILE_ATTRIBUTES Attributes;
3152 UINT32 AuthenticationStatus;
3153 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
3154 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
3155 UINTN DevicePathType;
3156 CHAR16 Buffer[40];
3157 EFI_HANDLE *FileSystemHandles;
3158 UINTN NumberFileSystemHandles;
3159 BOOLEAN NeedDelete;
3160 EFI_IMAGE_DOS_HEADER DosHeader;
3161 CHAR8 *PlatLang;
3162 CHAR8 *LastLang;
3163 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
3164 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
3165 CHAR16 *MacStr;
3166 CHAR16 *IPverStr;
3167 EFI_HANDLE *NetworkHandles;
3168 UINTN BufferSize;
3169
3170 FloppyNumber = 0;
3171 HarddriveNumber = 0;
3172 CdromNumber = 0;
3173 UsbNumber = 0;
3174 MiscNumber = 0;
3175 ScsiNumber = 0;
3176 PlatLang = NULL;
3177 LastLang = NULL;
3178 ZeroMem (Buffer, sizeof (Buffer));
3179
3180 //
3181 // If the boot device enumerate happened, just get the boot
3182 // device from the boot order variable
3183 //
3184 if (mEnumBootDevice) {
3185 GetVariable2 (LAST_ENUM_LANGUAGE_VARIABLE_NAME, &gLastEnumLangGuid, (VOID**)&LastLang, NULL);
3186 GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatLang, NULL);
3187 ASSERT (PlatLang != NULL);
3188 if ((LastLang != NULL) && (AsciiStrCmp (LastLang, PlatLang) == 0)) {
3189 Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
3190 FreePool (LastLang);
3191 FreePool (PlatLang);
3192 return Status;
3193 } else {
3194 Status = gRT->SetVariable (
3195 LAST_ENUM_LANGUAGE_VARIABLE_NAME,
3196 &gLastEnumLangGuid,
3197 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
3198 AsciiStrSize (PlatLang),
3199 PlatLang
3200 );
3201 //
3202 // Failure to set the variable only impacts the performance next time enumerating the boot options.
3203 //
3204
3205 if (LastLang != NULL) {
3206 FreePool (LastLang);
3207 }
3208 FreePool (PlatLang);
3209 }
3210 }
3211
3212 //
3213 // Notes: this dirty code is to get the legacy boot option from the
3214 // BBS table and create to variable as the EFI boot option, it should
3215 // be removed after the CSM can provide legacy boot option directly
3216 //
3217 REFRESH_LEGACY_BOOT_OPTIONS;
3218
3219 //
3220 // Delete invalid boot option
3221 //
3222 BdsDeleteAllInvalidEfiBootOption ();
3223
3224 //
3225 // Parse removable media followed by fixed media.
3226 // The Removable[] array is used by the for-loop below to create removable media boot options
3227 // at first, and then to create fixed media boot options.
3228 //
3229 Removable[0] = FALSE;
3230 Removable[1] = TRUE;
3231
3232 gBS->LocateHandleBuffer (
3233 ByProtocol,
3234 &gEfiBlockIoProtocolGuid,
3235 NULL,
3236 &NumberBlockIoHandles,
3237 &BlockIoHandles
3238 );
3239
3240 for (RemovableIndex = 0; RemovableIndex < 2; RemovableIndex++) {
3241 for (Index = 0; Index < NumberBlockIoHandles; Index++) {
3242 Status = gBS->HandleProtocol (
3243 BlockIoHandles[Index],
3244 &gEfiBlockIoProtocolGuid,
3245 (VOID **) &BlkIo
3246 );
3247 //
3248 // skip the logical partition
3249 //
3250 if (EFI_ERROR (Status) || BlkIo->Media->LogicalPartition) {
3251 continue;
3252 }
3253
3254 //
3255 // firstly fixed block io then the removable block io
3256 //
3257 if (BlkIo->Media->RemovableMedia == Removable[RemovableIndex]) {
3258 continue;
3259 }
3260 DevicePath = DevicePathFromHandle (BlockIoHandles[Index]);
3261 DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);
3262
3263 switch (DevicePathType) {
3264 case BDS_EFI_ACPI_FLOPPY_BOOT:
3265 if (FloppyNumber != 0) {
3266 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)), FloppyNumber);
3267 } else {
3268 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)));
3269 }
3270 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
3271 FloppyNumber++;
3272 break;
3273
3274 //
3275 // Assume a removable SATA device should be the DVD/CD device, a fixed SATA device should be the Hard Drive device.
3276 //
3277 case BDS_EFI_MESSAGE_ATAPI_BOOT:
3278 case BDS_EFI_MESSAGE_SATA_BOOT:
3279 if (BlkIo->Media->RemovableMedia) {
3280 if (CdromNumber != 0) {
3281 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)), CdromNumber);
3282 } else {
3283 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)));
3284 }
3285 CdromNumber++;
3286 } else {
3287 if (HarddriveNumber != 0) {
3288 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)), HarddriveNumber);
3289 } else {
3290 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)));
3291 }
3292 HarddriveNumber++;
3293 }
3294 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Buffer: %S\n", Buffer));
3295 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
3296 break;
3297
3298 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
3299 if (UsbNumber != 0) {
3300 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)), UsbNumber);
3301 } else {
3302 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)));
3303 }
3304 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
3305 UsbNumber++;
3306 break;
3307
3308 case BDS_EFI_MESSAGE_SCSI_BOOT:
3309 if (ScsiNumber != 0) {
3310 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)), ScsiNumber);
3311 } else {
3312 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)));
3313 }
3314 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
3315 ScsiNumber++;
3316 break;
3317
3318 case BDS_EFI_MESSAGE_MISC_BOOT:
3319 default:
3320 if (MiscNumber != 0) {
3321 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)), MiscNumber);
3322 } else {
3323 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)));
3324 }
3325 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
3326 MiscNumber++;
3327 break;
3328 }
3329 }
3330 }
3331
3332 if (NumberBlockIoHandles != 0) {
3333 FreePool (BlockIoHandles);
3334 }
3335
3336 //
3337 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
3338 //
3339 NonBlockNumber = 0;
3340 gBS->LocateHandleBuffer (
3341 ByProtocol,
3342 &gEfiSimpleFileSystemProtocolGuid,
3343 NULL,
3344 &NumberFileSystemHandles,
3345 &FileSystemHandles
3346 );
3347 for (Index = 0; Index < NumberFileSystemHandles; Index++) {
3348 Status = gBS->HandleProtocol (
3349 FileSystemHandles[Index],
3350 &gEfiBlockIoProtocolGuid,
3351 (VOID **) &BlkIo
3352 );
3353 if (!EFI_ERROR (Status)) {
3354 //
3355 // Skip if the file system handle supports a BlkIo protocol,
3356 //
3357 continue;
3358 }
3359
3360 //
3361 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
3362 // machinename is ia32, ia64, x64, ...
3363 //
3364 Hdr.Union = &HdrData;
3365 NeedDelete = TRUE;
3366 Status = BdsLibGetImageHeader (
3367 FileSystemHandles[Index],
3368 EFI_REMOVABLE_MEDIA_FILE_NAME,
3369 &DosHeader,
3370 Hdr
3371 );
3372 if (!EFI_ERROR (Status) &&
3373 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
3374 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
3375 NeedDelete = FALSE;
3376 }
3377
3378 if (NeedDelete) {
3379 //
3380 // No such file or the file is not a EFI application, delete this boot option
3381 //
3382 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
3383 } else {
3384 if (NonBlockNumber != 0) {
3385 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)), NonBlockNumber);
3386 } else {
3387 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)));
3388 }
3389 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);
3390 NonBlockNumber++;
3391 }
3392 }
3393
3394 if (NumberFileSystemHandles != 0) {
3395 FreePool (FileSystemHandles);
3396 }
3397
3398 //
3399 // Parse Network Boot Device
3400 //
3401 NumOfLoadFileHandles = 0;
3402 //
3403 // Search Load File protocol for PXE boot option.
3404 //
3405 gBS->LocateHandleBuffer (
3406 ByProtocol,
3407 &gEfiLoadFileProtocolGuid,
3408 NULL,
3409 &NumOfLoadFileHandles,
3410 &LoadFileHandles
3411 );
3412
3413 for (Index = 0; Index < NumOfLoadFileHandles; Index++) {
3414
3415 //
3416 //Locate EFI_DEVICE_PATH_PROTOCOL to dynamically get IPv4/IPv6 protocol information.
3417 //
3418
3419 Status = gBS->HandleProtocol (
3420 LoadFileHandles[Index],
3421 &gEfiDevicePathProtocolGuid,
3422 (VOID **) &DevicePath
3423 );
3424
3425 ASSERT_EFI_ERROR (Status);
3426
3427 while (!IsDevicePathEnd (DevicePath)) {
3428 if ((DevicePath->Type == MESSAGING_DEVICE_PATH) &&
3429 (DevicePath->SubType == MSG_IPv4_DP)) {
3430
3431 //
3432 //Get handle infomation
3433 //
3434 BufferSize = 0;
3435 NetworkHandles = NULL;
3436 Status = gBS->LocateHandle (
3437 ByProtocol,
3438 &gEfiSimpleNetworkProtocolGuid,
3439 NULL,
3440 &BufferSize,
3441 NetworkHandles
3442 );
3443
3444 if (Status == EFI_BUFFER_TOO_SMALL) {
3445 NetworkHandles = AllocateZeroPool(BufferSize);
3446 if (NetworkHandles == NULL) {
3447 return (EFI_OUT_OF_RESOURCES);
3448 }
3449 Status = gBS->LocateHandle(
3450 ByProtocol,
3451 &gEfiSimpleNetworkProtocolGuid,
3452 NULL,
3453 &BufferSize,
3454 NetworkHandles
3455 );
3456 }
3457
3458 //
3459 //Get the MAC string
3460 //
3461 Status = NetLibGetMacString (
3462 *NetworkHandles,
3463 NULL,
3464 &MacStr
3465 );
3466 if (EFI_ERROR (Status)) {
3467 return Status;
3468 }
3469 IPverStr = L" IPv4";
3470 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s%s%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)),MacStr,IPverStr);
3471 break;
3472 }
3473 if((DevicePath->Type == MESSAGING_DEVICE_PATH) &&
3474 (DevicePath->SubType == MSG_IPv6_DP)) {
3475
3476 //
3477 //Get handle infomation
3478 //
3479 BufferSize = 0;
3480 NetworkHandles = NULL;
3481 Status = gBS->LocateHandle (
3482 ByProtocol,
3483 &gEfiSimpleNetworkProtocolGuid,
3484 NULL,
3485 &BufferSize,
3486 NetworkHandles
3487 );
3488
3489 if (Status == EFI_BUFFER_TOO_SMALL) {
3490 NetworkHandles = AllocateZeroPool(BufferSize);
3491 if (NetworkHandles == NULL) {
3492 return (EFI_OUT_OF_RESOURCES);
3493 }
3494 Status = gBS->LocateHandle(
3495 ByProtocol,
3496 &gEfiSimpleNetworkProtocolGuid,
3497 NULL,
3498 &BufferSize,
3499 NetworkHandles
3500 );
3501 }
3502
3503 //
3504 //Get the MAC string
3505 //
3506 Status = NetLibGetMacString (
3507 *NetworkHandles,
3508 NULL,
3509 &MacStr
3510 );
3511 if (EFI_ERROR (Status)) {
3512 return Status;
3513 }
3514 IPverStr = L" IPv6";
3515 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s%s%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)),MacStr,IPverStr);
3516 break;
3517 }
3518 DevicePath = NextDevicePathNode (DevicePath);
3519 }
3520
3521 BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList, Buffer);
3522 }
3523
3524 if (NumOfLoadFileHandles != 0) {
3525 FreePool (LoadFileHandles);
3526 }
3527
3528 //
3529 // Check if we have on flash shell
3530 //
3531 gBS->LocateHandleBuffer (
3532 ByProtocol,
3533 &gEfiFirmwareVolume2ProtocolGuid,
3534 NULL,
3535 &FvHandleCount,
3536 &FvHandleBuffer
3537 );
3538 for (Index = 0; Index < FvHandleCount; Index++) {
3539 gBS->HandleProtocol (
3540 FvHandleBuffer[Index],
3541 &gEfiFirmwareVolume2ProtocolGuid,
3542 (VOID **) &Fv
3543 );
3544
3545 Status = Fv->ReadFile (
3546 Fv,
3547 &gUefiShellFileGuid,
3548 NULL,
3549 &Size,
3550 &Type,
3551 &Attributes,
3552 &AuthenticationStatus
3553 );
3554 if (EFI_ERROR (Status)) {
3555 //
3556 // Skip if no shell file in the FV
3557 //
3558 continue;
3559 }
3560 //
3561 // Build the shell boot option
3562 //
3563 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
3564 }
3565
3566 if (FvHandleCount != 0) {
3567 FreePool (FvHandleBuffer);
3568 }
3569 //
3570 // Make sure every boot only have one time
3571 // boot device enumerate
3572 //
3573 Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
3574 mEnumBootDevice = TRUE;
3575
3576 return Status;
3577 }
3578
3579 /**
3580 Build the boot option with the handle parsed in
3581
3582 @param Handle The handle which present the device path to create
3583 boot option
3584 @param BdsBootOptionList The header of the link list which indexed all
3585 current boot options
3586 @param String The description of the boot option.
3587
3588 **/
3589 VOID
3590 EFIAPI
3591 BdsLibBuildOptionFromHandle (
3592 IN EFI_HANDLE Handle,
3593 IN LIST_ENTRY *BdsBootOptionList,
3594 IN CHAR16 *String
3595 )
3596 {
3597 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
3598
3599 DevicePath = DevicePathFromHandle (Handle);
3600
3601 //
3602 // Create and register new boot option
3603 //
3604 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");
3605 }
3606
3607
3608 /**
3609 Build the on flash shell boot option with the handle parsed in.
3610
3611 @param Handle The handle which present the device path to create
3612 on flash shell boot option
3613 @param BdsBootOptionList The header of the link list which indexed all
3614 current boot options
3615
3616 **/
3617 VOID
3618 EFIAPI
3619 BdsLibBuildOptionFromShell (
3620 IN EFI_HANDLE Handle,
3621 IN OUT LIST_ENTRY *BdsBootOptionList
3622 )
3623 {
3624 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
3625 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
3626
3627 DevicePath = DevicePathFromHandle (Handle);
3628
3629 //
3630 // Build the shell device path
3631 //
3632 EfiInitializeFwVolDevicepathNode (&ShellNode, &gUefiShellFileGuid);
3633
3634 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
3635
3636 //
3637 // Create and register the shell boot option
3638 //
3639 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");
3640
3641 }
3642
3643 /**
3644 Boot from the UEFI spec defined "BootNext" variable.
3645
3646 **/
3647 VOID
3648 EFIAPI
3649 BdsLibBootNext (
3650 VOID
3651 )
3652 {
3653 EFI_STATUS Status;
3654 UINT16 *BootNext;
3655 UINTN BootNextSize;
3656 CHAR16 Buffer[20];
3657 BDS_COMMON_OPTION *BootOption;
3658 LIST_ENTRY TempList;
3659 UINTN ExitDataSize;
3660 CHAR16 *ExitData;
3661
3662 //
3663 // Init the boot option name buffer and temp link list
3664 //
3665 InitializeListHead (&TempList);
3666 ZeroMem (Buffer, sizeof (Buffer));
3667
3668 BootNext = BdsLibGetVariableAndSize (
3669 L"BootNext",
3670 &gEfiGlobalVariableGuid,
3671 &BootNextSize
3672 );
3673
3674 //
3675 // Clear the boot next variable first
3676 //
3677 if (BootNext != NULL) {
3678 Status = gRT->SetVariable (
3679 L"BootNext",
3680 &gEfiGlobalVariableGuid,
3681 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
3682 0,
3683 NULL
3684 );
3685 //
3686 // Deleting variable with current variable implementation shouldn't fail.
3687 //
3688 ASSERT_EFI_ERROR (Status);
3689
3690 //
3691 // Start to build the boot option and try to boot
3692 //
3693 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
3694 BootOption = BdsLibVariableToOption (&TempList, Buffer);
3695 ASSERT (BootOption != NULL);
3696 BdsLibConnectDevicePath (BootOption->DevicePath);
3697 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
3698 FreePool(BootOption);
3699 FreePool(BootNext);
3700 }
3701
3702 }
3703
3704 /**
3705 Return the bootable media handle.
3706 First, check the device is connected
3707 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
3708 Third, detect the the default boot file in the Media, and return the removable Media handle.
3709
3710 @param DevicePath Device Path to a bootable device
3711
3712 @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
3713
3714 **/
3715 EFI_HANDLE
3716 EFIAPI
3717 BdsLibGetBootableHandle (
3718 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
3719 )
3720 {
3721 EFI_STATUS Status;
3722 EFI_TPL OldTpl;
3723 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
3724 EFI_DEVICE_PATH_PROTOCOL *DupDevicePath;
3725 EFI_HANDLE Handle;
3726 EFI_BLOCK_IO_PROTOCOL *BlockIo;
3727 VOID *Buffer;
3728 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
3729 UINTN Size;
3730 UINTN TempSize;
3731 EFI_HANDLE ReturnHandle;
3732 EFI_HANDLE *SimpleFileSystemHandles;
3733
3734 UINTN NumberSimpleFileSystemHandles;
3735 UINTN Index;
3736 EFI_IMAGE_DOS_HEADER DosHeader;
3737 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
3738 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
3739
3740 UpdatedDevicePath = DevicePath;
3741
3742 //
3743 // Enter to critical section to protect the acquired BlockIo instance
3744 // from getting released due to the USB mass storage hotplug event
3745 //
3746 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
3747
3748 //
3749 // Check whether the device is connected
3750 //
3751 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);
3752 if (EFI_ERROR (Status)) {
3753 //
3754 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
3755 //
3756 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);
3757 if (EFI_ERROR (Status)) {
3758 //
3759 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
3760 //
3761 UpdatedDevicePath = DevicePath;
3762 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
3763 gBS->ConnectController (Handle, NULL, NULL, TRUE);
3764 }
3765 } else {
3766 //
3767 // For removable device boot option, its contained device path only point to the removable device handle,
3768 // should make sure all its children handles (its child partion or media handles) are created and connected.
3769 //
3770 gBS->ConnectController (Handle, NULL, NULL, TRUE);
3771 //
3772 // Get BlockIo protocol and check removable attribute
3773 //
3774 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
3775 ASSERT_EFI_ERROR (Status);
3776
3777 //
3778 // Issue a dummy read to the device to check for media change.
3779 // When the removable media is changed, any Block IO read/write will
3780 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
3781 // returned. After the Block IO protocol is reinstalled, subsequent
3782 // Block IO read/write will success.
3783 //
3784 Buffer = AllocatePool (BlockIo->Media->BlockSize);
3785 if (Buffer != NULL) {
3786 BlockIo->ReadBlocks (
3787 BlockIo,
3788 BlockIo->Media->MediaId,
3789 0,
3790 BlockIo->Media->BlockSize,
3791 Buffer
3792 );
3793 FreePool(Buffer);
3794 }
3795 }
3796
3797 //
3798 // Detect the the default boot file from removable Media
3799 //
3800
3801 //
3802 // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus
3803 // Try to locate the USB node device path first, if fail then use its previous PCI node to search
3804 //
3805 DupDevicePath = DuplicateDevicePath (DevicePath);
3806 ASSERT (DupDevicePath != NULL);
3807
3808 UpdatedDevicePath = DupDevicePath;
3809 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
3810 //
3811 // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node
3812 // Acpi()/Pci()/Usb() --> Acpi()/Pci()
3813 //
3814 if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&
3815 (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {
3816 //
3817 // Remove the usb node, let the device path only point to PCI node
3818 //
3819 SetDevicePathEndNode (UpdatedDevicePath);
3820 UpdatedDevicePath = DupDevicePath;
3821 } else {
3822 UpdatedDevicePath = DevicePath;
3823 }
3824
3825 //
3826 // Get the device path size of boot option
3827 //
3828 Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
3829 ReturnHandle = NULL;
3830 gBS->LocateHandleBuffer (
3831 ByProtocol,
3832 &gEfiSimpleFileSystemProtocolGuid,
3833 NULL,
3834 &NumberSimpleFileSystemHandles,
3835 &SimpleFileSystemHandles
3836 );
3837 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
3838 //
3839 // Get the device path size of SimpleFileSystem handle
3840 //
3841 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
3842 TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
3843 //
3844 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
3845 //
3846 if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {
3847 //
3848 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
3849 // machinename is ia32, ia64, x64, ...
3850 //
3851 Hdr.Union = &HdrData;
3852 Status = BdsLibGetImageHeader (
3853 SimpleFileSystemHandles[Index],
3854 EFI_REMOVABLE_MEDIA_FILE_NAME,
3855 &DosHeader,
3856 Hdr
3857 );
3858 if (!EFI_ERROR (Status) &&
3859 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
3860 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
3861 ReturnHandle = SimpleFileSystemHandles[Index];
3862 break;
3863 }
3864 }
3865 }
3866
3867 FreePool(DupDevicePath);
3868
3869 if (SimpleFileSystemHandles != NULL) {
3870 FreePool(SimpleFileSystemHandles);
3871 }
3872
3873 gBS->RestoreTPL (OldTpl);
3874
3875 return ReturnHandle;
3876 }
3877
3878 /**
3879 Check to see if the network cable is plugged in. If the DevicePath is not
3880 connected it will be connected.
3881
3882 @param DevicePath Device Path to check
3883
3884 @retval TRUE DevicePath points to an Network that is connected
3885 @retval FALSE DevicePath does not point to a bootable network
3886
3887 **/
3888 BOOLEAN
3889 BdsLibNetworkBootWithMediaPresent (
3890 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
3891 )
3892 {
3893 EFI_STATUS Status;
3894 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
3895 EFI_HANDLE Handle;
3896 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
3897 BOOLEAN MediaPresent;
3898 UINT32 InterruptStatus;
3899
3900 MediaPresent = FALSE;
3901
3902 UpdatedDevicePath = DevicePath;
3903 //
3904 // Locate Load File Protocol for PXE boot option first
3905 //
3906 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);
3907 if (EFI_ERROR (Status)) {
3908 //
3909 // Device not present so see if we need to connect it
3910 //
3911 Status = BdsLibConnectDevicePath (DevicePath);
3912 if (!EFI_ERROR (Status)) {
3913 //
3914 // This one should work after we did the connect
3915 //
3916 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);
3917 }
3918 }
3919
3920 if (!EFI_ERROR (Status)) {
3921 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
3922 if (EFI_ERROR (Status)) {
3923 //
3924 // Failed to open SNP from this handle, try to get SNP from parent handle
3925 //
3926 UpdatedDevicePath = DevicePathFromHandle (Handle);
3927 if (UpdatedDevicePath != NULL) {
3928 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
3929 if (!EFI_ERROR (Status)) {
3930 //
3931 // SNP handle found, get SNP from it
3932 //
3933 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &Snp);
3934 }
3935 }
3936 }
3937
3938 if (!EFI_ERROR (Status)) {
3939 if (Snp->Mode->MediaPresentSupported) {
3940 if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
3941 //
3942 // Invoke Snp->GetStatus() to refresh the media status
3943 //
3944 Snp->GetStatus (Snp, &InterruptStatus, NULL);
3945
3946 //
3947 // In case some one else is using the SNP check to see if it's connected
3948 //
3949 MediaPresent = Snp->Mode->MediaPresent;
3950 } else {
3951 //
3952 // No one is using SNP so we need to Start and Initialize so
3953 // MediaPresent will be valid.
3954 //
3955 Status = Snp->Start (Snp);
3956 if (!EFI_ERROR (Status)) {
3957 Status = Snp->Initialize (Snp, 0, 0);
3958 if (!EFI_ERROR (Status)) {
3959 MediaPresent = Snp->Mode->MediaPresent;
3960 Snp->Shutdown (Snp);
3961 }
3962 Snp->Stop (Snp);
3963 }
3964 }
3965 } else {
3966 MediaPresent = TRUE;
3967 }
3968 }
3969 }
3970
3971 return MediaPresent;
3972 }
3973
3974 /**
3975 For a bootable Device path, return its boot type.
3976
3977 @param DevicePath The bootable device Path to check
3978
3979 @retval BDS_EFI_MEDIA_HD_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
3980 which subtype is MEDIA_HARDDRIVE_DP
3981 @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
3982 which subtype is MEDIA_CDROM_DP
3983 @retval BDS_EFI_ACPI_FLOPPY_BOOT If given device path contains ACPI_DEVICE_PATH type device path node
3984 which HID is floppy device.
3985 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
3986 and its last device path node's subtype is MSG_ATAPI_DP.
3987 @retval BDS_EFI_MESSAGE_SCSI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
3988 and its last device path node's subtype is MSG_SCSI_DP.
3989 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
3990 and its last device path node's subtype is MSG_USB_DP.
3991 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media device path node, and
3992 its last device path node point to a message device path node.
3993 @retval BDS_LEGACY_BBS_BOOT If given device path contains BBS_DEVICE_PATH type device path node.
3994 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message device,
3995
3996 **/
3997 UINT32
3998 EFIAPI
3999 BdsGetBootTypeFromDevicePath (
4000 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
4001 )
4002 {
4003 ACPI_HID_DEVICE_PATH *Acpi;
4004 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
4005 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
4006 UINT32 BootType;
4007
4008 if (NULL == DevicePath) {
4009 return BDS_EFI_UNSUPPORT;
4010 }
4011
4012 TempDevicePath = DevicePath;
4013
4014 while (!IsDevicePathEndType (TempDevicePath)) {
4015 switch (DevicePathType (TempDevicePath)) {
4016 case BBS_DEVICE_PATH:
4017 return BDS_LEGACY_BBS_BOOT;
4018 case MEDIA_DEVICE_PATH:
4019 if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {
4020 return BDS_EFI_MEDIA_HD_BOOT;
4021 } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {
4022 return BDS_EFI_MEDIA_CDROM_BOOT;
4023 }
4024 break;
4025 case ACPI_DEVICE_PATH:
4026 Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;
4027 if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {
4028 return BDS_EFI_ACPI_FLOPPY_BOOT;
4029 }
4030 break;
4031 case MESSAGING_DEVICE_PATH:
4032 //
4033 // Get the last device path node
4034 //
4035 LastDeviceNode = NextDevicePathNode (TempDevicePath);
4036 if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {
4037 //
4038 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
4039 // skip it
4040 //
4041 LastDeviceNode = NextDevicePathNode (LastDeviceNode);
4042 }
4043 //
4044 // if the device path not only point to driver device, it is not a messaging device path,
4045 //
4046 if (!IsDevicePathEndType (LastDeviceNode)) {
4047 break;
4048 }
4049
4050 switch (DevicePathSubType (TempDevicePath)) {
4051 case MSG_ATAPI_DP:
4052 BootType = BDS_EFI_MESSAGE_ATAPI_BOOT;
4053 break;
4054
4055 case MSG_USB_DP:
4056 BootType = BDS_EFI_MESSAGE_USB_DEVICE_BOOT;
4057 break;
4058
4059 case MSG_SCSI_DP:
4060 BootType = BDS_EFI_MESSAGE_SCSI_BOOT;
4061 break;
4062
4063 case MSG_SATA_DP:
4064 BootType = BDS_EFI_MESSAGE_SATA_BOOT;
4065 break;
4066
4067 case MSG_MAC_ADDR_DP:
4068 case MSG_VLAN_DP:
4069 case MSG_IPv4_DP:
4070 case MSG_IPv6_DP:
4071 BootType = BDS_EFI_MESSAGE_MAC_BOOT;
4072 break;
4073
4074 default:
4075 BootType = BDS_EFI_MESSAGE_MISC_BOOT;
4076 break;
4077 }
4078 return BootType;
4079
4080 default:
4081 break;
4082 }
4083 TempDevicePath = NextDevicePathNode (TempDevicePath);
4084 }
4085
4086 return BDS_EFI_UNSUPPORT;
4087 }
4088
4089 /**
4090 Check whether the Device path in a boot option point to a valid bootable device,
4091 And if CheckMedia is true, check the device is ready to boot now.
4092
4093 @param DevPath the Device path in a boot option
4094 @param CheckMedia if true, check the device is ready to boot now.
4095
4096 @retval TRUE the Device path is valid
4097 @retval FALSE the Device path is invalid .
4098
4099 **/
4100 BOOLEAN
4101 EFIAPI
4102 BdsLibIsValidEFIBootOptDevicePath (
4103 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
4104 IN BOOLEAN CheckMedia
4105 )
4106 {
4107 return BdsLibIsValidEFIBootOptDevicePathExt (DevPath, CheckMedia, NULL);
4108 }
4109
4110 /**
4111 Check whether the Device path in a boot option point to a valid bootable device,
4112 And if CheckMedia is true, check the device is ready to boot now.
4113 If Description is not NULL and the device path point to a fixed BlockIo
4114 device, check the description whether conflict with other auto-created
4115 boot options.
4116
4117 @param DevPath the Device path in a boot option
4118 @param CheckMedia if true, check the device is ready to boot now.
4119 @param Description the description in a boot option
4120
4121 @retval TRUE the Device path is valid
4122 @retval FALSE the Device path is invalid .
4123
4124 **/
4125 BOOLEAN
4126 EFIAPI
4127 BdsLibIsValidEFIBootOptDevicePathExt (
4128 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
4129 IN BOOLEAN CheckMedia,
4130 IN CHAR16 *Description
4131 )
4132 {
4133 EFI_STATUS Status;
4134 EFI_HANDLE Handle;
4135 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
4136 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
4137 EFI_BLOCK_IO_PROTOCOL *BlockIo;
4138
4139 TempDevicePath = DevPath;
4140 LastDeviceNode = DevPath;
4141
4142 //
4143 // Check if it's a valid boot option for network boot device.
4144 // Check if there is EfiLoadFileProtocol installed.
4145 // If yes, that means there is a boot option for network.
4146 //
4147 Status = gBS->LocateDevicePath (
4148 &gEfiLoadFileProtocolGuid,
4149 &TempDevicePath,
4150 &Handle
4151 );
4152 if (EFI_ERROR (Status)) {
4153 //
4154 // Device not present so see if we need to connect it
4155 //
4156 TempDevicePath = DevPath;
4157 BdsLibConnectDevicePath (TempDevicePath);
4158 Status = gBS->LocateDevicePath (
4159 &gEfiLoadFileProtocolGuid,
4160 &TempDevicePath,
4161 &Handle
4162 );
4163 }
4164
4165 if (!EFI_ERROR (Status)) {
4166 if (!IsDevicePathEnd (TempDevicePath)) {
4167 //
4168 // LoadFile protocol is not installed on handle with exactly the same DevPath
4169 //
4170 return FALSE;
4171 }
4172
4173 if (CheckMedia) {
4174 //
4175 // Test if it is ready to boot now
4176 //
4177 if (BdsLibNetworkBootWithMediaPresent(DevPath)) {
4178 return TRUE;
4179 }
4180 } else {
4181 return TRUE;
4182 }
4183 }
4184
4185 //
4186 // If the boot option point to a file, it is a valid EFI boot option,
4187 // and assume it is ready to boot now
4188 //
4189 while (!IsDevicePathEnd (TempDevicePath)) {
4190 //
4191 // If there is USB Class or USB WWID device path node, treat it as valid EFI
4192 // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it
4193 // to full device path.
4194 //
4195 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
4196 ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
4197 (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
4198 return TRUE;
4199 }
4200
4201 LastDeviceNode = TempDevicePath;
4202 TempDevicePath = NextDevicePathNode (TempDevicePath);
4203 }
4204 if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
4205 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {
4206 return TRUE;
4207 }
4208
4209 //
4210 // Check if it's a valid boot option for internal FV application
4211 //
4212 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {
4213 //
4214 // If the boot option point to internal FV application, make sure it is valid
4215 //
4216 TempDevicePath = DevPath;
4217 Status = BdsLibUpdateFvFileDevicePath (
4218 &TempDevicePath,
4219 EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode)
4220 );
4221 if (Status == EFI_ALREADY_STARTED) {
4222 return TRUE;
4223 } else {
4224 if (Status == EFI_SUCCESS) {
4225 FreePool (TempDevicePath);
4226 }
4227 return FALSE;
4228 }
4229 }
4230
4231 //
4232 // If the boot option point to a blockIO device:
4233 // if it is a removable blockIo device, it is valid.
4234 // if it is a fixed blockIo device, check its description confliction.
4235 //
4236 TempDevicePath = DevPath;
4237 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
4238 if (EFI_ERROR (Status)) {
4239 //
4240 // Device not present so see if we need to connect it
4241 //
4242 Status = BdsLibConnectDevicePath (DevPath);
4243 if (!EFI_ERROR (Status)) {
4244 //
4245 // Try again to get the Block Io protocol after we did the connect
4246 //
4247 TempDevicePath = DevPath;
4248 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
4249 }
4250 }
4251
4252 if (!EFI_ERROR (Status)) {
4253 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
4254 if (!EFI_ERROR (Status)) {
4255 if (CheckMedia) {
4256 //
4257 // Test if it is ready to boot now
4258 //
4259 if (BdsLibGetBootableHandle (DevPath) != NULL) {
4260 return TRUE;
4261 }
4262 } else {
4263 return TRUE;
4264 }
4265 }
4266 } else {
4267 //
4268 // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,
4269 //
4270 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
4271 if (!EFI_ERROR (Status)) {
4272 if (CheckMedia) {
4273 //
4274 // Test if it is ready to boot now
4275 //
4276 if (BdsLibGetBootableHandle (DevPath) != NULL) {
4277 return TRUE;
4278 }
4279 } else {
4280 return TRUE;
4281 }
4282 }
4283 }
4284
4285 return FALSE;
4286 }
4287
4288
4289 /**
4290 According to a file guild, check a Fv file device path is valid. If it is invalid,
4291 try to return the valid device path.
4292 FV address maybe changes for memory layout adjust from time to time, use this function
4293 could promise the Fv file device path is right.
4294
4295 @param DevicePath on input, the Fv file device path need to check on
4296 output, the updated valid Fv file device path
4297 @param FileGuid the Fv file guild
4298
4299 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
4300 parameter
4301 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
4302 guild at all
4303 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
4304 valid
4305 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
4306 and return the updated device path in DevicePath
4307
4308 **/
4309 EFI_STATUS
4310 EFIAPI
4311 BdsLibUpdateFvFileDevicePath (
4312 IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
4313 IN EFI_GUID *FileGuid
4314 )
4315 {
4316 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
4317 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
4318 EFI_STATUS Status;
4319 EFI_GUID *GuidPoint;
4320 UINTN Index;
4321 UINTN FvHandleCount;
4322 EFI_HANDLE *FvHandleBuffer;
4323 EFI_FV_FILETYPE Type;
4324 UINTN Size;
4325 EFI_FV_FILE_ATTRIBUTES Attributes;
4326 UINT32 AuthenticationStatus;
4327 BOOLEAN FindFvFile;
4328 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
4329 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
4330 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
4331 EFI_HANDLE FoundFvHandle;
4332 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
4333
4334 if ((DevicePath == NULL) || (*DevicePath == NULL)) {
4335 return EFI_INVALID_PARAMETER;
4336 }
4337 if (FileGuid == NULL) {
4338 return EFI_INVALID_PARAMETER;
4339 }
4340
4341 //
4342 // Check whether the device path point to the default the input Fv file
4343 //
4344 TempDevicePath = *DevicePath;
4345 LastDeviceNode = TempDevicePath;
4346 while (!IsDevicePathEnd (TempDevicePath)) {
4347 LastDeviceNode = TempDevicePath;
4348 TempDevicePath = NextDevicePathNode (TempDevicePath);
4349 }
4350 GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
4351 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode
4352 );
4353 if (GuidPoint == NULL) {
4354 //
4355 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
4356 //
4357 return EFI_UNSUPPORTED;
4358 }
4359 if (!CompareGuid (GuidPoint, FileGuid)) {
4360 //
4361 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
4362 //
4363 return EFI_UNSUPPORTED;
4364 }
4365
4366 //
4367 // Check whether the input Fv file device path is valid
4368 //
4369 TempDevicePath = *DevicePath;
4370 FoundFvHandle = NULL;
4371 Status = gBS->LocateDevicePath (
4372 &gEfiFirmwareVolume2ProtocolGuid,
4373 &TempDevicePath,
4374 &FoundFvHandle
4375 );
4376 if (!EFI_ERROR (Status)) {
4377 Status = gBS->HandleProtocol (
4378 FoundFvHandle,
4379 &gEfiFirmwareVolume2ProtocolGuid,
4380 (VOID **) &Fv
4381 );
4382 if (!EFI_ERROR (Status)) {
4383 //
4384 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
4385 //
4386 Status = Fv->ReadFile (
4387 Fv,
4388 FileGuid,
4389 NULL,
4390 &Size,
4391 &Type,
4392 &Attributes,
4393 &AuthenticationStatus
4394 );
4395 if (!EFI_ERROR (Status)) {
4396 return EFI_ALREADY_STARTED;
4397 }
4398 }
4399 }
4400
4401 //
4402 // Look for the input wanted FV file in current FV
4403 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
4404 //
4405 FindFvFile = FALSE;
4406 FoundFvHandle = NULL;
4407 Status = gBS->HandleProtocol (
4408 gImageHandle,
4409 &gEfiLoadedImageProtocolGuid,
4410 (VOID **) &LoadedImage
4411 );
4412 if (!EFI_ERROR (Status)) {
4413 Status = gBS->HandleProtocol (
4414 LoadedImage->DeviceHandle,
4415 &gEfiFirmwareVolume2ProtocolGuid,
4416 (VOID **) &Fv
4417 );
4418 if (!EFI_ERROR (Status)) {
4419 Status = Fv->ReadFile (
4420 Fv,
4421 FileGuid,
4422 NULL,
4423 &Size,
4424 &Type,
4425 &Attributes,
4426 &AuthenticationStatus
4427 );
4428 if (!EFI_ERROR (Status)) {
4429 FindFvFile = TRUE;
4430 FoundFvHandle = LoadedImage->DeviceHandle;
4431 }
4432 }
4433 }
4434 //
4435 // Second, if fail to find, try to enumerate all FV
4436 //
4437 if (!FindFvFile) {
4438 FvHandleBuffer = NULL;
4439 gBS->LocateHandleBuffer (
4440 ByProtocol,
4441 &gEfiFirmwareVolume2ProtocolGuid,
4442 NULL,
4443 &FvHandleCount,
4444 &FvHandleBuffer
4445 );
4446 for (Index = 0; Index < FvHandleCount; Index++) {
4447 gBS->HandleProtocol (
4448 FvHandleBuffer[Index],
4449 &gEfiFirmwareVolume2ProtocolGuid,
4450 (VOID **) &Fv
4451 );
4452
4453 Status = Fv->ReadFile (
4454 Fv,
4455 FileGuid,
4456 NULL,
4457 &Size,
4458 &Type,
4459 &Attributes,
4460 &AuthenticationStatus
4461 );
4462 if (EFI_ERROR (Status)) {
4463 //
4464 // Skip if input Fv file not in the FV
4465 //
4466 continue;
4467 }
4468 FindFvFile = TRUE;
4469 FoundFvHandle = FvHandleBuffer[Index];
4470 break;
4471 }
4472
4473 if (FvHandleBuffer != NULL) {
4474 FreePool (FvHandleBuffer);
4475 }
4476 }
4477
4478 if (FindFvFile) {
4479 //
4480 // Build the shell device path
4481 //
4482 NewDevicePath = DevicePathFromHandle (FoundFvHandle);
4483 EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
4484 NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
4485 ASSERT (NewDevicePath != NULL);
4486 *DevicePath = NewDevicePath;
4487 return EFI_SUCCESS;
4488 }
4489 return EFI_NOT_FOUND;
4490 }