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