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