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