]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c
Remove SafeFreePool from MemoryAllocationLib as this API's name is misleading. Its...
[mirror_edk2.git] / MdeModulePkg / 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 SafeFreePool (Buffer);
328 Buffer = NULL;
329
330 NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));
331 if (NULL == NewBootOrderList) {
332 FreePool (NewBbsDevPathNode);
333 FreePool (CurrentBbsDevPath);
334 return EFI_OUT_OF_RESOURCES;
335 }
336
337 if (NULL != *BootOrderList) {
338 CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);
339 }
340
341 SafeFreePool (*BootOrderList);
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 SafeFreePool (BootOrder);
466 return EFI_OUT_OF_RESOURCES;
467 }
468
469 //
470 // Skip Non-Legacy boot options
471 //
472 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {
473 SafeFreePool (BootOptionVar);
474 Index++;
475 continue;
476 }
477
478 //
479 // Check if BBS Description String is changed
480 //
481 DescStringMatch = FALSE;
482
483 BdsBuildLegacyDevNameString (
484 &LocalBbsTable[BbsIndex],
485 BbsIndex,
486 sizeof(BootDesc),
487 BootDesc
488 );
489
490 if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {
491 DescStringMatch = TRUE;
492 }
493
494 if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||
495 (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&
496 (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&
497 DescStringMatch) {
498 Index++;
499 continue;
500 }
501
502 SafeFreePool (BootOptionVar);
503 //
504 // should delete
505 //
506 BdsDeleteBootOption (
507 BootOrder[Index],
508 BootOrder,
509 &BootOrderSize
510 );
511 }
512
513 //
514 // Adjust the number of boot options.
515 //
516 if (BootOrderSize != 0) {
517 Status = gRT->SetVariable (
518 L"BootOrder",
519 &gEfiGlobalVariableGuid,
520 VAR_FLAG,
521 BootOrderSize,
522 BootOrder
523 );
524 } else {
525 EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
526 }
527
528 SafeFreePool (BootOrder);
529
530 return Status;
531 }
532
533 /**
534 Find all legacy boot option by device type.
535
536 @param BootOrder The boot order array.
537 @param BootOptionNum The number of boot option.
538 @param DevType Device type.
539 @param Attribute The boot option attribute.
540 @param BbsIndex The BBS table index.
541 @param OptionNumber The boot option index.
542
543 @retval TRUE The Legacy boot option is found.
544 @retval FALSE The legacy boot option is not found.
545
546 **/
547 BOOLEAN
548 BdsFindLegacyBootOptionByDevType (
549 IN UINT16 *BootOrder,
550 IN UINTN BootOptionNum,
551 IN UINT16 DevType,
552 OUT UINT32 *Attribute,
553 OUT UINT16 *BbsIndex,
554 OUT UINTN *OptionNumber
555 )
556 {
557 UINTN Index;
558 UINTN BootOrderIndex;
559 UINT16 BootOption[100];
560 UINTN BootOptionSize;
561 UINT8 *BootOptionVar;
562 BBS_TABLE *BbsEntry;
563 BOOLEAN Found;
564
565 BbsEntry = NULL;
566 Found = FALSE;
567
568 if (NULL == BootOrder) {
569 return Found;
570 }
571
572 //
573 // Loop all boot option from variable
574 //
575 for (BootOrderIndex = 0; BootOrderIndex < BootOptionNum; BootOrderIndex++) {
576 Index = (UINTN) BootOrder[BootOrderIndex];
577 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", Index);
578 BootOptionVar = BdsLibGetVariableAndSize (
579 BootOption,
580 &gEfiGlobalVariableGuid,
581 &BootOptionSize
582 );
583 if (NULL == BootOptionVar) {
584 continue;
585 }
586
587 //
588 // Skip Non-legacy boot option
589 //
590 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {
591 SafeFreePool (BootOptionVar);
592 continue;
593 }
594
595 if (BbsEntry->DeviceType != DevType) {
596 SafeFreePool (BootOptionVar);
597 continue;
598 }
599
600 *Attribute = *(UINT32 *) BootOptionVar;
601 *OptionNumber = Index;
602 Found = TRUE;
603 SafeFreePool (BootOptionVar);
604 break;
605 }
606
607 return Found;
608 }
609
610 /**
611 Create a legacy boot option.
612
613 @param BbsItem The BBS Table entry.
614 @param Index Index of the specified entry in BBS table.
615 @param BootOrderList The boot order list.
616 @param BootOrderListSize The size of boot order list.
617
618 @retval EFI_OUT_OF_RESOURCE No enough memory.
619 @retval EFI_SUCCESS The function complete successfully.
620 @return Other value if the legacy boot option is not created.
621
622 **/
623 EFI_STATUS
624 BdsCreateOneLegacyBootOption (
625 IN BBS_TABLE *BbsItem,
626 IN UINTN Index,
627 IN OUT UINT16 **BootOrderList,
628 IN OUT UINTN *BootOrderListSize
629 )
630 {
631 BBS_BBS_DEVICE_PATH BbsDevPathNode;
632 EFI_STATUS Status;
633 EFI_DEVICE_PATH_PROTOCOL *DevPath;
634
635 DevPath = NULL;
636
637 //
638 // Create device path node.
639 //
640 BbsDevPathNode.Header.Type = BBS_DEVICE_PATH;
641 BbsDevPathNode.Header.SubType = BBS_BBS_DP;
642 SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
643 BbsDevPathNode.DeviceType = BbsItem->DeviceType;
644 CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));
645
646 DevPath = AppendDevicePathNode (
647 EndDevicePath,
648 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode
649 );
650 if (NULL == DevPath) {
651 return EFI_OUT_OF_RESOURCES;
652 }
653
654 Status = BdsCreateLegacyBootOption (
655 BbsItem,
656 DevPath,
657 Index,
658 BootOrderList,
659 BootOrderListSize
660 );
661 BbsItem->BootPriority = 0x00;
662
663 FreePool (DevPath);
664
665 return Status;
666 }
667
668 /**
669
670 Add the legacy boot options from BBS table if they do not exist.
671
672 @retval EFI_SUCCESS The boot options are added successfully
673 or they are already in boot options.
674
675 **/
676 EFI_STATUS
677 BdsAddNonExistingLegacyBootOptions (
678 VOID
679 )
680 {
681 UINT16 *BootOrder;
682 UINTN BootOrderSize;
683 EFI_STATUS Status;
684 UINT16 HddCount;
685 UINT16 BbsCount;
686 HDD_INFO *LocalHddInfo;
687 BBS_TABLE *LocalBbsTable;
688 UINT16 BbsIndex;
689 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
690 UINTN Index;
691 UINT32 Attribute;
692 UINTN OptionNumber;
693 BOOLEAN Ret;
694
695 BootOrder = NULL;
696 HddCount = 0;
697 BbsCount = 0;
698 LocalHddInfo = NULL;
699 LocalBbsTable = NULL;
700
701 Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
702 if (EFI_ERROR (Status)) {
703 return Status;
704 }
705
706 LegacyBios->GetBbsInfo (
707 LegacyBios,
708 &HddCount,
709 &LocalHddInfo,
710 &BbsCount,
711 &LocalBbsTable
712 );
713
714 BootOrder = BdsLibGetVariableAndSize (
715 L"BootOrder",
716 &gEfiGlobalVariableGuid,
717 &BootOrderSize
718 );
719 if (NULL == BootOrder) {
720 BootOrderSize = 0;
721 }
722
723 for (Index = 0; Index < BbsCount; Index++) {
724 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
725 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
726 ) {
727 continue;
728 }
729
730 Ret = BdsFindLegacyBootOptionByDevType (
731 BootOrder,
732 BootOrderSize / sizeof (UINT16),
733 LocalBbsTable[Index].DeviceType,
734 &Attribute,
735 &BbsIndex,
736 &OptionNumber
737 );
738 if (Ret) {
739 continue;
740 }
741
742 //
743 // Not found such type of legacy device in boot options or we found but it's disabled
744 // so we have to create one and put it to the tail of boot order list
745 //
746 Status = BdsCreateOneLegacyBootOption (
747 &LocalBbsTable[Index],
748 Index,
749 &BootOrder,
750 &BootOrderSize
751 );
752 if (EFI_ERROR (Status)) {
753 break;
754 }
755 }
756
757 if (BootOrderSize > 0) {
758 Status = gRT->SetVariable (
759 L"BootOrder",
760 &gEfiGlobalVariableGuid,
761 VAR_FLAG,
762 BootOrderSize,
763 BootOrder
764 );
765 } else {
766 EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
767 }
768
769 if (BootOrder != NULL) {
770 SafeFreePool (BootOrder);
771 }
772
773 return Status;
774 }
775
776 /**
777 Fill the device order buffer.
778
779 @param BbsTable The BBS table.
780 @param BbsType The BBS Type.
781 @param BbsCount The BBS Count.
782 @param Buf device order buffer.
783
784 @return The device order buffer.
785
786 **/
787 UINT16 *
788 BdsFillDevOrderBuf (
789 IN BBS_TABLE *BbsTable,
790 IN BBS_TYPE BbsType,
791 IN UINTN BbsCount,
792 OUT UINT16 *Buf
793 )
794 {
795 UINTN Index;
796
797 for (Index = 0; Index < BbsCount; Index++) {
798 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
799 continue;
800 }
801
802 if (BbsTable[Index].DeviceType != BbsType) {
803 continue;
804 }
805
806 *Buf = (UINT16) (Index & 0xFF);
807 Buf++;
808 }
809
810 return Buf;
811 }
812
813 /**
814 Create the device order buffer.
815
816 @param BbsTable The BBS table.
817 @param BbsCount The BBS Count.
818
819 @retval EFI_SUCCES The buffer is created and the EFI variable named
820 VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is
821 set correctly.
822 @return Other value if the set of EFI variable fails. Check gRT->SetVariable
823 for detailed information.
824
825 **/
826 EFI_STATUS
827 BdsCreateDevOrder (
828 IN BBS_TABLE *BbsTable,
829 IN UINT16 BbsCount
830 )
831 {
832 UINTN Index;
833 UINTN FDCount;
834 UINTN HDCount;
835 UINTN CDCount;
836 UINTN NETCount;
837 UINTN BEVCount;
838 UINTN TotalSize;
839 UINTN HeaderSize;
840 UINT8 *DevOrder;
841 UINT8 *Ptr;
842 EFI_STATUS Status;
843
844 FDCount = 0;
845 HDCount = 0;
846 CDCount = 0;
847 NETCount = 0;
848 BEVCount = 0;
849 TotalSize = 0;
850 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
851 DevOrder = NULL;
852 Ptr = NULL;
853 Status = EFI_SUCCESS;
854
855 //
856 // Count all boot devices
857 //
858 for (Index = 0; Index < BbsCount; Index++) {
859 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
860 continue;
861 }
862
863 switch (BbsTable[Index].DeviceType) {
864 case BBS_FLOPPY:
865 FDCount++;
866 break;
867
868 case BBS_HARDDISK:
869 HDCount++;
870 break;
871
872 case BBS_CDROM:
873 CDCount++;
874 break;
875
876 case BBS_EMBED_NETWORK:
877 NETCount++;
878 break;
879
880 case BBS_BEV_DEVICE:
881 BEVCount++;
882 break;
883
884 default:
885 break;
886 }
887 }
888
889 TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
890 TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
891 TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
892 TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
893 TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
894
895 //
896 // Create buffer to hold all boot device order
897 //
898 DevOrder = AllocateZeroPool (TotalSize);
899 if (NULL == DevOrder) {
900 return EFI_OUT_OF_RESOURCES;
901 }
902
903 Ptr = DevOrder;
904
905 *((BBS_TYPE *) Ptr) = BBS_FLOPPY;
906 Ptr += sizeof (BBS_TYPE);
907 *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
908 Ptr += sizeof (UINT16);
909 if (FDCount != 0) {
910 Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, (UINT16 *) Ptr);
911 }
912
913 *((BBS_TYPE *) Ptr) = BBS_HARDDISK;
914 Ptr += sizeof (BBS_TYPE);
915 *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
916 Ptr += sizeof (UINT16);
917 if (HDCount != 0) {
918 Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, (UINT16 *) Ptr);
919 }
920
921 *((BBS_TYPE *) Ptr) = BBS_CDROM;
922 Ptr += sizeof (BBS_TYPE);
923 *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
924 Ptr += sizeof (UINT16);
925 if (CDCount != 0) {
926 Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, (UINT16 *) Ptr);
927 }
928
929 *((BBS_TYPE *) Ptr) = BBS_EMBED_NETWORK;
930 Ptr += sizeof (BBS_TYPE);
931 *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
932 Ptr += sizeof (UINT16);
933 if (NETCount != 0) {
934 Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, (UINT16 *) Ptr);
935 }
936
937 *((BBS_TYPE *) Ptr) = BBS_BEV_DEVICE;
938 Ptr += sizeof (BBS_TYPE);
939 *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
940 Ptr += sizeof (UINT16);
941 if (BEVCount != 0) {
942 Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, (UINT16 *) Ptr);
943 }
944
945 //
946 // Save device order for legacy boot device to variable.
947 //
948 Status = gRT->SetVariable (
949 VAR_LEGACY_DEV_ORDER,
950 &EfiLegacyDevOrderGuid,
951 VAR_FLAG,
952 TotalSize,
953 DevOrder
954 );
955 SafeFreePool (DevOrder);
956
957 return Status;
958 }
959
960 /**
961
962 Add the legacy boot devices from BBS table into
963 the legacy device boot order.
964
965 @retval EFI_SUCCESS The boot devices are added successfully.
966
967 **/
968 EFI_STATUS
969 BdsUpdateLegacyDevOrder (
970 VOID
971 )
972 {
973 UINT8 *DevOrder;
974 UINT8 *NewDevOrder;
975 UINTN DevOrderSize;
976 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
977 EFI_STATUS Status;
978 UINT16 HddCount;
979 UINT16 BbsCount;
980 HDD_INFO *LocalHddInfo;
981 BBS_TABLE *LocalBbsTable;
982 UINTN Index;
983 UINTN Index2;
984 UINTN *Idx;
985 UINTN FDCount;
986 UINTN HDCount;
987 UINTN CDCount;
988 UINTN NETCount;
989 UINTN BEVCount;
990 UINTN TotalSize;
991 UINTN HeaderSize;
992 UINT8 *Ptr;
993 UINT8 *NewPtr;
994 UINT16 *NewFDPtr;
995 UINT16 *NewHDPtr;
996 UINT16 *NewCDPtr;
997 UINT16 *NewNETPtr;
998 UINT16 *NewBEVPtr;
999 UINT16 *NewDevPtr;
1000 UINT16 Length;
1001 UINT16 Tmp;
1002 UINTN FDIndex;
1003 UINTN HDIndex;
1004 UINTN CDIndex;
1005 UINTN NETIndex;
1006 UINTN BEVIndex;
1007
1008 LocalHddInfo = NULL;
1009 LocalBbsTable = NULL;
1010 Idx = NULL;
1011 FDCount = 0;
1012 HDCount = 0;
1013 CDCount = 0;
1014 NETCount = 0;
1015 BEVCount = 0;
1016 TotalSize = 0;
1017 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
1018 FDIndex = 0;
1019 HDIndex = 0;
1020 CDIndex = 0;
1021 NETIndex = 0;
1022 BEVIndex = 0;
1023 NewDevPtr = NULL;
1024
1025 Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
1026 if (EFI_ERROR (Status)) {
1027 return Status;
1028 }
1029
1030 LegacyBios->GetBbsInfo (
1031 LegacyBios,
1032 &HddCount,
1033 &LocalHddInfo,
1034 &BbsCount,
1035 &LocalBbsTable
1036 );
1037
1038 DevOrder = (UINT8 *) BdsLibGetVariableAndSize (
1039 VAR_LEGACY_DEV_ORDER,
1040 &EfiLegacyDevOrderGuid,
1041 &DevOrderSize
1042 );
1043 if (NULL == DevOrder) {
1044 return BdsCreateDevOrder (LocalBbsTable, BbsCount);
1045 }
1046 //
1047 // First we figure out how many boot devices with same device type respectively
1048 //
1049 for (Index = 0; Index < BbsCount; Index++) {
1050 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
1051 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
1052 ) {
1053 continue;
1054 }
1055
1056 switch (LocalBbsTable[Index].DeviceType) {
1057 case BBS_FLOPPY:
1058 FDCount++;
1059 break;
1060
1061 case BBS_HARDDISK:
1062 HDCount++;
1063 break;
1064
1065 case BBS_CDROM:
1066 CDCount++;
1067 break;
1068
1069 case BBS_EMBED_NETWORK:
1070 NETCount++;
1071 break;
1072
1073 case BBS_BEV_DEVICE:
1074 BEVCount++;
1075 break;
1076
1077 default:
1078 break;
1079 }
1080 }
1081
1082 TotalSize += (HeaderSize + FDCount * sizeof (UINT16));
1083 TotalSize += (HeaderSize + HDCount * sizeof (UINT16));
1084 TotalSize += (HeaderSize + CDCount * sizeof (UINT16));
1085 TotalSize += (HeaderSize + NETCount * sizeof (UINT16));
1086 TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));
1087
1088 NewDevOrder = AllocateZeroPool (TotalSize);
1089 if (NULL == NewDevOrder) {
1090 return EFI_OUT_OF_RESOURCES;
1091 }
1092
1093 NewFDPtr = (UINT16 *) (NewDevOrder + HeaderSize);
1094 NewHDPtr = (UINT16 *) ((UINT8 *) NewFDPtr + FDCount * sizeof (UINT16) + HeaderSize);
1095 NewCDPtr = (UINT16 *) ((UINT8 *) NewHDPtr + HDCount * sizeof (UINT16) + HeaderSize);
1096 NewNETPtr = (UINT16 *) ((UINT8 *) NewCDPtr + CDCount * sizeof (UINT16) + HeaderSize);
1097 NewBEVPtr = (UINT16 *) ((UINT8 *) NewNETPtr + NETCount * sizeof (UINT16) + HeaderSize);
1098
1099 //
1100 // copy FD
1101 //
1102 Ptr = DevOrder;
1103 NewPtr = NewDevOrder;
1104 *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
1105 Ptr += sizeof (BBS_TYPE);
1106 NewPtr += sizeof (BBS_TYPE);
1107 Length = *((UINT16 *) Ptr);
1108 *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
1109 Ptr += sizeof (UINT16);
1110
1111 for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
1112 if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
1113 LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1114 LocalBbsTable[*Ptr].DeviceType != BBS_FLOPPY
1115 ) {
1116 Ptr += sizeof (UINT16);
1117 continue;
1118 }
1119
1120 NewFDPtr[FDIndex] = *(UINT16 *) Ptr;
1121 FDIndex++;
1122 Ptr += sizeof (UINT16);
1123 }
1124 //
1125 // copy HD
1126 //
1127 NewPtr = (UINT8 *) NewHDPtr - HeaderSize;
1128 *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
1129 Ptr += sizeof (BBS_TYPE);
1130 NewPtr += sizeof (BBS_TYPE);
1131 Length = *((UINT16 *) Ptr);
1132 *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
1133 Ptr += sizeof (UINT16);
1134
1135 for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
1136 if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
1137 LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1138 LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
1139 LocalBbsTable[*Ptr].DeviceType != BBS_HARDDISK
1140 ) {
1141 Ptr += sizeof (UINT16);
1142 continue;
1143 }
1144
1145 NewHDPtr[HDIndex] = *(UINT16 *) Ptr;
1146 HDIndex++;
1147 Ptr += sizeof (UINT16);
1148 }
1149 //
1150 // copy CD
1151 //
1152 NewPtr = (UINT8 *) NewCDPtr - HeaderSize;
1153 *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
1154 Ptr += sizeof (BBS_TYPE);
1155 NewPtr += sizeof (BBS_TYPE);
1156 Length = *((UINT16 *) Ptr);
1157 *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
1158 Ptr += sizeof (UINT16);
1159
1160 for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
1161 if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
1162 LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1163 LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
1164 LocalBbsTable[*Ptr].DeviceType != BBS_CDROM
1165 ) {
1166 Ptr += sizeof (UINT16);
1167 continue;
1168 }
1169
1170 NewCDPtr[CDIndex] = *(UINT16 *) Ptr;
1171 CDIndex++;
1172 Ptr += sizeof (UINT16);
1173 }
1174 //
1175 // copy NET
1176 //
1177 NewPtr = (UINT8 *) NewNETPtr - HeaderSize;
1178 *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
1179 Ptr += sizeof (BBS_TYPE);
1180 NewPtr += sizeof (BBS_TYPE);
1181 Length = *((UINT16 *) Ptr);
1182 *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
1183 Ptr += sizeof (UINT16);
1184
1185 for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
1186 if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
1187 LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1188 LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
1189 LocalBbsTable[*Ptr].DeviceType != BBS_EMBED_NETWORK
1190 ) {
1191 Ptr += sizeof (UINT16);
1192 continue;
1193 }
1194
1195 NewNETPtr[NETIndex] = *(UINT16 *) Ptr;
1196 NETIndex++;
1197 Ptr += sizeof (UINT16);
1198 }
1199 //
1200 // copy BEV
1201 //
1202 NewPtr = (UINT8 *) NewBEVPtr - HeaderSize;
1203 *((BBS_TYPE *) NewPtr) = *((BBS_TYPE *) Ptr);
1204 Ptr += sizeof (BBS_TYPE);
1205 NewPtr += sizeof (BBS_TYPE);
1206 Length = *((UINT16 *) Ptr);
1207 *((UINT16 *) NewPtr) = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
1208 Ptr += sizeof (UINT16);
1209
1210 for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {
1211 if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||
1212 LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||
1213 LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||
1214 LocalBbsTable[*Ptr].DeviceType != BBS_BEV_DEVICE
1215 ) {
1216 Ptr += sizeof (UINT16);
1217 continue;
1218 }
1219
1220 NewBEVPtr[BEVIndex] = *(UINT16 *) Ptr;
1221 BEVIndex++;
1222 Ptr += sizeof (UINT16);
1223 }
1224
1225 for (Index = 0; Index < BbsCount; Index++) {
1226 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
1227 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
1228 ) {
1229 continue;
1230 }
1231
1232 switch (LocalBbsTable[Index].DeviceType) {
1233 case BBS_FLOPPY:
1234 Idx = &FDIndex;
1235 NewDevPtr = NewFDPtr;
1236 break;
1237
1238 case BBS_HARDDISK:
1239 Idx = &HDIndex;
1240 NewDevPtr = NewHDPtr;
1241 break;
1242
1243 case BBS_CDROM:
1244 Idx = &CDIndex;
1245 NewDevPtr = NewCDPtr;
1246 break;
1247
1248 case BBS_EMBED_NETWORK:
1249 Idx = &NETIndex;
1250 NewDevPtr = NewNETPtr;
1251 break;
1252
1253 case BBS_BEV_DEVICE:
1254 Idx = &BEVIndex;
1255 NewDevPtr = NewBEVPtr;
1256 break;
1257
1258 default:
1259 Idx = NULL;
1260 break;
1261 }
1262 //
1263 // at this point we have copied those valid indexes to new buffer
1264 // and we should check if there is any new appeared boot device
1265 //
1266 if (Idx != 0) {
1267 for (Index2 = 0; Index2 < *Idx; Index2++) {
1268 if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {
1269 break;
1270 }
1271 }
1272
1273 if (Index2 == *Idx) {
1274 //
1275 // Index2 == *Idx means we didn't find Index
1276 // so Index is a new appeared device's index in BBS table
1277 // save it.
1278 //
1279 NewDevPtr[*Idx] = (UINT16) (Index & 0xFF);
1280 (*Idx)++;
1281 }
1282 }
1283 }
1284
1285 if (FDCount != 0) {
1286 //
1287 // Just to make sure that disabled indexes are all at the end of the array
1288 //
1289 for (Index = 0; Index < FDIndex - 1; Index++) {
1290 if (0xFF00 != (NewFDPtr[Index] & 0xFF00)) {
1291 continue;
1292 }
1293
1294 for (Index2 = Index + 1; Index2 < FDIndex; Index2++) {
1295 if (0 == (NewFDPtr[Index2] & 0xFF00)) {
1296 Tmp = NewFDPtr[Index];
1297 NewFDPtr[Index] = NewFDPtr[Index2];
1298 NewFDPtr[Index2] = Tmp;
1299 break;
1300 }
1301 }
1302 }
1303 }
1304
1305 if (HDCount != 0) {
1306 //
1307 // Just to make sure that disabled indexes are all at the end of the array
1308 //
1309 for (Index = 0; Index < HDIndex - 1; Index++) {
1310 if (0xFF00 != (NewHDPtr[Index] & 0xFF00)) {
1311 continue;
1312 }
1313
1314 for (Index2 = Index + 1; Index2 < HDIndex; Index2++) {
1315 if (0 == (NewHDPtr[Index2] & 0xFF00)) {
1316 Tmp = NewHDPtr[Index];
1317 NewHDPtr[Index] = NewHDPtr[Index2];
1318 NewHDPtr[Index2] = Tmp;
1319 break;
1320 }
1321 }
1322 }
1323 }
1324
1325 if (CDCount != 0) {
1326 //
1327 // Just to make sure that disabled indexes are all at the end of the array
1328 //
1329 for (Index = 0; Index < CDIndex - 1; Index++) {
1330 if (0xFF00 != (NewCDPtr[Index] & 0xFF00)) {
1331 continue;
1332 }
1333
1334 for (Index2 = Index + 1; Index2 < CDIndex; Index2++) {
1335 if (0 == (NewCDPtr[Index2] & 0xFF00)) {
1336 Tmp = NewCDPtr[Index];
1337 NewCDPtr[Index] = NewCDPtr[Index2];
1338 NewCDPtr[Index2] = Tmp;
1339 break;
1340 }
1341 }
1342 }
1343 }
1344
1345 if (NETCount != 0) {
1346 //
1347 // Just to make sure that disabled indexes are all at the end of the array
1348 //
1349 for (Index = 0; Index < NETIndex - 1; Index++) {
1350 if (0xFF00 != (NewNETPtr[Index] & 0xFF00)) {
1351 continue;
1352 }
1353
1354 for (Index2 = Index + 1; Index2 < NETIndex; Index2++) {
1355 if (0 == (NewNETPtr[Index2] & 0xFF00)) {
1356 Tmp = NewNETPtr[Index];
1357 NewNETPtr[Index] = NewNETPtr[Index2];
1358 NewNETPtr[Index2] = Tmp;
1359 break;
1360 }
1361 }
1362 }
1363 }
1364
1365 if (BEVCount!= 0) {
1366 //
1367 // Just to make sure that disabled indexes are all at the end of the array
1368 //
1369 for (Index = 0; Index < BEVIndex - 1; Index++) {
1370 if (0xFF00 != (NewBEVPtr[Index] & 0xFF00)) {
1371 continue;
1372 }
1373
1374 for (Index2 = Index + 1; Index2 < BEVIndex; Index2++) {
1375 if (0 == (NewBEVPtr[Index2] & 0xFF00)) {
1376 Tmp = NewBEVPtr[Index];
1377 NewBEVPtr[Index] = NewBEVPtr[Index2];
1378 NewBEVPtr[Index2] = Tmp;
1379 break;
1380 }
1381 }
1382 }
1383 }
1384
1385 SafeFreePool (DevOrder);
1386
1387 Status = gRT->SetVariable (
1388 VAR_LEGACY_DEV_ORDER,
1389 &EfiLegacyDevOrderGuid,
1390 VAR_FLAG,
1391 TotalSize,
1392 NewDevOrder
1393 );
1394 SafeFreePool (NewDevOrder);
1395
1396 return Status;
1397 }
1398
1399 /**
1400 Set Boot Priority for specified device type.
1401
1402 @param DeviceType The device type.
1403 @param LocalBbsTable The BBS table.
1404 @param Priority The prority table.
1405
1406 @retval EFI_SUCCESS The function completes successfully.
1407 @retval EFI_NOT_FOUND Failed to find device.
1408
1409 **/
1410 EFI_STATUS
1411 BdsSetBootPriority4SameTypeDev (
1412 IN UINT16 DeviceType,
1413 IN OUT BBS_TABLE *LocalBbsTable,
1414 IN OUT UINT16 *Priority
1415 )
1416 {
1417 UINT8 *DevOrder;
1418
1419 UINT8 *OrigBuffer;
1420 UINT16 *DevIndex;
1421 UINTN DevOrderSize;
1422 UINTN DevCount;
1423 UINTN Index;
1424
1425 DevOrder = BdsLibGetVariableAndSize (
1426 VAR_LEGACY_DEV_ORDER,
1427 &EfiLegacyDevOrderGuid,
1428 &DevOrderSize
1429 );
1430 if (NULL == DevOrder) {
1431 return EFI_OUT_OF_RESOURCES;
1432 }
1433
1434 OrigBuffer = DevOrder;
1435 while (DevOrder < OrigBuffer + DevOrderSize) {
1436 if (DeviceType == * (BBS_TYPE *) DevOrder) {
1437 break;
1438 }
1439
1440 DevOrder += sizeof (BBS_TYPE);
1441 DevOrder += *(UINT16 *) DevOrder;
1442 }
1443
1444 if (DevOrder >= OrigBuffer + DevOrderSize) {
1445 SafeFreePool (OrigBuffer);
1446 return EFI_NOT_FOUND;
1447 }
1448
1449 DevOrder += sizeof (BBS_TYPE);
1450 DevCount = (*((UINT16 *) DevOrder) - sizeof (UINT16)) / sizeof (UINT16);
1451 DevIndex = (UINT16 *) (DevOrder + sizeof (UINT16));
1452 //
1453 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
1454 //
1455 for (Index = 0; Index < DevCount; Index++) {
1456 if ((DevIndex[Index] & 0xFF00) == 0xFF00) {
1457 //
1458 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
1459 //
1460 } else {
1461 LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = *Priority;
1462 (*Priority)++;
1463 }
1464 }
1465
1466 SafeFreePool (OrigBuffer);
1467 return EFI_SUCCESS;
1468 }
1469
1470 /**
1471 Print the BBS Table.
1472
1473 @param LocalBbsTable The BBS table.
1474
1475 **/
1476 VOID
1477 PrintBbsTable (
1478 IN BBS_TABLE *LocalBbsTable
1479 )
1480 {
1481 UINT16 Idx;
1482
1483 DEBUG ((DEBUG_ERROR, "\n"));
1484 DEBUG ((DEBUG_ERROR, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
1485 DEBUG ((DEBUG_ERROR, "=============================================\n"));
1486 for (Idx = 0; Idx < MAX_BBS_ENTRIES; Idx++) {
1487 if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) ||
1488 (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) ||
1489 (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY)
1490 ) {
1491 continue;
1492 }
1493
1494 DEBUG (
1495 (DEBUG_ERROR,
1496 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
1497 (UINTN) Idx,
1498 (UINTN) LocalBbsTable[Idx].BootPriority,
1499 (UINTN) LocalBbsTable[Idx].Bus,
1500 (UINTN) LocalBbsTable[Idx].Device,
1501 (UINTN) LocalBbsTable[Idx].Function,
1502 (UINTN) LocalBbsTable[Idx].Class,
1503 (UINTN) LocalBbsTable[Idx].SubClass,
1504 (UINTN) LocalBbsTable[Idx].DeviceType,
1505 (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,
1506 (UINTN) LocalBbsTable[Idx].BootHandlerSegment,
1507 (UINTN) LocalBbsTable[Idx].BootHandlerOffset,
1508 (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),
1509 (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset))
1510 );
1511 }
1512
1513 DEBUG ((DEBUG_ERROR, "\n"));
1514 }
1515
1516 /**
1517
1518 Set the boot priority for BBS entries based on boot option entry and boot order.
1519
1520 @param Entry The boot option is to be checked for refresh BBS table.
1521
1522 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
1523 @return status of BdsSetBootPriority4SameTypeDev()
1524 **/
1525 EFI_STATUS
1526 BdsRefreshBbsTableForBoot (
1527 IN BDS_COMMON_OPTION *Entry
1528 )
1529 {
1530 EFI_STATUS Status;
1531 UINT16 HddCount;
1532 UINT16 BbsCount;
1533 HDD_INFO *LocalHddInfo;
1534 BBS_TABLE *LocalBbsTable;
1535 UINT16 DevType;
1536 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
1537 UINTN Index;
1538 UINT16 Priority;
1539 UINT16 *BootOrder;
1540 UINTN BootOrderSize;
1541 UINT8 *BootOptionVar;
1542 UINTN BootOptionSize;
1543 UINT16 BootOption[100];
1544 UINT8 *Ptr;
1545 UINT16 DevPathLen;
1546 EFI_DEVICE_PATH_PROTOCOL *DevPath;
1547
1548 HddCount = 0;
1549 BbsCount = 0;
1550 LocalHddInfo = NULL;
1551 LocalBbsTable = NULL;
1552 DevType = BBS_UNKNOWN;
1553
1554 Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
1555 if (EFI_ERROR (Status)) {
1556 return Status;
1557 }
1558
1559 LegacyBios->GetBbsInfo (
1560 LegacyBios,
1561 &HddCount,
1562 &LocalHddInfo,
1563 &BbsCount,
1564 &LocalBbsTable
1565 );
1566 //
1567 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
1568 // We will set them according to the settings setup by user
1569 //
1570 for (Index = 0; Index < BbsCount; Index++) {
1571 if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) ||
1572 (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) ||
1573 (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) {
1574 LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
1575 }
1576 }
1577 //
1578 // boot priority always starts at 0
1579 //
1580 Priority = 0;
1581 if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) {
1582 //
1583 // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.
1584 //
1585 DevType = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType;
1586 Status = BdsSetBootPriority4SameTypeDev (
1587 DevType,
1588 LocalBbsTable,
1589 &Priority
1590 );
1591 if (EFI_ERROR (Status)) {
1592 return Status;
1593 }
1594 }
1595 //
1596 // we have to set the boot priority for other BBS entries with different device types
1597 //
1598 BootOrder = (UINT16 *) BdsLibGetVariableAndSize (
1599 L"BootOrder",
1600 &gEfiGlobalVariableGuid,
1601 &BootOrderSize
1602 );
1603 for (Index = 0; ((BootOrder != NULL) && (Index < BootOrderSize / sizeof (UINT16))); Index++) {
1604 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
1605 BootOptionVar = BdsLibGetVariableAndSize (
1606 BootOption,
1607 &gEfiGlobalVariableGuid,
1608 &BootOptionSize
1609 );
1610 if (NULL == BootOptionVar) {
1611 continue;
1612 }
1613
1614 Ptr = BootOptionVar;
1615
1616 Ptr += sizeof (UINT32);
1617 DevPathLen = *(UINT16 *) Ptr;
1618 Ptr += sizeof (UINT16);
1619 Ptr += StrSize ((UINT16 *) Ptr);
1620 DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
1621 if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {
1622 SafeFreePool (BootOptionVar);
1623 continue;
1624 }
1625
1626 Ptr += DevPathLen;
1627 if (DevType == ((BBS_TABLE *) Ptr)->DeviceType) {
1628 //
1629 // We don't want to process twice for a device type
1630 //
1631 SafeFreePool (BootOptionVar);
1632 continue;
1633 }
1634
1635 Status = BdsSetBootPriority4SameTypeDev (
1636 ((BBS_TABLE *) Ptr)->DeviceType,
1637 LocalBbsTable,
1638 &Priority
1639 );
1640 SafeFreePool (BootOptionVar);
1641 if (EFI_ERROR (Status)) {
1642 break;
1643 }
1644 }
1645
1646 if (BootOrder != NULL) {
1647 SafeFreePool (BootOrder);
1648 }
1649 //
1650 // For debug
1651 //
1652 PrintBbsTable (LocalBbsTable);
1653
1654 return Status;
1655 }