]> code.delx.au - refind/blob - EfiLib/legacy.c
4578da0b3105f053efa13c88e37e0b1f29c5757a
[refind] / EfiLib / legacy.c
1 /*
2 * EfiLib/legacy.c
3 * CSM/legacy boot support functions
4 *
5 * Taken from Tianocore source code (mostly IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c)
6 *
7 * Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
8 * This program and the accompanying materials
9 * are licensed and made available under the terms and conditions of the BSD License
10 * which accompanies this distribution. The full text of the license may be found at
11 * http://opensource.org/licenses/bsd-license.php
12 *
13 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 *
16 */
17
18 #include "../include/tiano_includes.h"
19 #include "legacy.h"
20
21 BOOT_OPTION_BBS_MAPPING *mBootOptionBbsMapping = NULL;
22 UINTN mBootOptionBbsMappingCount = 0;
23
24 extern EFI_DEVICE_PATH EndDevicePath[];
25 extern EFI_GUID gEfiLegacyBiosProtocolGuid;
26 EFI_GUID gEfiLegacyDevOrderVariableGuid = { 0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52 }};
27
28 /**
29
30 Translate the first n characters of an Ascii string to
31 Unicode characters. The count n is indicated by parameter
32 Size. If Size is greater than the length of string, then
33 the entire string is translated.
34
35
36 @param AStr Pointer to input Ascii string.
37 @param Size The number of characters to translate.
38 @param UStr Pointer to output Unicode string buffer.
39
40 **/
41 VOID
42 AsciiToUnicodeSize (
43 IN UINT8 *AStr,
44 IN UINTN Size,
45 OUT UINT16 *UStr
46 )
47 {
48 UINTN Idx;
49
50 Idx = 0;
51 while (AStr[Idx] != 0) {
52 UStr[Idx] = (CHAR16) AStr[Idx];
53 if (Idx == Size) {
54 break;
55 }
56
57 Idx++;
58 }
59 UStr[Idx] = 0;
60 }
61
62 /**
63 Build Legacy Device Name String according.
64
65 @param CurBBSEntry BBS Table.
66 @param Index Index.
67 @param BufSize The buffer size.
68 @param BootString The output string.
69
70 **/
71 VOID
72 BdsBuildLegacyDevNameString (
73 IN BBS_TABLE *CurBBSEntry,
74 IN UINTN Index,
75 IN UINTN BufSize,
76 OUT CHAR16 *BootString
77 )
78 {
79 CHAR16 *Fmt;
80 CHAR16 *Type;
81 UINT8 *StringDesc;
82 CHAR16 Temp[80];
83
84 switch (Index) {
85 //
86 // Primary Master
87 //
88 case 1:
89 Fmt = L"Primary Master %s";
90 break;
91
92 //
93 // Primary Slave
94 //
95 case 2:
96 Fmt = L"Primary Slave %s";
97 break;
98
99 //
100 // Secondary Master
101 //
102 case 3:
103 Fmt = L"Secondary Master %s";
104 break;
105
106 //
107 // Secondary Slave
108 //
109 case 4:
110 Fmt = L"Secondary Slave %s";
111 break;
112
113 default:
114 Fmt = L"%s";
115 break;
116 }
117
118 switch (CurBBSEntry->DeviceType) {
119 case BBS_FLOPPY:
120 Type = L"Floppy";
121 break;
122
123 case BBS_HARDDISK:
124 Type = L"Harddisk";
125 break;
126
127 case BBS_CDROM:
128 Type = L"CDROM";
129 break;
130
131 case BBS_PCMCIA:
132 Type = L"PCMCIAe";
133 break;
134
135 case BBS_USB:
136 Type = L"USB";
137 break;
138
139 case BBS_EMBED_NETWORK:
140 Type = L"Network";
141 break;
142
143 case BBS_BEV_DEVICE:
144 Type = L"BEVe";
145 break;
146
147 case BBS_UNKNOWN:
148 default:
149 Type = L"Unknown";
150 break;
151 }
152 //
153 // If current BBS entry has its description then use it.
154 //
155 StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
156 if (NULL != StringDesc) {
157 //
158 // Only get fisrt 32 characters, this is suggested by BBS spec
159 //
160 AsciiToUnicodeSize (StringDesc, 32, Temp);
161 Fmt = L"%s";
162 Type = Temp;
163 }
164
165 //
166 // BbsTable 16 entries are for onboard IDE.
167 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
168 //
169 if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {
170 Fmt = L"%s %d";
171 UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
172 } else {
173 UnicodeSPrint (BootString, BufSize, Fmt, Type);
174 }
175 }
176
177 /**
178 Check if the boot option is a legacy one.
179
180 @param BootOptionVar The boot option data payload.
181 @param BbsEntry The BBS Table.
182 @param BbsIndex The table index.
183
184 @retval TRUE It is a legacy boot option.
185 @retval FALSE It is not a legacy boot option.
186
187 **/
188 BOOLEAN
189 BdsIsLegacyBootOption (
190 IN UINT8 *BootOptionVar,
191 OUT BBS_TABLE **BbsEntry,
192 OUT UINT16 *BbsIndex
193 )
194 {
195 UINT8 *Ptr;
196 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
197 BOOLEAN Ret;
198 UINT16 DevPathLen;
199
200 Ptr = BootOptionVar;
201 Ptr += sizeof (UINT32);
202 DevPathLen = *(UINT16 *) Ptr;
203 Ptr += sizeof (UINT16);
204 Ptr += StrSize ((UINT16 *) Ptr);
205 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
206 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
207 Ptr += DevPathLen;
208 *BbsEntry = (BBS_TABLE *) Ptr;
209 Ptr += sizeof (BBS_TABLE);
210 *BbsIndex = *(UINT16 *) Ptr;
211 Ret = TRUE;
212 } else {
213 *BbsEntry = NULL;
214 Ret = FALSE;
215 }
216
217 return Ret;
218 }
219
220 /**
221 Find all legacy boot option by device type.
222
223 @param BootOrder The boot order array.
224 @param BootOptionNum The number of boot option.
225 @param DevType Device type.
226 @param DevName Device name.
227 @param Attribute The boot option attribute.
228 @param BbsIndex The BBS table index.
229 @param OptionNumber The boot option index.
230
231 @retval TRUE The Legacy boot option is found.
232 @retval FALSE The legacy boot option is not found.
233
234 **/
235 BOOLEAN
236 BdsFindLegacyBootOptionByDevTypeAndName (
237 IN UINT16 *BootOrder,
238 IN UINTN BootOptionNum,
239 IN UINT16 DevType,
240 IN CHAR16 *DevName,
241 OUT UINT32 *Attribute,
242 OUT UINT16 *BbsIndex,
243 OUT UINT16 *OptionNumber
244 )
245 {
246 UINTN Index;
247 CHAR16 BootOption[9];
248 UINTN BootOptionSize;
249 UINT8 *BootOptionVar;
250 BBS_TABLE *BbsEntry;
251 BOOLEAN Found;
252
253 BbsEntry = NULL;
254 Found = FALSE;
255
256 if (NULL == BootOrder) {
257 return Found;
258 }
259
260 //
261 // Loop all boot option from variable
262 //
263 for (Index = 0; Index < BootOptionNum; Index++) {
264 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]);
265 BootOptionVar = BdsLibGetVariableAndSize (
266 BootOption,
267 &gEfiGlobalVariableGuid,
268 &BootOptionSize
269 );
270 if (NULL == BootOptionVar) {
271 continue;
272 }
273
274 //
275 // Skip Non-legacy boot option
276 //
277 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {
278 FreePool (BootOptionVar);
279 continue;
280 }
281
282 if (
283 (BbsEntry->DeviceType != DevType) ||
284 (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0)
285 ) {
286 FreePool (BootOptionVar);
287 continue;
288 }
289
290 *Attribute = *(UINT32 *) BootOptionVar;
291 *OptionNumber = BootOrder[Index];
292 Found = TRUE;
293 FreePool (BootOptionVar);
294 break;
295 }
296
297 return Found;
298 }
299
300 /**
301
302 Create a legacy boot option for the specified entry of
303 BBS table, save it as variable, and append it to the boot
304 order list.
305
306
307 @param CurrentBbsEntry Pointer to current BBS table.
308 @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS
309 @param Index Index of the specified entry in BBS table.
310 @param BootOrderList On input, the original boot order list.
311 On output, the new boot order list attached with the
312 created node.
313 @param BootOrderListSize On input, the original size of boot order list.
314 On output, the size of new boot order list.
315
316 @retval EFI_SUCCESS Boot Option successfully created.
317 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
318 @retval Other Error occurs while setting variable.
319
320 **/
321 EFI_STATUS
322 BdsCreateLegacyBootOption (
323 IN BBS_TABLE *CurrentBbsEntry,
324 IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath,
325 IN UINTN Index,
326 IN OUT UINT16 **BootOrderList,
327 IN OUT UINTN *BootOrderListSize
328 )
329 {
330 EFI_STATUS Status;
331 UINT16 CurrentBootOptionNo;
332 UINT16 BootString[10];
333 CHAR16 BootDesc[100];
334 CHAR8 HelpString[100];
335 UINT16 *NewBootOrderList;
336 UINTN BufferSize;
337 UINTN StringLen;
338 VOID *Buffer;
339 UINT8 *Ptr;
340 UINT16 CurrentBbsDevPathSize;
341 UINTN BootOrderIndex;
342 UINTN BootOrderLastIndex;
343 UINTN ArrayIndex;
344 BOOLEAN IndexNotFound;
345 BBS_BBS_DEVICE_PATH *NewBbsDevPathNode;
346
347 if ((*BootOrderList) == NULL) {
348 CurrentBootOptionNo = 0;
349 } else {
350 for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {
351 IndexNotFound = TRUE;
352 for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {
353 if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {
354 IndexNotFound = FALSE;
355 break;
356 }
357 }
358
359 if (!IndexNotFound) {
360 continue;
361 } else {
362 break;
363 }
364 }
365
366 CurrentBootOptionNo = (UINT16) ArrayIndex;
367 }
368
369 UnicodeSPrint (
370 BootString,
371 sizeof (BootString),
372 L"Boot%04x",
373 CurrentBootOptionNo
374 );
375
376 BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);
377
378 //
379 // Create new BBS device path node with description string
380 //
381 UnicodeStrToAsciiStr (BootDesc, HelpString);
382
383 StringLen = AsciiStrLen (HelpString);
384 NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
385 if (NewBbsDevPathNode == NULL) {
386 return EFI_OUT_OF_RESOURCES;
387 }
388 CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH));
389 CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1);
390 SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
391
392 //
393 // Create entire new CurrentBbsDevPath with end node
394 //
395 CurrentBbsDevPath = AppendDevicePathNode (
396 EndDevicePath,
397 (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode
398 );
399 if (CurrentBbsDevPath == NULL) {
400 FreePool (NewBbsDevPathNode);
401 return EFI_OUT_OF_RESOURCES;
402 }
403
404 CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));
405
406 BufferSize = sizeof (UINT32) +
407 sizeof (UINT16) +
408 StrSize (BootDesc) +
409 CurrentBbsDevPathSize +
410 sizeof (BBS_TABLE) +
411 sizeof (UINT16);
412
413 Buffer = AllocateZeroPool (BufferSize);
414 if (Buffer == NULL) {
415 FreePool (NewBbsDevPathNode);
416 FreePool (CurrentBbsDevPath);
417 return EFI_OUT_OF_RESOURCES;
418 }
419
420 Ptr = (UINT8 *) Buffer;
421
422 *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
423 Ptr += sizeof (UINT32);
424
425 *((UINT16 *) Ptr) = CurrentBbsDevPathSize;
426 Ptr += sizeof (UINT16);
427
428 CopyMem (
429 Ptr,
430 BootDesc,
431 StrSize (BootDesc)
432 );
433 Ptr += StrSize (BootDesc);
434
435 CopyMem (
436 Ptr,
437 CurrentBbsDevPath,
438 CurrentBbsDevPathSize
439 );
440 Ptr += CurrentBbsDevPathSize;
441
442 CopyMem (
443 Ptr,
444 CurrentBbsEntry,
445 sizeof (BBS_TABLE)
446 );
447
448 Ptr += sizeof (BBS_TABLE);
449 *((UINT16 *) Ptr) = (UINT16) Index;
450
451 Status = gRT->SetVariable (
452 BootString,
453 &gEfiGlobalVariableGuid,
454 VAR_FLAG,
455 BufferSize,
456 Buffer
457 );
458
459 FreePool (Buffer);
460
461 Buffer = NULL;
462
463 NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));
464 if (NULL == NewBootOrderList) {
465 FreePool (NewBbsDevPathNode);
466 FreePool (CurrentBbsDevPath);
467 return EFI_OUT_OF_RESOURCES;
468 }
469
470 if (*BootOrderList != NULL) {
471 CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);
472 FreePool (*BootOrderList);
473 }
474
475 BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16));
476 NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo;
477 *BootOrderListSize += sizeof (UINT16);
478 *BootOrderList = NewBootOrderList;
479
480 FreePool (NewBbsDevPathNode);
481 FreePool (CurrentBbsDevPath);
482 return Status;
483 }
484
485 /**
486 Create a legacy boot option.
487
488 @param BbsItem The BBS Table entry.
489 @param Index Index of the specified entry in BBS table.
490 @param BootOrderList The boot order list.
491 @param BootOrderListSize The size of boot order list.
492
493 @retval EFI_OUT_OF_RESOURCE No enough memory.
494 @retval EFI_SUCCESS The function complete successfully.
495 @return Other value if the legacy boot option is not created.
496
497 **/
498 EFI_STATUS
499 BdsCreateOneLegacyBootOption (
500 IN BBS_TABLE *BbsItem,
501 IN UINTN Index,
502 IN OUT UINT16 **BootOrderList,
503 IN OUT UINTN *BootOrderListSize
504 )
505 {
506 BBS_BBS_DEVICE_PATH BbsDevPathNode;
507 EFI_STATUS Status;
508 EFI_DEVICE_PATH_PROTOCOL *DevPath;
509
510 DevPath = NULL;
511
512 //
513 // Create device path node.
514 //
515 BbsDevPathNode.Header.Type = BBS_DEVICE_PATH;
516 BbsDevPathNode.Header.SubType = BBS_BBS_DP;
517 SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
518 BbsDevPathNode.DeviceType = BbsItem->DeviceType;
519 CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));
520
521 DevPath = AppendDevicePathNode (
522 EndDevicePath,
523 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode
524 );
525 if (NULL == DevPath) {
526 return EFI_OUT_OF_RESOURCES;
527 }
528
529 Status = BdsCreateLegacyBootOption (
530 BbsItem,
531 DevPath,
532 Index,
533 BootOrderList,
534 BootOrderListSize
535 );
536 BbsItem->BootPriority = 0x00;
537
538 FreePool (DevPath);
539
540 return Status;
541 }
542
543 /**
544 Group the legacy boot options in the BootOption.
545
546 The routine assumes the boot options in the beginning that covers all the device
547 types are ordered properly and re-position the following boot options just after
548 the corresponding boot options with the same device type.
549 For example:
550 1. Input = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0]
551 Assuming [Harddisk1 CdRom2 Efi1] is ordered properly
552 Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0]
553
554 2. Input = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2]
555 Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly
556 Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2]
557
558 @param BootOption Pointer to buffer containing Boot Option Numbers
559 @param BootOptionCount Count of the Boot Option Numbers
560 **/
561 VOID
562 GroupMultipleLegacyBootOption4SameType (
563 UINT16 *BootOption,
564 UINTN BootOptionCount
565 )
566 {
567 UINTN DeviceTypeIndex[7];
568 UINTN Index;
569 UINTN MappingIndex;
570 UINTN *NextIndex;
571 UINT16 OptionNumber;
572 UINTN DeviceIndex;
573
574 SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xFF);
575
576 for (Index = 0; Index < BootOptionCount; Index++) {
577
578 //
579 // Find the DeviceType
580 //
581 for (MappingIndex = 0; MappingIndex < mBootOptionBbsMappingCount; MappingIndex++) {
582 if (mBootOptionBbsMapping[MappingIndex].BootOptionNumber == BootOption[Index]) {
583 break;
584 }
585 }
586 if (MappingIndex == mBootOptionBbsMappingCount) {
587 //
588 // Is not a legacy boot option
589 //
590 continue;
591 }
592
593 ASSERT ((mBootOptionBbsMapping[MappingIndex].BbsType & 0xF) <
594 sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]));
595 NextIndex = &DeviceTypeIndex[mBootOptionBbsMapping[MappingIndex].BbsType & 0xF];
596 if (*NextIndex == (UINTN) -1) {
597 //
598 // *NextIndex is the index in BootOption to put the next Option Number for the same type
599 //
600 *NextIndex = Index + 1;
601 } else {
602 //
603 // insert the current boot option before *NextIndex, causing [*Next .. Index] shift right one position
604 //
605 OptionNumber = BootOption[Index];
606 CopyMem (&BootOption[*NextIndex + 1], &BootOption[*NextIndex], (Index - *NextIndex) * sizeof (UINT16));
607 BootOption[*NextIndex] = OptionNumber;
608
609 //
610 // Update the DeviceTypeIndex array to reflect the right shift operation
611 //
612 for (DeviceIndex = 0; DeviceIndex < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]); DeviceIndex++) {
613 if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) {
614 DeviceTypeIndex[DeviceIndex]++;
615 }
616 }
617 }
618 }
619 }
620
621 /**
622 Function returns the value of the specified variable.
623
624
625 @param Name A Null-terminated Unicode string that is
626 the name of the vendor's variable.
627 @param VendorGuid A unique identifier for the vendor.
628
629 @return The payload of the variable.
630 @retval NULL If the variable can't be read.
631
632 **/
633 VOID *
634 EfiLibGetVariable (
635 IN CHAR16 *Name,
636 IN EFI_GUID *VendorGuid
637 )
638 {
639 UINTN VarSize;
640
641 return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize);
642 }
643
644 /**
645 Function deletes the variable specified by VarName and VarGuid.
646
647 @param VarName A Null-terminated Unicode string that is
648 the name of the vendor's variable.
649
650 @param VarGuid A unique identifier for the vendor.
651
652 @retval EFI_SUCCESS The variable was found and removed
653 @retval EFI_UNSUPPORTED The variable store was inaccessible
654 @retval EFI_OUT_OF_RESOURCES The temporary buffer was not available
655 @retval EFI_NOT_FOUND The variable was not found
656
657 **/
658 EFI_STATUS
659 EfiLibDeleteVariable (
660 IN CHAR16 *VarName,
661 IN EFI_GUID *VarGuid
662 )
663 {
664 VOID *VarBuf;
665 EFI_STATUS Status;
666
667 VarBuf = EfiLibGetVariable (VarName, VarGuid);
668 Status = EFI_NOT_FOUND;
669
670 if (VarBuf != NULL) {
671 //
672 // Delete variable from Storage
673 //
674 Status = gRT->SetVariable (VarName, VarGuid, VAR_FLAG, 0, NULL);
675 ASSERT (!EFI_ERROR (Status));
676 FreePool (VarBuf);
677 }
678
679 return Status;
680 }
681
682 /**
683 Add the legacy boot options from BBS table if they do not exist.
684
685 @retval EFI_SUCCESS The boot options are added successfully
686 or they are already in boot options.
687 @retval EFI_NOT_FOUND No legacy boot options is found.
688 @retval EFI_OUT_OF_RESOURCE No enough memory.
689 @return Other value LegacyBoot options are not added.
690 **/
691 EFI_STATUS
692 EFIAPI
693 BdsAddNonExistingLegacyBootOptions (
694 VOID
695 )
696 {
697 UINT16 *BootOrder;
698 UINTN BootOrderSize;
699 EFI_STATUS Status;
700 CHAR16 Desc[100];
701 UINT16 HddCount;
702 UINT16 BbsCount;
703 HDD_INFO *LocalHddInfo;
704 BBS_TABLE *LocalBbsTable;
705 UINT16 BbsIndex;
706 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
707 UINT16 Index;
708 UINT32 Attribute;
709 UINT16 OptionNumber;
710 BOOLEAN Exist;
711
712 HddCount = 0;
713 BbsCount = 0;
714 LocalHddInfo = NULL;
715 LocalBbsTable = NULL;
716
717 Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
718 if (EFI_ERROR (Status)) {
719 return Status;
720 }
721
722 if (mBootOptionBbsMapping != NULL) {
723 FreePool (mBootOptionBbsMapping);
724
725 mBootOptionBbsMapping = NULL;
726 mBootOptionBbsMappingCount = 0;
727 }
728
729 LegacyBios->GetBbsInfo (
730 LegacyBios,
731 &HddCount,
732 &LocalHddInfo,
733 &BbsCount,
734 &LocalBbsTable
735 );
736
737 BootOrder = BdsLibGetVariableAndSize (
738 L"BootOrder",
739 &gEfiGlobalVariableGuid,
740 &BootOrderSize
741 );
742 if (BootOrder == NULL) {
743 BootOrderSize = 0;
744 }
745
746 for (Index = 0; Index < BbsCount; Index++) {
747 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
748 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
749 ) {
750 continue;
751 }
752
753 BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc);
754
755 Exist = BdsFindLegacyBootOptionByDevTypeAndName (
756 BootOrder,
757 BootOrderSize / sizeof (UINT16),
758 LocalBbsTable[Index].DeviceType,
759 Desc,
760 &Attribute,
761 &BbsIndex,
762 &OptionNumber
763 );
764 if (!Exist) {
765 //
766 // Not found such type of legacy device in boot options or we found but it's disabled
767 // so we have to create one and put it to the tail of boot order list
768 //
769 Status = BdsCreateOneLegacyBootOption (
770 &LocalBbsTable[Index],
771 Index,
772 &BootOrder,
773 &BootOrderSize
774 );
775 if (EFI_ERROR (Status)) {
776 break;
777 }
778 BbsIndex = Index;
779 OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1];
780 }
781
782 ASSERT (BbsIndex == Index);
783 //
784 // Save the BbsIndex
785 //
786 mBootOptionBbsMapping = ReallocatePool (
787 mBootOptionBbsMappingCount * sizeof (BOOT_OPTION_BBS_MAPPING),
788 (mBootOptionBbsMappingCount + 1) * sizeof (BOOT_OPTION_BBS_MAPPING),
789 mBootOptionBbsMapping
790 );
791 ASSERT (mBootOptionBbsMapping != NULL);
792 mBootOptionBbsMapping[mBootOptionBbsMappingCount].BootOptionNumber = OptionNumber;
793 mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsIndex = Index;
794 mBootOptionBbsMapping[mBootOptionBbsMappingCount].BbsType = LocalBbsTable[Index].DeviceType;
795 mBootOptionBbsMappingCount ++;
796 }
797
798 //
799 // Group the Boot Option Number in BootOrder for the same type devices
800 //
801 GroupMultipleLegacyBootOption4SameType (
802 BootOrder,
803 BootOrderSize / sizeof (UINT16)
804 );
805
806 if (BootOrderSize > 0) {
807 Status = gRT->SetVariable (
808 L"BootOrder",
809 &gEfiGlobalVariableGuid,
810 VAR_FLAG,
811 BootOrderSize,
812 BootOrder
813 );
814 } else {
815 EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
816 }
817
818 if (BootOrder != NULL) {
819 FreePool (BootOrder);
820 }
821
822 return Status;
823 }
824
825 /**
826 Deletete the Boot Option from EFI Variable. The Boot Order Arrray
827 is also updated.
828
829 @param OptionNumber The number of Boot option want to be deleted.
830 @param BootOrder The Boot Order array.
831 @param BootOrderSize The size of the Boot Order Array.
832
833 @retval EFI_SUCCESS The Boot Option Variable was found and removed
834 @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible
835 @retval EFI_NOT_FOUND The Boot Option Variable was not found
836 **/
837 EFI_STATUS
838 EFIAPI
839 BdsDeleteBootOption (
840 IN UINTN OptionNumber,
841 IN OUT UINT16 *BootOrder,
842 IN OUT UINTN *BootOrderSize
843 )
844 {
845 UINT16 BootOption[100];
846 UINTN Index;
847 EFI_STATUS Status;
848 UINTN Index2Del;
849
850 Status = EFI_SUCCESS;
851 Index2Del = 0;
852
853 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);
854 Status = EfiLibDeleteVariable (BootOption, &gEfiGlobalVariableGuid);
855
856 //
857 // adjust boot order array
858 //
859 for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {
860 if (BootOrder[Index] == OptionNumber) {
861 Index2Del = Index;
862 break;
863 }
864 }
865
866 if (Index != *BootOrderSize / sizeof (UINT16)) {
867 for (Index = 0; Index < *BootOrderSize / sizeof (UINT16) - 1; Index++) {
868 if (Index >= Index2Del) {
869 BootOrder[Index] = BootOrder[Index + 1];
870 }
871 }
872
873 *BootOrderSize -= sizeof (UINT16);
874 }
875
876 return Status;
877
878 }
879
880 /**
881 Delete all the invalid legacy boot options.
882
883 @retval EFI_SUCCESS All invalide legacy boot options are deleted.
884 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
885 @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
886 **/
887 EFI_STATUS
888 EFIAPI
889 BdsDeleteAllInvalidLegacyBootOptions (
890 VOID
891 )
892 {
893 UINT16 *BootOrder;
894 UINT8 *BootOptionVar;
895 UINTN BootOrderSize;
896 UINTN BootOptionSize;
897 EFI_STATUS Status;
898 UINT16 HddCount;
899 UINT16 BbsCount;
900 HDD_INFO *LocalHddInfo;
901 BBS_TABLE *LocalBbsTable;
902 BBS_TABLE *BbsEntry;
903 UINT16 BbsIndex;
904 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
905 UINTN Index;
906 UINT16 BootOption[10];
907 UINT16 BootDesc[100];
908 BOOLEAN DescStringMatch;
909
910 Status = EFI_SUCCESS;
911 BootOrder = NULL;
912 BootOrderSize = 0;
913 HddCount = 0;
914 BbsCount = 0;
915 LocalHddInfo = NULL;
916 LocalBbsTable = NULL;
917 BbsEntry = NULL;
918
919 Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
920 if (EFI_ERROR (Status)) {
921 return Status;
922 }
923
924 LegacyBios->GetBbsInfo (
925 LegacyBios,
926 &HddCount,
927 &LocalHddInfo,
928 &BbsCount,
929 &LocalBbsTable
930 );
931
932 BootOrder = BdsLibGetVariableAndSize (
933 L"BootOrder",
934 &gEfiGlobalVariableGuid,
935 &BootOrderSize
936 );
937 if (BootOrder == NULL) {
938 BootOrderSize = 0;
939 }
940
941 Index = 0;
942 while (Index < BootOrderSize / sizeof (UINT16)) {
943 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
944 BootOptionVar = BdsLibGetVariableAndSize (
945 BootOption,
946 &gEfiGlobalVariableGuid,
947 &BootOptionSize
948 );
949 if (NULL == BootOptionVar) {
950 BootOptionSize = 0;
951 Status = gRT->GetVariable (
952 BootOption,
953 &gEfiGlobalVariableGuid,
954 NULL,
955 &BootOptionSize,
956 BootOptionVar
957 );
958 if (Status == EFI_NOT_FOUND) {
959 //
960 // Update BootOrder
961 //
962 BdsDeleteBootOption (
963 BootOrder[Index],
964 BootOrder,
965 &BootOrderSize
966 );
967 continue;
968 } else {
969 FreePool (BootOrder);
970 return EFI_OUT_OF_RESOURCES;
971 }
972 }
973
974 //
975 // Skip Non-Legacy boot option
976 //
977 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {
978 if (BootOptionVar!= NULL) {
979 FreePool (BootOptionVar);
980 }
981 Index++;
982 continue;
983 }
984
985 if (BbsIndex < BbsCount) {
986 //
987 // Check if BBS Description String is changed
988 //
989 DescStringMatch = FALSE;
990 BdsBuildLegacyDevNameString (
991 &LocalBbsTable[BbsIndex],
992 BbsIndex,
993 sizeof (BootDesc),
994 BootDesc
995 );
996
997 if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {
998 DescStringMatch = TRUE;
999 }
1000
1001 if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||
1002 (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&
1003 (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&
1004 DescStringMatch) {
1005 Index++;
1006 continue;
1007 }
1008 }
1009
1010 if (BootOptionVar != NULL) {
1011 FreePool (BootOptionVar);
1012 }
1013 //
1014 // should delete
1015 //
1016 BdsDeleteBootOption (
1017 BootOrder[Index],
1018 BootOrder,
1019 &BootOrderSize
1020 );
1021 }
1022
1023 //
1024 // Adjust the number of boot options.
1025 //
1026 if (BootOrderSize != 0) {
1027 Status = gRT->SetVariable (
1028 L"BootOrder",
1029 &gEfiGlobalVariableGuid,
1030 VAR_FLAG,
1031 BootOrderSize,
1032 BootOrder
1033 );
1034 } else {
1035 EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
1036 }
1037
1038 if (BootOrder != NULL) {
1039 FreePool (BootOrder);
1040 }
1041
1042 return Status;
1043 }
1044
1045 /**
1046 Fill the device order buffer.
1047
1048 @param BbsTable The BBS table.
1049 @param BbsType The BBS Type.
1050 @param BbsCount The BBS Count.
1051 @param Buf device order buffer.
1052
1053 @return The device order buffer.
1054
1055 **/
1056 UINT16 *
1057 BdsFillDevOrderBuf (
1058 IN BBS_TABLE *BbsTable,
1059 IN BBS_TYPE BbsType,
1060 IN UINTN BbsCount,
1061 OUT UINT16 *Buf
1062 )
1063 {
1064 UINTN Index;
1065
1066 for (Index = 0; Index < BbsCount; Index++) {
1067 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
1068 continue;
1069 }
1070
1071 if (BbsTable[Index].DeviceType != BbsType) {
1072 continue;
1073 }
1074
1075 *Buf = (UINT16) (Index & 0xFF);
1076 Buf++;
1077 }
1078
1079 return Buf;
1080 }
1081
1082 /**
1083 Create the device order buffer.
1084
1085 @param BbsTable The BBS table.
1086 @param BbsCount The BBS Count.
1087
1088 @retval EFI_SUCCES The buffer is created and the EFI variable named
1089 VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid is
1090 set correctly.
1091 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
1092 @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
1093 because of hardware error.
1094 **/
1095 EFI_STATUS
1096 BdsCreateDevOrder (
1097 IN BBS_TABLE *BbsTable,
1098 IN UINT16 BbsCount
1099 )
1100 {
1101 UINTN Index;
1102 UINTN FDCount;
1103 UINTN HDCount;
1104 UINTN CDCount;
1105 UINTN NETCount;
1106 UINTN BEVCount;
1107 UINTN TotalSize;
1108 UINTN HeaderSize;
1109 LEGACY_DEV_ORDER_ENTRY *DevOrder;
1110 LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
1111 EFI_STATUS Status;
1112
1113 FDCount = 0;
1114 HDCount = 0;
1115 CDCount = 0;
1116 NETCount = 0;
1117 BEVCount = 0;
1118 TotalSize = 0;
1119 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
1120 DevOrder = NULL;
1121 Status = EFI_SUCCESS;
1122
1123 //
1124 // Count all boot devices
1125 //
1126 for (Index = 0; Index < BbsCount; Index++) {
1127 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
1128 continue;
1129 }
1130
1131 switch (BbsTable[Index].DeviceType) {
1132 case BBS_FLOPPY:
1133 FDCount++;
1134 break;
1135
1136 case BBS_HARDDISK:
1137 HDCount++;
1138 break;
1139
1140 case BBS_CDROM:
1141 CDCount++;
1142 break;
1143
1144 case BBS_EMBED_NETWORK:
1145 NETCount++;
1146 break;
1147
1148 case BBS_BEV_DEVICE:
1149 BEVCount++;
1150 break;
1151
1152 default:
1153 break;
1154 }
1155 }
1156
1157 TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
1158 TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
1159 TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
1160 TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
1161 TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
1162
1163 //
1164 // Create buffer to hold all boot device order
1165 //
1166 DevOrder = AllocateZeroPool (TotalSize);
1167 if (NULL == DevOrder) {
1168 return EFI_OUT_OF_RESOURCES;
1169 }
1170 DevOrderPtr = DevOrder;
1171
1172 DevOrderPtr->BbsType = BBS_FLOPPY;
1173 DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));
1174 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);
1175
1176 DevOrderPtr->BbsType = BBS_HARDDISK;
1177 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
1178 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);
1179
1180 DevOrderPtr->BbsType = BBS_CDROM;
1181 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
1182 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);
1183
1184 DevOrderPtr->BbsType = BBS_EMBED_NETWORK;
1185 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
1186 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);
1187
1188 DevOrderPtr->BbsType = BBS_BEV_DEVICE;
1189 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
1190 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);
1191
1192 ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder));
1193
1194 //
1195 // Save device order for legacy boot device to variable.
1196 //
1197 Status = gRT->SetVariable (
1198 VAR_LEGACY_DEV_ORDER,
1199 &gEfiLegacyDevOrderVariableGuid,
1200 VAR_FLAG,
1201 TotalSize,
1202 DevOrder
1203 );
1204 FreePool (DevOrder);
1205
1206 return Status;
1207 }