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