]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c
Move BdsDxe and GenericBdsLib to IntelFrameworkModulePkg, these modules need dependen...
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / BootMaint / BBSsupport.c
1 /** @file
2 This function deal with the legacy boot option, it create, delete
3 and manage the legacy boot option, all legacy boot option is getting from
4 the legacy BBS table.
5
6 Copyright (c) 2004 - 2008, Intel Corporation. <BR>
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "BBSsupport.h"
18
19 /**
20
21 Translate the first n characters of an Ascii string to
22 Unicode characters. The count n is indicated by parameter
23 Size. If Size is greater than the length of string, then
24 the entire string is translated.
25
26
27 @param AStr Pointer to input Ascii string.
28 @param Size The number of characters to translate.
29 @param UStr Pointer to output Unicode string buffer.
30
31 **/
32 VOID
33 AsciiToUnicodeSize (
34 IN UINT8 *AStr,
35 IN UINTN Size,
36 OUT UINT16 *UStr
37 )
38 {
39 UINTN Idx;
40
41 Idx = 0;
42 while (AStr[Idx] != 0) {
43 UStr[Idx] = (CHAR16) AStr[Idx];
44 if (Idx == Size) {
45 break;
46 }
47
48 Idx++;
49 }
50 UStr[Idx] = 0;
51 }
52
53 /**
54 Build Legacy Device Name String according.
55
56 @param CurBBSEntry BBS Table.
57 @param Index Index.
58 @param BufSize The buffer size.
59 @param BootString The output string.
60
61 **/
62 VOID
63 BdsBuildLegacyDevNameString (
64 IN BBS_TABLE *CurBBSEntry,
65 IN UINTN Index,
66 IN UINTN BufSize,
67 OUT CHAR16 *BootString
68 )
69 {
70 CHAR16 *Fmt;
71 CHAR16 *Type;
72 UINT8 *StringDesc;
73 CHAR16 Temp[80];
74
75 switch (Index) {
76 //
77 // Primary Master
78 //
79 case 1:
80 Fmt = L"Primary Master %s";
81 break;
82
83 //
84 // Primary Slave
85 //
86 case 2:
87 Fmt = L"Primary Slave %s";
88 break;
89
90 //
91 // Secondary Master
92 //
93 case 3:
94 Fmt = L"Secondary Master %s";
95 break;
96
97 //
98 // Secondary Slave
99 //
100 case 4:
101 Fmt = L"Secondary Slave %s";
102 break;
103
104 default:
105 Fmt = L"%s";
106 break;
107 }
108
109 switch (CurBBSEntry->DeviceType) {
110 case BBS_FLOPPY:
111 Type = L"Floppy";
112 break;
113
114 case BBS_HARDDISK:
115 Type = L"Harddisk";
116 break;
117
118 case BBS_CDROM:
119 Type = L"CDROM";
120 break;
121
122 case BBS_PCMCIA:
123 Type = L"PCMCIAe";
124 break;
125
126 case BBS_USB:
127 Type = L"USB";
128 break;
129
130 case BBS_EMBED_NETWORK:
131 Type = L"Network";
132 break;
133
134 case BBS_BEV_DEVICE:
135 Type = L"BEVe";
136 break;
137
138 case BBS_UNKNOWN:
139 default:
140 Type = L"Unknown";
141 break;
142 }
143 //
144 // If current BBS entry has its description then use it.
145 //
146 StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
147 if (NULL != StringDesc) {
148 //
149 // Only get fisrt 32 characters, this is suggested by BBS spec
150 //
151 AsciiToUnicodeSize (StringDesc, 32, Temp);
152 Fmt = L"%s";
153 Type = Temp;
154 }
155
156 //
157 // BbsTable 16 entries are for onboard IDE.
158 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
159 //
160 if (Index >= 5 && Index <= 16 && CurBBSEntry->DeviceType == BBS_HARDDISK) {
161 Fmt = L"%s %d";
162 UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
163 } else {
164 UnicodeSPrint (BootString, BufSize, Fmt, Type);
165 }
166 }
167
168 /**
169
170 Create a legacy boot option for the specified entry of
171 BBS table, save it as variable, and append it to the boot
172 order list.
173
174
175 @param CurrentBbsEntry Pointer to current BBS table.
176 @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS
177 @param Index Index of the specified entry in BBS table.
178 @param BootOrderList On input, the original boot order list.
179 On output, the new boot order list attached with the
180 created node.
181 @param BootOrderListSize On input, the original size of boot order list.
182 On output, the size of new boot order list.
183
184 @retval EFI_SUCCESS Boot Option successfully created.
185 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
186 @retval Other Error occurs while setting variable.
187
188 **/
189 EFI_STATUS
190 BdsCreateLegacyBootOption (
191 IN BBS_TABLE *CurrentBbsEntry,
192 IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath,
193 IN UINTN Index,
194 IN OUT UINT16 **BootOrderList,
195 IN OUT UINTN *BootOrderListSize
196 )
197 {
198 EFI_STATUS Status;
199 UINT16 CurrentBootOptionNo;
200 UINT16 BootString[10];
201 UINT16 BootDesc[100];
202 CHAR8 HelpString[100];
203 UINT16 *NewBootOrderList;
204 UINTN BufferSize;
205 UINTN StringLen;
206 VOID *Buffer;
207 UINT8 *Ptr;
208 UINT16 CurrentBbsDevPathSize;
209 UINTN BootOrderIndex;
210 UINTN BootOrderLastIndex;
211 UINTN ArrayIndex;
212 BOOLEAN IndexNotFound;
213 BBS_BBS_DEVICE_PATH *NewBbsDevPathNode;
214
215 if ((*BootOrderList) == NULL) {
216 CurrentBootOptionNo = 0;
217 } else {
218 for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {
219 IndexNotFound = TRUE;
220 for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {
221 if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {
222 IndexNotFound = FALSE;
223 break;
224 }
225 }
226
227 if (!IndexNotFound) {
228 continue;
229 } else {
230 break;
231 }
232 }
233
234 CurrentBootOptionNo = (UINT16) ArrayIndex;
235 }
236
237 UnicodeSPrint (
238 BootString,
239 sizeof (BootString),
240 L"Boot%04x",
241 CurrentBootOptionNo
242 );
243
244 BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);
245
246 //
247 // Create new BBS device path node with description string
248 //
249 UnicodeStrToAsciiStr ((CONST CHAR16*)&BootDesc, (CHAR8*)&HelpString);
250
251 StringLen = AsciiStrLen (HelpString);
252 NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
253 if (NewBbsDevPathNode == NULL) {
254 return EFI_OUT_OF_RESOURCES;
255 }
256 CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH));
257 CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1);
258 SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
259
260 //
261 // Create entire new CurrentBbsDevPath with end node
262 //
263 CurrentBbsDevPath = AppendDevicePathNode (
264 EndDevicePath,
265 (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode
266 );
267 if (CurrentBbsDevPath == NULL) {
268 FreePool (NewBbsDevPathNode);
269 return EFI_OUT_OF_RESOURCES;
270 }
271
272 CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));
273
274 BufferSize = sizeof (UINT32) +
275 sizeof (UINT16) +
276 StrSize (BootDesc) +
277 CurrentBbsDevPathSize +
278 sizeof (BBS_TABLE) +
279 sizeof (UINT16);
280
281 Buffer = AllocateZeroPool (BufferSize);
282 if (Buffer == NULL) {
283 FreePool (NewBbsDevPathNode);
284 FreePool (CurrentBbsDevPath);
285 return EFI_OUT_OF_RESOURCES;
286 }
287
288 Ptr = (UINT8 *) Buffer;
289
290 *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
291 Ptr += sizeof (UINT32);
292
293 *((UINT16 *) Ptr) = CurrentBbsDevPathSize;
294 Ptr += sizeof (UINT16);
295
296 CopyMem (
297 Ptr,
298 BootDesc,
299 StrSize (BootDesc)
300 );
301 Ptr += StrSize (BootDesc);
302
303 CopyMem (
304 Ptr,
305 CurrentBbsDevPath,
306 CurrentBbsDevPathSize
307 );
308 Ptr += CurrentBbsDevPathSize;
309
310 CopyMem (
311 Ptr,
312 CurrentBbsEntry,
313 sizeof (BBS_TABLE)
314 );
315
316 Ptr += sizeof (BBS_TABLE);
317 *((UINT16 *) Ptr) = (UINT16) Index;
318
319 Status = gRT->SetVariable (
320 BootString,
321 &gEfiGlobalVariableGuid,
322 VAR_FLAG,
323 BufferSize,
324 Buffer
325 );
326
327 FreePool (Buffer);
328
329 Buffer = NULL;
330
331 NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));
332 if (NULL == NewBootOrderList) {
333 FreePool (NewBbsDevPathNode);
334 FreePool (CurrentBbsDevPath);
335 return EFI_OUT_OF_RESOURCES;
336 }
337
338 if (*BootOrderList != NULL) {
339 CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);
340 FreePool (*BootOrderList);
341 }
342
343 BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16));
344 NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo;
345 *BootOrderListSize += sizeof (UINT16);
346 *BootOrderList = NewBootOrderList;
347
348 FreePool (NewBbsDevPathNode);
349 FreePool (CurrentBbsDevPath);
350 return Status;
351 }
352
353 /**
354 Check if the boot option is a legacy one.
355
356 @param BootOptionVar The boot option data payload.
357 @param BbsEntry The BBS Table.
358 @param BbsIndex The table index.
359
360 @retval TRUE It is a legacy boot option.
361 @retval FALSE It is not a legacy boot option.
362
363 **/
364 BOOLEAN
365 BdsIsLegacyBootOption (
366 IN UINT8 *BootOptionVar,
367 OUT BBS_TABLE **BbsEntry,
368 OUT UINT16 *BbsIndex
369 )
370 {
371 UINT8 *Ptr;
372 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
373 BOOLEAN Ret;
374 UINT16 DevPathLen;
375
376 Ptr = BootOptionVar;
377 Ptr += sizeof (UINT32);
378 DevPathLen = *(UINT16 *) Ptr;
379 Ptr += sizeof (UINT16);
380 Ptr += StrSize ((UINT16 *) Ptr);
381 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
382 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
383 Ptr += DevPathLen;
384 *BbsEntry = (BBS_TABLE *) Ptr;
385 Ptr += sizeof (BBS_TABLE);
386 *BbsIndex = *(UINT16 *) Ptr;
387 Ret = TRUE;
388 } else {
389 *BbsEntry = NULL;
390 Ret = FALSE;
391 }
392
393 return Ret;
394 }
395
396 /**
397 Delete all the invalid legacy boot options.
398
399 @retval EFI_SUCCESS All invalide legacy boot options are deleted.
400 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
401 @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
402 **/
403 EFI_STATUS
404 BdsDeleteAllInvalidLegacyBootOptions (
405 VOID
406 )
407 {
408 UINT16 *BootOrder;
409 UINT8 *BootOptionVar;
410 UINTN BootOrderSize;
411 UINTN BootOptionSize;
412 EFI_STATUS Status;
413 UINT16 HddCount;
414 UINT16 BbsCount;
415 HDD_INFO *LocalHddInfo;
416 BBS_TABLE *LocalBbsTable;
417 BBS_TABLE *BbsEntry;
418 UINT16 BbsIndex;
419 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
420 UINTN Index;
421 UINT16 BootOption[10];
422 UINT16 BootDesc[100];
423 BOOLEAN DescStringMatch;
424
425 Status = EFI_SUCCESS;
426 BootOrder = NULL;
427 BootOrderSize = 0;
428 HddCount = 0;
429 BbsCount = 0;
430 LocalHddInfo = NULL;
431 LocalBbsTable = NULL;
432 BbsEntry = NULL;
433
434 Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
435 if (EFI_ERROR (Status)) {
436 return Status;
437 }
438
439 LegacyBios->GetBbsInfo (
440 LegacyBios,
441 &HddCount,
442 &LocalHddInfo,
443 &BbsCount,
444 &LocalBbsTable
445 );
446
447 BootOrder = BdsLibGetVariableAndSize (
448 L"BootOrder",
449 &gEfiGlobalVariableGuid,
450 &BootOrderSize
451 );
452 if (NULL == BootOrder) {
453 return EFI_NOT_FOUND;
454 }
455
456 Index = 0;
457 while (Index < BootOrderSize / sizeof (UINT16)) {
458 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
459 BootOptionVar = BdsLibGetVariableAndSize (
460 BootOption,
461 &gEfiGlobalVariableGuid,
462 &BootOptionSize
463 );
464 if (NULL == BootOptionVar) {
465 if (BootOrder != NULL) {
466 FreePool (BootOrder);
467 }
468 return EFI_OUT_OF_RESOURCES;
469 }
470
471 //
472 // Skip Non-Legacy boot options
473 //
474 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {
475 if (BootOptionVar!= NULL) {
476 FreePool (BootOptionVar);
477 }
478 Index++;
479 continue;
480 }
481
482 //
483 // Check if BBS Description String is changed
484 //
485 DescStringMatch = FALSE;
486
487 BdsBuildLegacyDevNameString (
488 &LocalBbsTable[BbsIndex],
489 BbsIndex,
490 sizeof(BootDesc),
491 BootDesc
492 );
493
494 if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {
495 DescStringMatch = TRUE;
496 }
497
498 if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||
499 (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&
500 (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&
501 DescStringMatch) {
502 Index++;
503 continue;
504 }
505
506 if (BootOptionVar != NULL) {
507 FreePool (BootOptionVar);
508 }
509 //
510 // should delete
511 //
512 BdsDeleteBootOption (
513 BootOrder[Index],
514 BootOrder,
515 &BootOrderSize
516 );
517 }
518
519 //
520 // Adjust the number of boot options.
521 //
522 if (BootOrderSize != 0) {
523 Status = gRT->SetVariable (
524 L"BootOrder",
525 &gEfiGlobalVariableGuid,
526 VAR_FLAG,
527 BootOrderSize,
528 BootOrder
529 );
530 } else {
531 EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
532 }
533
534 if (BootOrder != NULL) {
535 FreePool (BootOrder);
536 }
537
538 return Status;
539 }
540
541 /**
542 Find all legacy boot option by device type.
543
544 @param BootOrder The boot order array.
545 @param BootOptionNum The number of boot option.
546 @param DevType Device type.
547 @param Attribute The boot option attribute.
548 @param BbsIndex The BBS table index.
549 @param OptionNumber The boot option index.
550
551 @retval TRUE The Legacy boot option is found.
552 @retval FALSE The legacy boot option is not found.
553
554 **/
555 BOOLEAN
556 BdsFindLegacyBootOptionByDevType (
557 IN UINT16 *BootOrder,
558 IN UINTN BootOptionNum,
559 IN UINT16 DevType,
560 OUT UINT32 *Attribute,
561 OUT UINT16 *BbsIndex,
562 OUT UINTN *OptionNumber
563 )
564 {
565 UINTN Index;
566 UINTN BootOrderIndex;
567 UINT16 BootOption[100];
568 UINTN BootOptionSize;
569 UINT8 *BootOptionVar;
570 BBS_TABLE *BbsEntry;
571 BOOLEAN Found;
572
573 BbsEntry = NULL;
574 Found = FALSE;
575
576 if (NULL == BootOrder) {
577 return Found;
578 }
579
580 //
581 // Loop all boot option from variable
582 //
583 for (BootOrderIndex = 0; BootOrderIndex < BootOptionNum; BootOrderIndex++) {
584 Index = (UINTN) BootOrder[BootOrderIndex];
585 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", Index);
586 BootOptionVar = BdsLibGetVariableAndSize (
587 BootOption,
588 &gEfiGlobalVariableGuid,
589 &BootOptionSize
590 );
591 if (NULL == BootOptionVar) {
592 continue;
593 }
594
595 //
596 // Skip Non-legacy boot option
597 //
598 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {
599 FreePool (BootOptionVar);
600 continue;
601 }
602
603 if (BbsEntry->DeviceType != DevType) {
604 FreePool (BootOptionVar);
605 continue;
606 }
607
608 *Attribute = *(UINT32 *) BootOptionVar;
609 *OptionNumber = Index;
610 Found = TRUE;
611 FreePool (BootOptionVar);
612 break;
613 }
614
615 return Found;
616 }
617
618 /**
619 Create a legacy boot option.
620
621 @param BbsItem The BBS Table entry.
622 @param Index Index of the specified entry in BBS table.
623 @param BootOrderList The boot order list.
624 @param BootOrderListSize The size of boot order list.
625
626 @retval EFI_OUT_OF_RESOURCE No enough memory.
627 @retval EFI_SUCCESS The function complete successfully.
628 @return Other value if the legacy boot option is not created.
629
630 **/
631 EFI_STATUS
632 BdsCreateOneLegacyBootOption (
633 IN BBS_TABLE *BbsItem,
634 IN UINTN Index,
635 IN OUT UINT16 **BootOrderList,
636 IN OUT UINTN *BootOrderListSize
637 )
638 {
639 BBS_BBS_DEVICE_PATH BbsDevPathNode;
640 EFI_STATUS Status;
641 EFI_DEVICE_PATH_PROTOCOL *DevPath;
642
643 DevPath = NULL;
644
645 //
646 // Create device path node.
647 //
648 BbsDevPathNode.Header.Type = BBS_DEVICE_PATH;
649 BbsDevPathNode.Header.SubType = BBS_BBS_DP;
650 SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
651 BbsDevPathNode.DeviceType = BbsItem->DeviceType;
652 CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));
653
654 DevPath = AppendDevicePathNode (
655 EndDevicePath,
656 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode
657 );
658 if (NULL == DevPath) {
659 return EFI_OUT_OF_RESOURCES;
660 }
661
662 Status = BdsCreateLegacyBootOption (
663 BbsItem,
664 DevPath,
665 Index,
666 BootOrderList,
667 BootOrderListSize
668 );
669 BbsItem->BootPriority = 0x00;
670
671 FreePool (DevPath);
672
673 return Status;
674 }
675
676 /**
677
678 Add the legacy boot options from BBS table if they do not exist.
679
680 @retval EFI_SUCCESS The boot options are added successfully
681 or they are already in boot options.
682
683 **/
684 EFI_STATUS
685 BdsAddNonExistingLegacyBootOptions (
686 VOID
687 )
688 {
689 UINT16 *BootOrder;
690 UINTN BootOrderSize;
691 EFI_STATUS Status;
692 UINT16 HddCount;
693 UINT16 BbsCount;
694 HDD_INFO *LocalHddInfo;
695 BBS_TABLE *LocalBbsTable;
696 UINT16 BbsIndex;
697 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
698 UINTN Index;
699 UINT32 Attribute;
700 UINTN OptionNumber;
701 BOOLEAN Ret;
702
703 BootOrder = NULL;
704 HddCount = 0;
705 BbsCount = 0;
706 LocalHddInfo = NULL;
707 LocalBbsTable = NULL;
708
709 Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
710 if (EFI_ERROR (Status)) {
711 return Status;
712 }
713
714 LegacyBios->GetBbsInfo (
715 LegacyBios,
716 &HddCount,
717 &LocalHddInfo,
718 &BbsCount,
719 &LocalBbsTable
720 );
721
722 BootOrder = BdsLibGetVariableAndSize (
723 L"BootOrder",
724 &gEfiGlobalVariableGuid,
725 &BootOrderSize
726 );
727 if (NULL == BootOrder) {
728 BootOrderSize = 0;
729 }
730
731 for (Index = 0; Index < BbsCount; Index++) {
732 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
733 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
734 ) {
735 continue;
736 }
737
738 Ret = BdsFindLegacyBootOptionByDevType (
739 BootOrder,
740 BootOrderSize / sizeof (UINT16),
741 LocalBbsTable[Index].DeviceType,
742 &Attribute,
743 &BbsIndex,
744 &OptionNumber
745 );
746 if (Ret) {
747 continue;
748 }
749
750 //
751 // Not found such type of legacy device in boot options or we found but it's disabled
752 // so we have to create one and put it to the tail of boot order list
753 //
754 Status = BdsCreateOneLegacyBootOption (
755 &LocalBbsTable[Index],
756 Index,
757 &BootOrder,
758 &BootOrderSize
759 );
760 if (EFI_ERROR (Status)) {
761 break;
762 }
763 }
764
765 if (BootOrderSize > 0) {
766 Status = gRT->SetVariable (
767 L"BootOrder",
768 &gEfiGlobalVariableGuid,
769 VAR_FLAG,
770 BootOrderSize,
771 BootOrder
772 );
773 } else {
774 EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
775 }
776
777 if (BootOrder != NULL) {
778 FreePool (BootOrder);
779 }
780
781 return Status;
782 }
783
784 /**
785 Fill the device order buffer.
786
787 @param BbsTable The BBS table.
788 @param BbsType The BBS Type.
789 @param BbsCount The BBS Count.
790 @param Buf device order buffer.
791
792 @return The device order buffer.
793
794 **/
795 UINT16 *
796 BdsFillDevOrderBuf (
797 IN BBS_TABLE *BbsTable,
798 IN BBS_TYPE BbsType,
799 IN UINTN BbsCount,
800 OUT UINT16 *Buf
801 )
802 {
803 UINTN Index;
804
805 for (Index = 0; Index < BbsCount; Index++) {
806 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
807 continue;
808 }
809
810 if (BbsTable[Index].DeviceType != BbsType) {
811 continue;
812 }
813
814 *Buf = (UINT16) (Index & 0xFF);
815 Buf++;
816 }
817
818 return Buf;
819 }
820
821 /**
822 Create the device order buffer.
823
824 @param BbsTable The BBS table.
825 @param BbsCount The BBS Count.
826
827 @retval EFI_SUCCES The buffer is created and the EFI variable named
828 VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is
829 set correctly.
830 @return Other value if the set of EFI variable fails. Check gRT->SetVariable
831 for detailed information.
832
833 **/
834 EFI_STATUS
835 BdsCreateDevOrder (
836 IN BBS_TABLE *BbsTable,
837 IN UINT16 BbsCount
838 )
839 {
840 UINTN Index;
841 UINTN FDCount;
842 UINTN HDCount;
843 UINTN CDCount;
844 UINTN NETCount;
845 UINTN BEVCount;
846 UINTN TotalSize;
847 UINTN HeaderSize;
848 UINT8 *DevOrder;
849 UINT8 *Ptr;
850 EFI_STATUS Status;
851
852 FDCount = 0;
853 HDCount = 0;
854 CDCount = 0;
855 NETCount = 0;
856 BEVCount = 0;
857 TotalSize = 0;
858 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
859 DevOrder = NULL;
860 Ptr = NULL;
861 Status = EFI_SUCCESS;
862
863 //
864 // Count all boot devices
865 //
866 for (Index = 0; Index < BbsCount; Index++) {
867 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
868 continue;
869 }
870
871 switch (BbsTable[Index].DeviceType) {
872 case BBS_FLOPPY:
873 FDCount++;
874 break;
875
876 case BBS_HARDDISK:
877 HDCount++;
878 break;
879
880 case BBS_CDROM:
881 CDCount++;
882 break;
883
884 case BBS_EMBED_NETWORK:
885 NETCount++;
886 break;
887
888 case BBS_BEV_DEVICE:
889 BEVCount++;
890 break;
891
892 default:
893 break;
894 }
895 }
896
897 TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
898 TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
899 TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
900 TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
901 TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
902
903 //
904 // Create buffer to hold all boot device order
905 //
906 DevOrder = AllocateZeroPool (TotalSize);
907 if (NULL == DevOrder) {
908 return EFI_OUT_OF_RESOURCES;
909 }
910
911 Ptr = DevOrder;
912
913 *((BBS_TYPE *) Ptr) = BBS_FLOPPY;
914 Ptr += sizeof (BBS_TYPE);
915 *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
916 Ptr += sizeof (UINT16);
917 if (FDCount != 0) {
918 Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, (UINT16 *) Ptr);
919 }
920
921 *((BBS_TYPE *) Ptr) = BBS_HARDDISK;
922 Ptr += sizeof (BBS_TYPE);
923 *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
924 Ptr += sizeof (UINT16);
925 if (HDCount != 0) {
926 Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, (UINT16 *) Ptr);
927 }
928
929 *((BBS_TYPE *) Ptr) = BBS_CDROM;
930 Ptr += sizeof (BBS_TYPE);
931 *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
932 Ptr += sizeof (UINT16);
933 if (CDCount != 0) {
934 Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, (UINT16 *) Ptr);
935 }
936
937 *((BBS_TYPE *) Ptr) = BBS_EMBED_NETWORK;
938 Ptr += sizeof (BBS_TYPE);
939 *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
940 Ptr += sizeof (UINT16);
941 if (NETCount != 0) {
942 Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, (UINT16 *) Ptr);
943 }
944
945 *((BBS_TYPE *) Ptr) = BBS_BEV_DEVICE;
946 Ptr += sizeof (BBS_TYPE);
947 *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
948 Ptr += sizeof (UINT16);
949 if (BEVCount != 0) {
950 Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, (UINT16 *) Ptr);
951 }
952
953 //
954 // Save device order for legacy boot device to variable.
955 //
956 Status = gRT->SetVariable (
957 VAR_LEGACY_DEV_ORDER,
958 &EfiLegacyDevOrderGuid,
959 VAR_FLAG,
960 TotalSize,
961 DevOrder
962 );
963 FreePool (DevOrder);
964
965 return Status;
966 }
967
968 /**
969
970 Add the legacy boot devices from BBS table into
971 the legacy device boot order.
972
973 @retval EFI_SUCCESS The boot devices are added successfully.
974
975 **/
976 EFI_STATUS
977 BdsUpdateLegacyDevOrder (
978 VOID
979 )
980 {
981 UINT8 *DevOrder;
982 UINT8 *NewDevOrder;
983 UINTN DevOrderSize;
984 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
985 EFI_STATUS Status;
986 UINT16 HddCount;
987 UINT16 BbsCount;
988 HDD_INFO *LocalHddInfo;
989 BBS_TABLE *LocalBbsTable;
990 UINTN Index;
991 UINTN Index2;
992 UINTN *Idx;
993 UINTN FDCount;
994 UINTN HDCount;
995 UINTN CDCount;
996 UINTN NETCount;
997 UINTN BEVCount;
998 UINTN TotalSize;
999 UINTN HeaderSize;
1000 UINT8 *Ptr;
1001 UINT8 *NewPtr;
1002 UINT16 *NewFDPtr;
1003 UINT16 *NewHDPtr;
1004 UINT16 *NewCDPtr;
1005 UINT16 *NewNETPtr;
1006 UINT16 *NewBEVPtr;
1007 UINT16 *NewDevPtr;
1008 UINT16 Length;
1009 UINT16 Tmp;
1010 UINTN FDIndex;
1011 UINTN HDIndex;
1012 UINTN CDIndex;
1013 UINTN NETIndex;
1014 UINTN BEVIndex;
1015
1016 LocalHddInfo = NULL;
1017 LocalBbsTable = NULL;
1018 Idx = NULL;
1019 FDCount = 0;
1020 HDCount = 0;
1021 CDCount = 0;
1022 NETCount = 0;
1023 BEVCount = 0;
1024 TotalSize = 0;
1025 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
1026 FDIndex = 0;
1027 HDIndex = 0;
1028 CDIndex = 0;
1029 NETIndex = 0;
1030 BEVIndex = 0;
1031 NewDevPtr = NULL;
1032
1033 Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
1034 if (EFI_ERROR (Status)) {
1035 return Status;
1036 }
1037
1038 LegacyBios->GetBbsInfo (
1039 LegacyBios,
1040 &HddCount,
1041 &LocalHddInfo,
1042 &BbsCount,
1043 &LocalBbsTable
1044 );
1045
1046 DevOrder = (UINT8 *) BdsLibGetVariableAndSize (
1047 VAR_LEGACY_DEV_ORDER,
1048 &EfiLegacyDevOrderGuid,
1049 &DevOrderSize
1050 );
1051 if (NULL == DevOrder) {
1052 return BdsCreateDevOrder (LocalBbsTable, BbsCount);
1053 }
1054 //
1055 // First we figure out how many boot devices with same device type respectively
1056 //
1057 for (Index = 0; Index < BbsCount; Index++) {
1058 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
1059 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
1060 ) {
1061 continue;
1062 }
1063
1064 switch (LocalBbsTable[Index].DeviceType) {
1065 case BBS_FLOPPY:
1066 FDCount++;
1067 break;
1068
1069 case BBS_HARDDISK:
1070 HDCount++;
1071 break;
1072
1073 case BBS_CDROM:
1074 CDCount++;
1075 break;
1076
1077 case BBS_EMBED_NETWORK:
1078 NETCount++;
1079 break;
1080
1081 case BBS_BEV_DEVICE:
1082 BEVCount++;
1083 break;
1084
1085 default:
1086 break;
1087 }
1088 }
1089
1090 TotalSize += (HeaderSize + FDCount * sizeof (UINT16));
1091 TotalSize += (HeaderSize + HDCount * sizeof (UINT16));
1092 TotalSize += (HeaderSize + CDCount * sizeof (UINT16));
1093 TotalSize += (HeaderSize + NETCount * sizeof (UINT16));
1094 TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));
1095
1096 NewDevOrder = AllocateZeroPool (TotalSize);
1097 if (NULL == NewDevOrder) {
1098 return EFI_OUT_OF_RESOURCES;
1099 }
1100
1101 NewFDPtr = (UINT16 *) (NewDevOrder + HeaderSize);
1102 NewHDPtr = (UINT16 *) ((UINT8 *) NewFDPtr + FDCount * sizeof (UINT16) + HeaderSize);
1103 NewCDPtr = (UINT16 *) ((UINT8 *) NewHDPtr + HDCount * sizeof (UINT16) + HeaderSize);
1104 NewNETPtr = (UINT16 *) ((UINT8 *) NewCDPtr + CDCount * sizeof (UINT16) + HeaderSize);
1105 NewBEVPtr = (UINT16 *) ((UINT8 *) NewNETPtr + NETCount * sizeof (UINT16) + HeaderSize);
1106
1107 //
1108 // copy FD
1109 //
1110 Ptr = DevOrder;
1111 NewPtr = NewDevOrder;
1112 *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
1113 Ptr += sizeof (BBS_TYPE);
1114 NewPtr += sizeof (BBS_TYPE);
1115 Length = *((UINT16 *) Ptr);
1116 *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
1117 Ptr += sizeof (UINT16);
1118
1119 for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
1120 if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
1121 LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1122 LocalBbsTable[*Ptr].DeviceType != BBS_FLOPPY
1123 ) {
1124 Ptr += sizeof (UINT16);
1125 continue;
1126 }
1127
1128 NewFDPtr[FDIndex] = *(UINT16 *) Ptr;
1129 FDIndex++;
1130 Ptr += sizeof (UINT16);
1131 }
1132 //
1133 // copy HD
1134 //
1135 NewPtr = (UINT8 *) NewHDPtr - HeaderSize;
1136 *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
1137 Ptr += sizeof (BBS_TYPE);
1138 NewPtr += sizeof (BBS_TYPE);
1139 Length = *((UINT16 *) Ptr);
1140 *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
1141 Ptr += sizeof (UINT16);
1142
1143 for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
1144 if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
1145 LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1146 LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
1147 LocalBbsTable[*Ptr].DeviceType != BBS_HARDDISK
1148 ) {
1149 Ptr += sizeof (UINT16);
1150 continue;
1151 }
1152
1153 NewHDPtr[HDIndex] = *(UINT16 *) Ptr;
1154 HDIndex++;
1155 Ptr += sizeof (UINT16);
1156 }
1157 //
1158 // copy CD
1159 //
1160 NewPtr = (UINT8 *) NewCDPtr - HeaderSize;
1161 *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
1162 Ptr += sizeof (BBS_TYPE);
1163 NewPtr += sizeof (BBS_TYPE);
1164 Length = *((UINT16 *) Ptr);
1165 *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
1166 Ptr += sizeof (UINT16);
1167
1168 for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
1169 if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
1170 LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1171 LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
1172 LocalBbsTable[*Ptr].DeviceType != BBS_CDROM
1173 ) {
1174 Ptr += sizeof (UINT16);
1175 continue;
1176 }
1177
1178 NewCDPtr[CDIndex] = *(UINT16 *) Ptr;
1179 CDIndex++;
1180 Ptr += sizeof (UINT16);
1181 }
1182 //
1183 // copy NET
1184 //
1185 NewPtr = (UINT8 *) NewNETPtr - HeaderSize;
1186 *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
1187 Ptr += sizeof (BBS_TYPE);
1188 NewPtr += sizeof (BBS_TYPE);
1189 Length = *((UINT16 *) Ptr);
1190 *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
1191 Ptr += sizeof (UINT16);
1192
1193 for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
1194 if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
1195 LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1196 LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
1197 LocalBbsTable[*Ptr].DeviceType != BBS_EMBED_NETWORK
1198 ) {
1199 Ptr += sizeof (UINT16);
1200 continue;
1201 }
1202
1203 NewNETPtr[NETIndex] = *(UINT16 *) Ptr;
1204 NETIndex++;
1205 Ptr += sizeof (UINT16);
1206 }
1207 //
1208 // copy BEV
1209 //
1210 NewPtr = (UINT8 *) NewBEVPtr - HeaderSize;
1211 *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
1212 Ptr += sizeof (BBS_TYPE);
1213 NewPtr += sizeof (BBS_TYPE);
1214 Length = *((UINT16 *) Ptr);
1215 *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
1216 Ptr += sizeof (UINT16);
1217
1218 for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
1219 if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
1220 LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1221 LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
1222 LocalBbsTable[*Ptr].DeviceType != BBS_BEV_DEVICE
1223 ) {
1224 Ptr += sizeof (UINT16);
1225 continue;
1226 }
1227
1228 NewBEVPtr[BEVIndex] = *(UINT16 *) Ptr;
1229 BEVIndex++;
1230 Ptr += sizeof (UINT16);
1231 }
1232
1233 for (Index = 0; Index < BbsCount; Index++) {
1234 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
1235 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
1236 ) {
1237 continue;
1238 }
1239
1240 switch (LocalBbsTable[Index].DeviceType) {
1241 case BBS_FLOPPY:
1242 Idx = &FDIndex;
1243 NewDevPtr = NewFDPtr;
1244 break;
1245
1246 case BBS_HARDDISK:
1247 Idx = &HDIndex;
1248 NewDevPtr = NewHDPtr;
1249 break;
1250
1251 case BBS_CDROM:
1252 Idx = &CDIndex;
1253 NewDevPtr = NewCDPtr;
1254 break;
1255
1256 case BBS_EMBED_NETWORK:
1257 Idx = &NETIndex;
1258 NewDevPtr = NewNETPtr;
1259 break;
1260
1261 case BBS_BEV_DEVICE:
1262 Idx = &BEVIndex;
1263 NewDevPtr = NewBEVPtr;
1264 break;
1265
1266 default:
1267 Idx = NULL;
1268 break;
1269 }
1270 //
1271 // at this point we have copied those valid indexes to new buffer
1272 // and we should check if there is any new appeared boot device
1273 //
1274 if (Idx != 0) {
1275 for (Index2 = 0; Index2 < *Idx; Index2++) {
1276 if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {
1277 break;
1278 }
1279 }
1280
1281 if (Index2 == *Idx) {
1282 //
1283 // Index2 == *Idx means we didn't find Index
1284 // so Index is a new appeared device's index in BBS table
1285 // save it.
1286 //
1287 NewDevPtr[*Idx] = (UINT16) (Index & 0xFF);
1288 (*Idx)++;
1289 }
1290 }
1291 }
1292
1293 if (FDCount != 0) {
1294 //
1295 // Just to make sure that disabled indexes are all at the end of the array
1296 //
1297 for (Index = 0; Index < FDIndex - 1; Index++) {
1298 if (0xFF00 != (NewFDPtr[Index] & 0xFF00)) {
1299 continue;
1300 }
1301
1302 for (Index2 = Index + 1; Index2 < FDIndex; Index2++) {
1303 if (0 == (NewFDPtr[Index2] & 0xFF00)) {
1304 Tmp = NewFDPtr[Index];
1305 NewFDPtr[Index] = NewFDPtr[Index2];
1306 NewFDPtr[Index2] = Tmp;
1307 break;
1308 }
1309 }
1310 }
1311 }
1312
1313 if (HDCount != 0) {
1314 //
1315 // Just to make sure that disabled indexes are all at the end of the array
1316 //
1317 for (Index = 0; Index < HDIndex - 1; Index++) {
1318 if (0xFF00 != (NewHDPtr[Index] & 0xFF00)) {
1319 continue;
1320 }
1321
1322 for (Index2 = Index + 1; Index2 < HDIndex; Index2++) {
1323 if (0 == (NewHDPtr[Index2] & 0xFF00)) {
1324 Tmp = NewHDPtr[Index];
1325 NewHDPtr[Index] = NewHDPtr[Index2];
1326 NewHDPtr[Index2] = Tmp;
1327 break;
1328 }
1329 }
1330 }
1331 }
1332
1333 if (CDCount != 0) {
1334 //
1335 // Just to make sure that disabled indexes are all at the end of the array
1336 //
1337 for (Index = 0; Index < CDIndex - 1; Index++) {
1338 if (0xFF00 != (NewCDPtr[Index] & 0xFF00)) {
1339 continue;
1340 }
1341
1342 for (Index2 = Index + 1; Index2 < CDIndex; Index2++) {
1343 if (0 == (NewCDPtr[Index2] & 0xFF00)) {
1344 Tmp = NewCDPtr[Index];
1345 NewCDPtr[Index] = NewCDPtr[Index2];
1346 NewCDPtr[Index2] = Tmp;
1347 break;
1348 }
1349 }
1350 }
1351 }
1352
1353 if (NETCount != 0) {
1354 //
1355 // Just to make sure that disabled indexes are all at the end of the array
1356 //
1357 for (Index = 0; Index < NETIndex - 1; Index++) {
1358 if (0xFF00 != (NewNETPtr[Index] & 0xFF00)) {
1359 continue;
1360 }
1361
1362 for (Index2 = Index + 1; Index2 < NETIndex; Index2++) {
1363 if (0 == (NewNETPtr[Index2] & 0xFF00)) {
1364 Tmp = NewNETPtr[Index];
1365 NewNETPtr[Index] = NewNETPtr[Index2];
1366 NewNETPtr[Index2] = Tmp;
1367 break;
1368 }
1369 }
1370 }
1371 }
1372
1373 if (BEVCount!= 0) {
1374 //
1375 // Just to make sure that disabled indexes are all at the end of the array
1376 //
1377 for (Index = 0; Index < BEVIndex - 1; Index++) {
1378 if (0xFF00 != (NewBEVPtr[Index] & 0xFF00)) {
1379 continue;
1380 }
1381
1382 for (Index2 = Index + 1; Index2 < BEVIndex; Index2++) {
1383 if (0 == (NewBEVPtr[Index2] & 0xFF00)) {
1384 Tmp = NewBEVPtr[Index];
1385 NewBEVPtr[Index] = NewBEVPtr[Index2];
1386 NewBEVPtr[Index2] = Tmp;
1387 break;
1388 }
1389 }
1390 }
1391 }
1392
1393 FreePool (DevOrder);
1394
1395 Status = gRT->SetVariable (
1396 VAR_LEGACY_DEV_ORDER,
1397 &EfiLegacyDevOrderGuid,
1398 VAR_FLAG,
1399 TotalSize,
1400 NewDevOrder
1401 );
1402 FreePool (NewDevOrder);
1403
1404 return Status;
1405 }
1406
1407 /**
1408 Set Boot Priority for specified device type.
1409
1410 @param DeviceType The device type.
1411 @param LocalBbsTable The BBS table.
1412 @param Priority The prority table.
1413
1414 @retval EFI_SUCCESS The function completes successfully.
1415 @retval EFI_NOT_FOUND Failed to find device.
1416
1417 **/
1418 EFI_STATUS
1419 BdsSetBootPriority4SameTypeDev (
1420 IN UINT16 DeviceType,
1421 IN OUT BBS_TABLE *LocalBbsTable,
1422 IN OUT UINT16 *Priority
1423 )
1424 {
1425 UINT8 *DevOrder;
1426
1427 UINT8 *OrigBuffer;
1428 UINT16 *DevIndex;
1429 UINTN DevOrderSize;
1430 UINTN DevCount;
1431 UINTN Index;
1432
1433 DevOrder = BdsLibGetVariableAndSize (
1434 VAR_LEGACY_DEV_ORDER,
1435 &EfiLegacyDevOrderGuid,
1436 &DevOrderSize
1437 );
1438 if (NULL == DevOrder) {
1439 return EFI_OUT_OF_RESOURCES;
1440 }
1441
1442 OrigBuffer = DevOrder;
1443 while (DevOrder < OrigBuffer + DevOrderSize) {
1444 if (DeviceType == * (BBS_TYPE *) DevOrder) {
1445 break;
1446 }
1447
1448 DevOrder += sizeof (BBS_TYPE);
1449 DevOrder += *(UINT16 *) DevOrder;
1450 }
1451
1452 if (DevOrder >= OrigBuffer + DevOrderSize) {
1453 FreePool (OrigBuffer);
1454 return EFI_NOT_FOUND;
1455 }
1456
1457 DevOrder += sizeof (BBS_TYPE);
1458 DevCount = (*((UINT16 *) DevOrder) - sizeof (UINT16)) / sizeof (UINT16);
1459 DevIndex = (UINT16 *) (DevOrder + sizeof (UINT16));
1460 //
1461 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
1462 //
1463 for (Index = 0; Index < DevCount; Index++) {
1464 if ((DevIndex[Index] & 0xFF00) == 0xFF00) {
1465 //
1466 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
1467 //
1468 } else {
1469 LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = *Priority;
1470 (*Priority)++;
1471 }
1472 }
1473
1474 FreePool (OrigBuffer);
1475 return EFI_SUCCESS;
1476 }
1477
1478 /**
1479 Print the BBS Table.
1480
1481 @param LocalBbsTable The BBS table.
1482
1483 **/
1484 VOID
1485 PrintBbsTable (
1486 IN BBS_TABLE *LocalBbsTable
1487 )
1488 {
1489 UINT16 Idx;
1490
1491 DEBUG ((DEBUG_ERROR, "\n"));
1492 DEBUG ((DEBUG_ERROR, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
1493 DEBUG ((DEBUG_ERROR, "=============================================\n"));
1494 for (Idx = 0; Idx < MAX_BBS_ENTRIES; Idx++) {
1495 if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) ||
1496 (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) ||
1497 (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY)
1498 ) {
1499 continue;
1500 }
1501
1502 DEBUG (
1503 (DEBUG_ERROR,
1504 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
1505 (UINTN) Idx,
1506 (UINTN) LocalBbsTable[Idx].BootPriority,
1507 (UINTN) LocalBbsTable[Idx].Bus,
1508 (UINTN) LocalBbsTable[Idx].Device,
1509 (UINTN) LocalBbsTable[Idx].Function,
1510 (UINTN) LocalBbsTable[Idx].Class,
1511 (UINTN) LocalBbsTable[Idx].SubClass,
1512 (UINTN) LocalBbsTable[Idx].DeviceType,
1513 (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,
1514 (UINTN) LocalBbsTable[Idx].BootHandlerSegment,
1515 (UINTN) LocalBbsTable[Idx].BootHandlerOffset,
1516 (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),
1517 (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset))
1518 );
1519 }
1520
1521 DEBUG ((DEBUG_ERROR, "\n"));
1522 }
1523
1524 /**
1525
1526 Set the boot priority for BBS entries based on boot option entry and boot order.
1527
1528 @param Entry The boot option is to be checked for refresh BBS table.
1529
1530 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
1531 @return status of BdsSetBootPriority4SameTypeDev()
1532 **/
1533 EFI_STATUS
1534 BdsRefreshBbsTableForBoot (
1535 IN BDS_COMMON_OPTION *Entry
1536 )
1537 {
1538 EFI_STATUS Status;
1539 UINT16 HddCount;
1540 UINT16 BbsCount;
1541 HDD_INFO *LocalHddInfo;
1542 BBS_TABLE *LocalBbsTable;
1543 UINT16 DevType;
1544 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
1545 UINTN Index;
1546 UINT16 Priority;
1547 UINT16 *BootOrder;
1548 UINTN BootOrderSize;
1549 UINT8 *BootOptionVar;
1550 UINTN BootOptionSize;
1551 UINT16 BootOption[100];
1552 UINT8 *Ptr;
1553 UINT16 DevPathLen;
1554 EFI_DEVICE_PATH_PROTOCOL *DevPath;
1555
1556 HddCount = 0;
1557 BbsCount = 0;
1558 LocalHddInfo = NULL;
1559 LocalBbsTable = NULL;
1560 DevType = BBS_UNKNOWN;
1561
1562 Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
1563 if (EFI_ERROR (Status)) {
1564 return Status;
1565 }
1566
1567 LegacyBios->GetBbsInfo (
1568 LegacyBios,
1569 &HddCount,
1570 &LocalHddInfo,
1571 &BbsCount,
1572 &LocalBbsTable
1573 );
1574 //
1575 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
1576 // We will set them according to the settings setup by user
1577 //
1578 for (Index = 0; Index < BbsCount; Index++) {
1579 if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) ||
1580 (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) ||
1581 (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) {
1582 LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
1583 }
1584 }
1585 //
1586 // boot priority always starts at 0
1587 //
1588 Priority = 0;
1589 if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) {
1590 //
1591 // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.
1592 //
1593 DevType = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType;
1594 Status = BdsSetBootPriority4SameTypeDev (
1595 DevType,
1596 LocalBbsTable,
1597 &Priority
1598 );
1599 if (EFI_ERROR (Status)) {
1600 return Status;
1601 }
1602 }
1603 //
1604 // we have to set the boot priority for other BBS entries with different device types
1605 //
1606 BootOrder = (UINT16 *) BdsLibGetVariableAndSize (
1607 L"BootOrder",
1608 &gEfiGlobalVariableGuid,
1609 &BootOrderSize
1610 );
1611 for (Index = 0; ((BootOrder != NULL) && (Index < BootOrderSize / sizeof (UINT16))); Index++) {
1612 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
1613 BootOptionVar = BdsLibGetVariableAndSize (
1614 BootOption,
1615 &gEfiGlobalVariableGuid,
1616 &BootOptionSize
1617 );
1618 if (NULL == BootOptionVar) {
1619 continue;
1620 }
1621
1622 Ptr = BootOptionVar;
1623
1624 Ptr += sizeof (UINT32);
1625 DevPathLen = *(UINT16 *) Ptr;
1626 Ptr += sizeof (UINT16);
1627 Ptr += StrSize ((UINT16 *) Ptr);
1628 DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
1629 if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {
1630 FreePool (BootOptionVar);
1631 continue;
1632 }
1633
1634 Ptr += DevPathLen;
1635 if (DevType == ((BBS_TABLE *) Ptr)->DeviceType) {
1636 //
1637 // We don't want to process twice for a device type
1638 //
1639 FreePool (BootOptionVar);
1640 continue;
1641 }
1642
1643 Status = BdsSetBootPriority4SameTypeDev (
1644 ((BBS_TABLE *) Ptr)->DeviceType,
1645 LocalBbsTable,
1646 &Priority
1647 );
1648 FreePool (BootOptionVar);
1649 if (EFI_ERROR (Status)) {
1650 break;
1651 }
1652 }
1653
1654 if (BootOrder != NULL) {
1655 FreePool (BootOrder);
1656 }
1657
1658 DEBUG_CODE_BEGIN();
1659 PrintBbsTable (LocalBbsTable);
1660 DEBUG_CODE_END();
1661
1662 return Status;
1663 }