IntelFrameworkModulePkg: Add LegacyBootManagerLib.
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / LegacyBootManagerLib / LegacyBm.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) 2011 - 2015, 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 "InternalLegacyBm.h"
18
19 #define LEGACY_BM_BOOT_DESCRIPTION_LENGTH 32
20
21 /**
22 Initialize legacy boot manager library by call EfiBootManagerRegisterLegacyBootSupport
23 function to export two function pointer.
24
25 @param ImageHandle The image handle.
26 @param SystemTable The system table.
27
28 @retval EFI_SUCCESS The legacy boot manager library is initialized correctly.
29 @return Other value if failed to initialize the legacy boot manager library.
30 **/
31 EFI_STATUS
32 EFIAPI
33 LegacyBootManagerLibConstructor (
34 IN EFI_HANDLE ImageHandle,
35 IN EFI_SYSTEM_TABLE *SystemTable
36 )
37 {
38 EfiBootManagerRegisterLegacyBootSupport (
39 LegacyBmRefreshAllBootOption,
40 LegacyBmBoot
41 );
42 return EFI_SUCCESS;
43 }
44
45 /**
46 Get the device type from the input legacy device path.
47
48 @param DevicePath The legacy device path.
49
50 @retval The legacy device type.
51 **/
52 UINT16
53 LegacyBmDeviceType (
54 EFI_DEVICE_PATH_PROTOCOL *DevicePath
55 )
56 {
57 ASSERT ((DevicePathType (DevicePath) == BBS_DEVICE_PATH) &&
58 (DevicePathSubType (DevicePath) == BBS_BBS_DP));
59 return ((BBS_BBS_DEVICE_PATH *) DevicePath)->DeviceType;
60 }
61
62 /**
63 Validate the BbsEntry base on the Boot Priority info in the BbsEntry.
64
65 @param BbsEntry The input bbs entry info.
66
67 @retval TRUE The BbsEntry is valid.
68 @retval FALSE The BbsEntry is invalid.
69 **/
70 BOOLEAN
71 LegacyBmValidBbsEntry (
72 IN BBS_TABLE *BbsEntry
73 )
74 {
75 switch (BbsEntry->BootPriority) {
76 case BBS_IGNORE_ENTRY:
77 case BBS_DO_NOT_BOOT_FROM:
78 case BBS_LOWEST_PRIORITY:
79 return FALSE;
80 default:
81 return TRUE;
82 }
83 }
84
85 /**
86 Build Legacy Device Name String according.
87
88 @param CurBBSEntry BBS Table.
89 @param Index Index.
90 @param BufSize The buffer size.
91 @param BootString The output string.
92
93 **/
94 VOID
95 LegacyBmBuildLegacyDevNameString (
96 IN BBS_TABLE *CurBBSEntry,
97 IN UINTN Index,
98 IN UINTN BufSize,
99 OUT CHAR16 *BootString
100 )
101 {
102 CHAR16 *Fmt;
103 CHAR16 *Type;
104 CHAR8 *StringDesc;
105 CHAR8 StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
106 CHAR16 StringBufferU[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
107
108 switch (Index) {
109 //
110 // Primary Master
111 //
112 case 1:
113 Fmt = L"Primary Master %s";
114 break;
115
116 //
117 // Primary Slave
118 //
119 case 2:
120 Fmt = L"Primary Slave %s";
121 break;
122
123 //
124 // Secondary Master
125 //
126 case 3:
127 Fmt = L"Secondary Master %s";
128 break;
129
130 //
131 // Secondary Slave
132 //
133 case 4:
134 Fmt = L"Secondary Slave %s";
135 break;
136
137 default:
138 Fmt = L"%s";
139 break;
140 }
141
142 switch (CurBBSEntry->DeviceType) {
143 case BBS_FLOPPY:
144 Type = L"Floppy";
145 break;
146
147 case BBS_HARDDISK:
148 Type = L"Harddisk";
149 break;
150
151 case BBS_CDROM:
152 Type = L"CDROM";
153 break;
154
155 case BBS_PCMCIA:
156 Type = L"PCMCIAe";
157 break;
158
159 case BBS_USB:
160 Type = L"USB";
161 break;
162
163 case BBS_EMBED_NETWORK:
164 Type = L"Network";
165 break;
166
167 case BBS_BEV_DEVICE:
168 Type = L"BEVe";
169 break;
170
171 case BBS_UNKNOWN:
172 default:
173 Type = L"Unknown";
174 break;
175 }
176 //
177 // If current BBS entry has its description then use it.
178 //
179 StringDesc = (CHAR8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
180 if (NULL != StringDesc) {
181 //
182 // Only get fisrt 32 characters, this is suggested by BBS spec
183 //
184 CopyMem (StringBufferA, StringDesc, LEGACY_BM_BOOT_DESCRIPTION_LENGTH);
185 StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH] = 0;
186 AsciiStrToUnicodeStr (StringBufferA, StringBufferU);
187 Fmt = L"%s";
188 Type = StringBufferU;
189 }
190
191 //
192 // BbsTable 16 entries are for onboard IDE.
193 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
194 //
195 if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {
196 Fmt = L"%s %d";
197 UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
198 } else {
199 UnicodeSPrint (BootString, BufSize, Fmt, Type);
200 }
201 }
202
203 /**
204 Get the Bbs index for the input boot option.
205
206 @param BootOption The input boot option info.
207 @param BbsTable The input Bbs table.
208 @param BbsCount The input total bbs entry number.
209 @param BbsIndexUsed The array shows how many BBS table indexs have been used.
210
211 @retval The index for the input boot option.
212 **/
213 UINT16
214 LegacyBmFuzzyMatch (
215 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,
216 BBS_TABLE *BbsTable,
217 UINT16 BbsCount,
218 BOOLEAN *BbsIndexUsed
219 )
220 {
221 UINT16 Index;
222 LEGACY_BM_BOOT_OPTION_BBS_DATA *BbsData;
223 CHAR16 Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
224
225 BbsData = (LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData;
226
227 //
228 // Directly check the BBS index stored in BootOption
229 //
230 if ((BbsData->BbsIndex < BbsCount) &&
231 (LegacyBmDeviceType (BootOption->FilePath) == BbsTable[BbsData->BbsIndex].DeviceType)) {
232 LegacyBmBuildLegacyDevNameString (
233 &BbsTable[BbsData->BbsIndex],
234 BbsData->BbsIndex,
235 sizeof (Description),
236 Description
237 );
238 if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[BbsData->BbsIndex]) {
239 //
240 // If devices with the same description string are connected,
241 // the BbsIndex of the first device is returned for the other device also.
242 // So, check if the BbsIndex is already being used, before assigning the BbsIndex.
243 //
244 BbsIndexUsed[BbsData->BbsIndex] = TRUE;
245 return BbsData->BbsIndex;
246 }
247 }
248
249 //
250 // BBS table could be changed (entry removed/moved)
251 // find the correct BBS index
252 //
253 for (Index = 0; Index < BbsCount; Index++) {
254 if (!LegacyBmValidBbsEntry (&BbsTable[Index]) ||
255 (BbsTable[Index].DeviceType != LegacyBmDeviceType (BootOption->FilePath))) {
256 continue;
257 }
258
259 LegacyBmBuildLegacyDevNameString (
260 &BbsTable[Index],
261 Index,
262 sizeof (Description),
263 Description
264 );
265 if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[Index]) {
266 //
267 // If devices with the same description string are connected,
268 // the BbsIndex of the first device is assigned for the other device also.
269 // So, check if the BbsIndex is already being used, before assigning the corrected BbsIndex.
270 //
271 break;
272 }
273 }
274
275 //
276 // Add the corrected BbsIndex in the UsedBbsIndex Buffer
277 //
278 if (Index != BbsCount) {
279 BbsIndexUsed[Index] = TRUE;
280 }
281
282 return Index;
283 }
284
285 /**
286
287 Update legacy device order base on the input info.
288
289 @param LegacyDevOrder Legacy device order data buffer.
290 @param LegacyDevOrderSize Legacy device order data buffer size.
291 @param DeviceType Device type which need to check.
292 @param OldBbsIndex Old Bds Index.
293 @param NewBbsIndex New Bds Index, if it is -1,means remove this option.
294
295 **/
296 VOID
297 LegacyBmUpdateBbsIndex (
298 LEGACY_DEV_ORDER_ENTRY *LegacyDevOrder,
299 UINTN *LegacyDevOrderSize,
300 UINT16 DeviceType,
301 UINT16 OldBbsIndex,
302 UINT16 NewBbsIndex // Delete entry if -1
303 )
304 {
305 LEGACY_DEV_ORDER_ENTRY *Entry;
306 UINTN Index;
307
308 ASSERT (((LegacyDevOrder == NULL) && (*LegacyDevOrderSize == 0)) ||
309 ((LegacyDevOrder != NULL) && (*LegacyDevOrderSize != 0))
310 );
311
312 for (Entry = LegacyDevOrder;
313 Entry < (LEGACY_DEV_ORDER_ENTRY *) ((UINT8 *) LegacyDevOrder + *LegacyDevOrderSize);
314 Entry = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) Entry + sizeof (BBS_TYPE) + Entry->Length)
315 ) {
316 if (Entry->BbsType == DeviceType) {
317 for (Index = 0; Index < Entry->Length / sizeof (UINT16) - 1; Index++) {
318 if (Entry->Data[Index] == OldBbsIndex) {
319 if (NewBbsIndex == (UINT16) -1) {
320 //
321 // Delete the old entry
322 //
323 CopyMem (
324 &Entry->Data[Index],
325 &Entry->Data[Index + 1],
326 (UINT8 *) LegacyDevOrder + *LegacyDevOrderSize - (UINT8 *) &Entry->Data[Index + 1]
327 );
328 Entry->Length -= sizeof (UINT16);
329 *LegacyDevOrderSize -= sizeof(UINT16);
330 } else {
331 Entry->Data[Index] = NewBbsIndex;
332 }
333 break;
334 }
335 }
336 break;
337 }
338 }
339 }
340
341 /**
342 Delete all the legacy boot options.
343
344 @retval EFI_SUCCESS All legacy boot options are deleted.
345 **/
346 EFI_STATUS
347 LegacyBmDeleteAllBootOptions (
348 VOID
349 )
350 {
351 EFI_STATUS Status;
352 UINTN Index;
353 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
354 UINTN BootOptionCount;
355
356 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
357 for (Index = 0; Index < BootOptionCount; Index++) {
358 if ((DevicePathType (BootOption[Index].FilePath) == BBS_DEVICE_PATH) &&
359 (DevicePathSubType (BootOption[Index].FilePath) == BBS_BBS_DP)) {
360 Status = EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType);
361 //
362 // Deleting variable with current variable implementation shouldn't fail.
363 //
364 ASSERT_EFI_ERROR (Status);
365 }
366 }
367
368 Status = gRT->SetVariable (
369 VAR_LEGACY_DEV_ORDER,
370 &gEfiLegacyDevOrderVariableGuid,
371 0,
372 0,
373 NULL
374 );
375 //
376 // Deleting variable with current variable implementation shouldn't fail.
377 //
378 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
379
380 return EFI_SUCCESS;
381 }
382
383
384 /**
385 Delete all the invalid legacy boot options.
386
387 @retval EFI_SUCCESS All invalide legacy boot options are deleted.
388 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
389 @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
390 **/
391 EFI_STATUS
392 LegacyBmDeleteAllInvalidBootOptions (
393 VOID
394 )
395 {
396 EFI_STATUS Status;
397 UINT16 HddCount;
398 UINT16 BbsCount;
399 HDD_INFO *HddInfo;
400 BBS_TABLE *BbsTable;
401 UINT16 BbsIndex;
402 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
403 UINTN Index;
404 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
405 UINTN BootOptionCount;
406 LEGACY_DEV_ORDER_ENTRY *LegacyDevOrder;
407 UINTN LegacyDevOrderSize;
408 BOOLEAN *BbsIndexUsed;
409
410 HddCount = 0;
411 BbsCount = 0;
412 HddInfo = NULL;
413 BbsTable = NULL;
414
415 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
416 if (EFI_ERROR (Status)) {
417 return Status;
418 }
419
420 Status = LegacyBios->GetBbsInfo (
421 LegacyBios,
422 &HddCount,
423 &HddInfo,
424 &BbsCount,
425 &BbsTable
426 );
427 if (EFI_ERROR (Status)) {
428 return Status;
429 }
430
431 GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &LegacyDevOrder, &LegacyDevOrderSize);
432
433 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
434
435 BbsIndexUsed = AllocateZeroPool (BbsCount * sizeof (BOOLEAN));
436 ASSERT (BbsIndexUsed != NULL);
437
438 for (Index = 0; Index < BootOptionCount; Index++) {
439 //
440 // Skip non legacy boot option
441 //
442 if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) ||
443 (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)) {
444 continue;
445 }
446
447 BbsIndex = LegacyBmFuzzyMatch (&BootOption[Index], BbsTable, BbsCount, BbsIndexUsed);
448 if (BbsIndex == BbsCount) {
449 DEBUG ((EFI_D_INFO, "[LegacyBds] Delete Boot Option Boot%04x: %s\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description));
450 //
451 // Delete entry from LegacyDevOrder
452 //
453 LegacyBmUpdateBbsIndex (
454 LegacyDevOrder,
455 &LegacyDevOrderSize,
456 LegacyBmDeviceType (BootOption[Index].FilePath),
457 ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex,
458 (UINT16) -1
459 );
460 EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType);
461 } else {
462 if (((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex != BbsIndex) {
463 DEBUG ((EFI_D_INFO, "[LegacyBds] Update Boot Option Boot%04x: %s Bbs0x%04x->Bbs0x%04x\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description,
464 (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex, (UINTN) BbsIndex));
465 //
466 // Update the BBS index in LegacyDevOrder
467 //
468 LegacyBmUpdateBbsIndex (
469 LegacyDevOrder,
470 &LegacyDevOrderSize,
471 LegacyBmDeviceType (BootOption[Index].FilePath),
472 ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex,
473 BbsIndex
474 );
475
476 //
477 // Update the OptionalData in the Boot#### variable
478 //
479 ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex = BbsIndex;
480 EfiBootManagerLoadOptionToVariable (&BootOption[Index]);
481 }
482 }
483 }
484 EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
485
486 if (LegacyDevOrder != NULL) {
487 Status = gRT->SetVariable (
488 VAR_LEGACY_DEV_ORDER,
489 &gEfiLegacyDevOrderVariableGuid,
490 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
491 LegacyDevOrderSize,
492 LegacyDevOrder
493 );
494 //
495 // Shrink variable with current variable implementation shouldn't fail.
496 //
497 ASSERT_EFI_ERROR (Status);
498
499 FreePool (LegacyDevOrder);
500 }
501 FreePool(BbsIndexUsed);
502 return Status;
503 }
504
505 /**
506 Create legacy boot option.
507
508 @param BootOption Ponter to the boot option which will be crated.
509 @param BbsEntry The input bbs entry info.
510 @param BbsIndex The BBS index.
511
512 @retval EFI_SUCCESS Create legacy boot option successfully.
513 @retval EFI_INVALID_PARAMETER Invalid input parameter.
514
515 **/
516 EFI_STATUS
517 LegacyBmCreateLegacyBootOption (
518 IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,
519 IN BBS_TABLE *BbsEntry,
520 IN UINT16 BbsIndex
521 )
522 {
523 EFI_STATUS Status;
524 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
525 CHAR16 Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
526 CHAR8 HelpString[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
527 UINTN StringLen;
528 LEGACY_BM_BOOT_OPTION_BBS_DATA *OptionalData;
529 BBS_BBS_DEVICE_PATH *BbsNode;
530
531 if ((BootOption == NULL) || (BbsEntry == NULL)) {
532 return EFI_INVALID_PARAMETER;
533 }
534
535 LegacyBmBuildLegacyDevNameString (BbsEntry, BbsIndex, sizeof (Description), Description);
536
537 //
538 // Create the BBS device path with description string
539 //
540 UnicodeStrToAsciiStr (Description, HelpString);
541 StringLen = AsciiStrLen (HelpString);
542 DevicePath = AllocatePool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen + END_DEVICE_PATH_LENGTH);
543 ASSERT (DevicePath != NULL);
544
545 BbsNode = (BBS_BBS_DEVICE_PATH *) DevicePath;
546 SetDevicePathNodeLength (BbsNode, sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
547 BbsNode->Header.Type = BBS_DEVICE_PATH;
548 BbsNode->Header.SubType = BBS_BBS_DP;
549 BbsNode->DeviceType = BbsEntry->DeviceType;
550 CopyMem (&BbsNode->StatusFlag, &BbsEntry->StatusFlags, sizeof (BBS_STATUS_FLAGS));
551 CopyMem (BbsNode->String, HelpString, StringLen + 1);
552
553 SetDevicePathEndNode (NextDevicePathNode (BbsNode));
554
555 //
556 // Create the OptionalData
557 //
558 OptionalData = AllocatePool (sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA));
559 ASSERT (OptionalData != NULL);
560 OptionalData->BbsIndex = BbsIndex;
561
562 //
563 // Create the BootOption
564 //
565 Status = EfiBootManagerInitializeLoadOption (
566 BootOption,
567 LoadOptionNumberUnassigned,
568 LoadOptionTypeBoot,
569 LOAD_OPTION_ACTIVE,
570 Description,
571 DevicePath,
572 (UINT8 *) OptionalData,
573 sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA)
574 );
575 FreePool (DevicePath);
576 FreePool (OptionalData);
577
578 return Status;
579 }
580
581 /**
582 Fill the device order buffer.
583
584 @param BbsTable The BBS table.
585 @param BbsType The BBS Type.
586 @param BbsCount The BBS Count.
587 @param Buf device order buffer.
588
589 @return The device order buffer.
590
591 **/
592 UINT16 *
593 LegacyBmFillDevOrderBuf (
594 IN BBS_TABLE *BbsTable,
595 IN BBS_TYPE BbsType,
596 IN UINTN BbsCount,
597 OUT UINT16 *Buf
598 )
599 {
600 UINTN Index;
601
602 for (Index = 0; Index < BbsCount; Index++) {
603 if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
604 continue;
605 }
606
607 if (BbsTable[Index].DeviceType != BbsType) {
608 continue;
609 }
610
611 *Buf = (UINT16) (Index & 0xFF);
612 Buf++;
613 }
614
615 return Buf;
616 }
617
618 /**
619 Create the device order buffer.
620
621 @param BbsTable The BBS table.
622 @param BbsCount The BBS Count.
623
624 @retval EFI_SUCCES The buffer is created and the EFI variable named
625 VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is
626 set correctly.
627 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
628 @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
629 because of hardware error.
630 **/
631 EFI_STATUS
632 LegacyBmCreateDevOrder (
633 IN BBS_TABLE *BbsTable,
634 IN UINT16 BbsCount
635 )
636 {
637 UINTN Index;
638 UINTN FDCount;
639 UINTN HDCount;
640 UINTN CDCount;
641 UINTN NETCount;
642 UINTN BEVCount;
643 UINTN TotalSize;
644 UINTN HeaderSize;
645 LEGACY_DEV_ORDER_ENTRY *DevOrder;
646 LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
647 EFI_STATUS Status;
648
649 FDCount = 0;
650 HDCount = 0;
651 CDCount = 0;
652 NETCount = 0;
653 BEVCount = 0;
654 TotalSize = 0;
655 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
656 DevOrder = NULL;
657 Status = EFI_SUCCESS;
658
659 //
660 // Count all boot devices
661 //
662 for (Index = 0; Index < BbsCount; Index++) {
663 if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
664 continue;
665 }
666
667 switch (BbsTable[Index].DeviceType) {
668 case BBS_FLOPPY:
669 FDCount++;
670 break;
671
672 case BBS_HARDDISK:
673 HDCount++;
674 break;
675
676 case BBS_CDROM:
677 CDCount++;
678 break;
679
680 case BBS_EMBED_NETWORK:
681 NETCount++;
682 break;
683
684 case BBS_BEV_DEVICE:
685 BEVCount++;
686 break;
687
688 default:
689 break;
690 }
691 }
692
693 TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
694 TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
695 TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
696 TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
697 TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
698
699 //
700 // Create buffer to hold all boot device order
701 //
702 DevOrder = AllocateZeroPool (TotalSize);
703 if (NULL == DevOrder) {
704 return EFI_OUT_OF_RESOURCES;
705 }
706 DevOrderPtr = DevOrder;
707
708 DevOrderPtr->BbsType = BBS_FLOPPY;
709 DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));
710 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);
711
712 DevOrderPtr->BbsType = BBS_HARDDISK;
713 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
714 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);
715
716 DevOrderPtr->BbsType = BBS_CDROM;
717 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
718 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);
719
720 DevOrderPtr->BbsType = BBS_EMBED_NETWORK;
721 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
722 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);
723
724 DevOrderPtr->BbsType = BBS_BEV_DEVICE;
725 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
726 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);
727
728 ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder));
729
730 //
731 // Save device order for legacy boot device to variable.
732 //
733 Status = gRT->SetVariable (
734 VAR_LEGACY_DEV_ORDER,
735 &gEfiLegacyDevOrderVariableGuid,
736 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
737 TotalSize,
738 DevOrder
739 );
740 FreePool (DevOrder);
741
742 return Status;
743 }
744
745 /**
746 Add the legacy boot devices from BBS table into
747 the legacy device boot order.
748
749 @retval EFI_SUCCESS The boot devices are added successfully.
750 @retval EFI_NOT_FOUND The legacy boot devices are not found.
751 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
752 @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
753 because of hardware error.
754 **/
755 EFI_STATUS
756 LegacyBmUpdateDevOrder (
757 VOID
758 )
759 {
760 LEGACY_DEV_ORDER_ENTRY *DevOrder;
761 LEGACY_DEV_ORDER_ENTRY *NewDevOrder;
762 LEGACY_DEV_ORDER_ENTRY *Ptr;
763 LEGACY_DEV_ORDER_ENTRY *NewPtr;
764 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
765 EFI_STATUS Status;
766 UINT16 HddCount;
767 UINT16 BbsCount;
768 HDD_INFO *LocalHddInfo;
769 BBS_TABLE *LocalBbsTable;
770 UINTN Index;
771 UINTN Index2;
772 UINTN *Idx;
773 UINTN FDCount;
774 UINTN HDCount;
775 UINTN CDCount;
776 UINTN NETCount;
777 UINTN BEVCount;
778 UINTN TotalSize;
779 UINTN HeaderSize;
780 UINT16 *NewFDPtr;
781 UINT16 *NewHDPtr;
782 UINT16 *NewCDPtr;
783 UINT16 *NewNETPtr;
784 UINT16 *NewBEVPtr;
785 UINT16 *NewDevPtr;
786 UINTN FDIndex;
787 UINTN HDIndex;
788 UINTN CDIndex;
789 UINTN NETIndex;
790 UINTN BEVIndex;
791
792 Idx = NULL;
793 FDCount = 0;
794 HDCount = 0;
795 CDCount = 0;
796 NETCount = 0;
797 BEVCount = 0;
798 TotalSize = 0;
799 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
800 FDIndex = 0;
801 HDIndex = 0;
802 CDIndex = 0;
803 NETIndex = 0;
804 BEVIndex = 0;
805 NewDevPtr = NULL;
806
807 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
808 if (EFI_ERROR (Status)) {
809 return Status;
810 }
811
812 Status = LegacyBios->GetBbsInfo (
813 LegacyBios,
814 &HddCount,
815 &LocalHddInfo,
816 &BbsCount,
817 &LocalBbsTable
818 );
819 if (EFI_ERROR (Status)) {
820 return Status;
821 }
822
823 GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, NULL);
824 if (NULL == DevOrder) {
825 return LegacyBmCreateDevOrder (LocalBbsTable, BbsCount);
826 }
827 //
828 // First we figure out how many boot devices with same device type respectively
829 //
830 for (Index = 0; Index < BbsCount; Index++) {
831 if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
832 continue;
833 }
834
835 switch (LocalBbsTable[Index].DeviceType) {
836 case BBS_FLOPPY:
837 FDCount++;
838 break;
839
840 case BBS_HARDDISK:
841 HDCount++;
842 break;
843
844 case BBS_CDROM:
845 CDCount++;
846 break;
847
848 case BBS_EMBED_NETWORK:
849 NETCount++;
850 break;
851
852 case BBS_BEV_DEVICE:
853 BEVCount++;
854 break;
855
856 default:
857 break;
858 }
859 }
860
861 TotalSize += (HeaderSize + FDCount * sizeof (UINT16));
862 TotalSize += (HeaderSize + HDCount * sizeof (UINT16));
863 TotalSize += (HeaderSize + CDCount * sizeof (UINT16));
864 TotalSize += (HeaderSize + NETCount * sizeof (UINT16));
865 TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));
866
867 NewDevOrder = AllocateZeroPool (TotalSize);
868 if (NULL == NewDevOrder) {
869 return EFI_OUT_OF_RESOURCES;
870 }
871
872 //
873 // copy FD
874 //
875 Ptr = DevOrder;
876 NewPtr = NewDevOrder;
877 NewPtr->BbsType = Ptr->BbsType;
878 NewPtr->Length = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
879 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
880 if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
881 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY
882 ) {
883 continue;
884 }
885
886 NewPtr->Data[FDIndex] = Ptr->Data[Index];
887 FDIndex++;
888 }
889 NewFDPtr = NewPtr->Data;
890
891 //
892 // copy HD
893 //
894 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
895 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
896 NewPtr->BbsType = Ptr->BbsType;
897 NewPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
898 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
899 if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
900 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK
901 ) {
902 continue;
903 }
904
905 NewPtr->Data[HDIndex] = Ptr->Data[Index];
906 HDIndex++;
907 }
908 NewHDPtr = NewPtr->Data;
909
910 //
911 // copy CD
912 //
913 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
914 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
915 NewPtr->BbsType = Ptr->BbsType;
916 NewPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
917 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
918 if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
919 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM
920 ) {
921 continue;
922 }
923
924 NewPtr->Data[CDIndex] = Ptr->Data[Index];
925 CDIndex++;
926 }
927 NewCDPtr = NewPtr->Data;
928
929 //
930 // copy NET
931 //
932 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
933 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
934 NewPtr->BbsType = Ptr->BbsType;
935 NewPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
936 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
937 if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
938 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK
939 ) {
940 continue;
941 }
942
943 NewPtr->Data[NETIndex] = Ptr->Data[Index];
944 NETIndex++;
945 }
946 NewNETPtr = NewPtr->Data;
947
948 //
949 // copy BEV
950 //
951 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
952 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
953 NewPtr->BbsType = Ptr->BbsType;
954 NewPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
955 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
956 if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
957 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE
958 ) {
959 continue;
960 }
961
962 NewPtr->Data[BEVIndex] = Ptr->Data[Index];
963 BEVIndex++;
964 }
965 NewBEVPtr = NewPtr->Data;
966
967 for (Index = 0; Index < BbsCount; Index++) {
968 if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
969 continue;
970 }
971
972 switch (LocalBbsTable[Index].DeviceType) {
973 case BBS_FLOPPY:
974 Idx = &FDIndex;
975 NewDevPtr = NewFDPtr;
976 break;
977
978 case BBS_HARDDISK:
979 Idx = &HDIndex;
980 NewDevPtr = NewHDPtr;
981 break;
982
983 case BBS_CDROM:
984 Idx = &CDIndex;
985 NewDevPtr = NewCDPtr;
986 break;
987
988 case BBS_EMBED_NETWORK:
989 Idx = &NETIndex;
990 NewDevPtr = NewNETPtr;
991 break;
992
993 case BBS_BEV_DEVICE:
994 Idx = &BEVIndex;
995 NewDevPtr = NewBEVPtr;
996 break;
997
998 default:
999 Idx = NULL;
1000 break;
1001 }
1002 //
1003 // at this point we have copied those valid indexes to new buffer
1004 // and we should check if there is any new appeared boot device
1005 //
1006 if (Idx != NULL) {
1007 for (Index2 = 0; Index2 < *Idx; Index2++) {
1008 if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {
1009 break;
1010 }
1011 }
1012
1013 if (Index2 == *Idx) {
1014 //
1015 // Index2 == *Idx means we didn't find Index
1016 // so Index is a new appeared device's index in BBS table
1017 // insert it before disabled indexes.
1018 //
1019 for (Index2 = 0; Index2 < *Idx; Index2++) {
1020 if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {
1021 break;
1022 }
1023 }
1024 CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16));
1025 NewDevPtr[Index2] = (UINT16) (Index & 0xFF);
1026 (*Idx)++;
1027 }
1028 }
1029 }
1030
1031 FreePool (DevOrder);
1032
1033 Status = gRT->SetVariable (
1034 VAR_LEGACY_DEV_ORDER,
1035 &gEfiLegacyDevOrderVariableGuid,
1036 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1037 TotalSize,
1038 NewDevOrder
1039 );
1040 FreePool (NewDevOrder);
1041
1042 return Status;
1043 }
1044
1045 /**
1046 Set Boot Priority for specified device type.
1047
1048 @param DeviceType The device type.
1049 @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
1050 @param LocalBbsTable The BBS table.
1051 @param Priority The prority table.
1052
1053 @retval EFI_SUCCESS The function completes successfully.
1054 @retval EFI_NOT_FOUND Failed to find device.
1055 @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
1056
1057 **/
1058 EFI_STATUS
1059 LegacyBmSetPriorityForSameTypeDev (
1060 IN UINT16 DeviceType,
1061 IN UINTN BbsIndex,
1062 IN OUT BBS_TABLE *LocalBbsTable,
1063 IN OUT UINT16 *Priority
1064 )
1065 {
1066 LEGACY_DEV_ORDER_ENTRY *DevOrder;
1067 LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
1068 UINTN DevOrderSize;
1069 UINTN Index;
1070
1071 GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, &DevOrderSize);
1072 if (NULL == DevOrder) {
1073 return EFI_OUT_OF_RESOURCES;
1074 }
1075
1076 DevOrderPtr = DevOrder;
1077 while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {
1078 if (DevOrderPtr->BbsType == DeviceType) {
1079 break;
1080 }
1081
1082 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length);
1083 }
1084
1085 if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {
1086 FreePool (DevOrder);
1087 return EFI_NOT_FOUND;
1088 }
1089
1090 if (BbsIndex != (UINTN) -1) {
1091 //
1092 // In case the BBS entry isn't valid because devices were plugged or removed.
1093 //
1094 if (!LegacyBmValidBbsEntry (&LocalBbsTable[BbsIndex]) || (LocalBbsTable[BbsIndex].DeviceType != DeviceType)) {
1095 FreePool (DevOrder);
1096 return EFI_NOT_FOUND;
1097 }
1098 LocalBbsTable[BbsIndex].BootPriority = *Priority;
1099 (*Priority)++;
1100 }
1101 //
1102 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
1103 //
1104 for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {
1105 if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {
1106 //
1107 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
1108 //
1109 } else if (DevOrderPtr->Data[Index] != BbsIndex) {
1110 LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;
1111 (*Priority)++;
1112 }
1113 }
1114
1115 FreePool (DevOrder);
1116 return EFI_SUCCESS;
1117 }
1118
1119 /**
1120 Print the BBS Table.
1121
1122 @param LocalBbsTable The BBS table.
1123 @param BbsCount The count of entry in BBS table.
1124 **/
1125 VOID
1126 LegacyBmPrintBbsTable (
1127 IN BBS_TABLE *LocalBbsTable,
1128 IN UINT16 BbsCount
1129 )
1130 {
1131 UINT16 Index;
1132
1133 DEBUG ((DEBUG_INFO, "\n"));
1134 DEBUG ((DEBUG_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
1135 DEBUG ((DEBUG_INFO, "=============================================\n"));
1136 for (Index = 0; Index < BbsCount; Index++) {
1137 if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
1138 continue;
1139 }
1140
1141 DEBUG (
1142 (DEBUG_INFO,
1143 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
1144 (UINTN) Index,
1145 (UINTN) LocalBbsTable[Index].BootPriority,
1146 (UINTN) LocalBbsTable[Index].Bus,
1147 (UINTN) LocalBbsTable[Index].Device,
1148 (UINTN) LocalBbsTable[Index].Function,
1149 (UINTN) LocalBbsTable[Index].Class,
1150 (UINTN) LocalBbsTable[Index].SubClass,
1151 (UINTN) LocalBbsTable[Index].DeviceType,
1152 (UINTN) * (UINT16 *) &LocalBbsTable[Index].StatusFlags,
1153 (UINTN) LocalBbsTable[Index].BootHandlerSegment,
1154 (UINTN) LocalBbsTable[Index].BootHandlerOffset,
1155 (UINTN) ((LocalBbsTable[Index].MfgStringSegment << 4) + LocalBbsTable[Index].MfgStringOffset),
1156 (UINTN) ((LocalBbsTable[Index].DescStringSegment << 4) + LocalBbsTable[Index].DescStringOffset))
1157 );
1158 }
1159
1160 DEBUG ((DEBUG_INFO, "\n"));
1161 }
1162
1163 /**
1164 Set the boot priority for BBS entries based on boot option entry and boot order.
1165
1166 @param BootOption The boot option is to be checked for refresh BBS table.
1167
1168 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
1169 @retval EFI_NOT_FOUND BBS entries can't be found.
1170 @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
1171 **/
1172 EFI_STATUS
1173 LegacyBmRefreshBbsTableForBoot (
1174 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
1175 )
1176 {
1177 EFI_STATUS Status;
1178 UINT16 BbsIndex;
1179 UINT16 HddCount;
1180 UINT16 BbsCount;
1181 HDD_INFO *LocalHddInfo;
1182 BBS_TABLE *LocalBbsTable;
1183 UINT16 DevType;
1184 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
1185 UINTN Index;
1186 UINT16 Priority;
1187 UINT16 *DeviceType;
1188 UINTN DeviceTypeCount;
1189 UINTN DeviceTypeIndex;
1190 EFI_BOOT_MANAGER_LOAD_OPTION *Option;
1191 UINTN OptionCount;
1192
1193 HddCount = 0;
1194 BbsCount = 0;
1195 LocalHddInfo = NULL;
1196 LocalBbsTable = NULL;
1197 DevType = BBS_UNKNOWN;
1198
1199 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
1200 if (EFI_ERROR (Status)) {
1201 return Status;
1202 }
1203
1204 Status = LegacyBios->GetBbsInfo (
1205 LegacyBios,
1206 &HddCount,
1207 &LocalHddInfo,
1208 &BbsCount,
1209 &LocalBbsTable
1210 );
1211 if (EFI_ERROR (Status)) {
1212 return Status;
1213 }
1214
1215 //
1216 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
1217 // We will set them according to the settings setup by user
1218 //
1219 for (Index = 0; Index < BbsCount; Index++) {
1220 if (LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
1221 LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
1222 }
1223 }
1224 //
1225 // boot priority always starts at 0
1226 //
1227 Priority = 0;
1228 if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) &&
1229 (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
1230 //
1231 // If BootOption stands for a legacy boot option, we prioritize the devices with the same type first.
1232 //
1233 DevType = LegacyBmDeviceType (BootOption->FilePath);
1234 BbsIndex = ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData)->BbsIndex;
1235 Status = LegacyBmSetPriorityForSameTypeDev (
1236 DevType,
1237 BbsIndex,
1238 LocalBbsTable,
1239 &Priority
1240 );
1241 if (EFI_ERROR (Status)) {
1242 return Status;
1243 }
1244 }
1245 //
1246 // we have to set the boot priority for other BBS entries with different device types
1247 //
1248 Option = EfiBootManagerGetLoadOptions (&OptionCount, LoadOptionTypeBoot);
1249 DeviceType = AllocatePool (sizeof (UINT16) * OptionCount);
1250 ASSERT (DeviceType != NULL);
1251 DeviceType[0] = DevType;
1252 DeviceTypeCount = 1;
1253 for (Index = 0; Index < OptionCount; Index++) {
1254 if ((DevicePathType (Option[Index].FilePath) != BBS_DEVICE_PATH) ||
1255 (DevicePathSubType (Option[Index].FilePath) != BBS_BBS_DP)) {
1256 continue;
1257 }
1258
1259 DevType = LegacyBmDeviceType (Option[Index].FilePath);
1260 for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) {
1261 if (DeviceType[DeviceTypeIndex] == DevType) {
1262 break;
1263 }
1264 }
1265 if (DeviceTypeIndex < DeviceTypeCount) {
1266 //
1267 // We don't want to process twice for a device type
1268 //
1269 continue;
1270 }
1271
1272 DeviceType[DeviceTypeCount] = DevType;
1273 DeviceTypeCount++;
1274
1275 Status = LegacyBmSetPriorityForSameTypeDev (
1276 DevType,
1277 (UINTN) -1,
1278 LocalBbsTable,
1279 &Priority
1280 );
1281 }
1282 EfiBootManagerFreeLoadOptions (Option, OptionCount);
1283
1284 DEBUG_CODE_BEGIN();
1285 LegacyBmPrintBbsTable (LocalBbsTable, BbsCount);
1286 DEBUG_CODE_END();
1287
1288 return Status;
1289 }
1290
1291
1292 /**
1293 Boot the legacy system with the boot option.
1294
1295 @param BootOption The legacy boot option which have BBS device path
1296 On return, BootOption->Status contains the boot status.
1297 EFI_UNSUPPORTED There is no legacybios protocol, do not support
1298 legacy boot.
1299 EFI_STATUS The status of LegacyBios->LegacyBoot ().
1300 **/
1301 VOID
1302 EFIAPI
1303 LegacyBmBoot (
1304 IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
1305 )
1306 {
1307 EFI_STATUS Status;
1308 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
1309
1310 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
1311 if (EFI_ERROR (Status)) {
1312 //
1313 // If no LegacyBios protocol we do not support legacy boot
1314 //
1315 BootOption->Status = EFI_UNSUPPORTED;
1316 return;
1317 }
1318 //
1319 // Notes: if we separate the int 19, then we don't need to refresh BBS
1320 //
1321 Status = LegacyBmRefreshBbsTableForBoot (BootOption);
1322 if (EFI_ERROR (Status)) {
1323 BootOption->Status = Status;
1324 return;
1325 }
1326
1327 BootOption->Status = LegacyBios->LegacyBoot (
1328 LegacyBios,
1329 (BBS_BBS_DEVICE_PATH *) BootOption->FilePath,
1330 BootOption->OptionalDataSize,
1331 BootOption->OptionalData
1332 );
1333 }
1334
1335 /**
1336 This function enumerates all the legacy boot options.
1337
1338 @param BootOptionCount Return the legacy boot option count.
1339
1340 @retval Pointer to the legacy boot option buffer.
1341 **/
1342 EFI_BOOT_MANAGER_LOAD_OPTION *
1343 LegacyBmEnumerateAllBootOptions (
1344 UINTN *BootOptionCount
1345 )
1346 {
1347 EFI_STATUS Status;
1348 UINT16 HddCount;
1349 UINT16 BbsCount;
1350 HDD_INFO *HddInfo;
1351 BBS_TABLE *BbsTable;
1352 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
1353 UINT16 Index;
1354 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
1355
1356 ASSERT (BootOptionCount != NULL);
1357
1358 BootOptions = NULL;
1359 *BootOptionCount = 0;
1360 BbsCount = 0;
1361
1362 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
1363 if (EFI_ERROR (Status)) {
1364 return NULL;
1365 }
1366
1367 Status = LegacyBios->GetBbsInfo (
1368 LegacyBios,
1369 &HddCount,
1370 &HddInfo,
1371 &BbsCount,
1372 &BbsTable
1373 );
1374 if (EFI_ERROR (Status)) {
1375 return NULL;
1376 }
1377
1378 for (Index = 0; Index < BbsCount; Index++) {
1379 if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
1380 continue;
1381 }
1382
1383 BootOptions = ReallocatePool (
1384 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
1385 sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
1386 BootOptions
1387 );
1388 ASSERT (BootOptions != NULL);
1389
1390 Status = LegacyBmCreateLegacyBootOption (&BootOptions[(*BootOptionCount)++], &BbsTable[Index], Index);
1391 ASSERT_EFI_ERROR (Status);
1392 }
1393
1394 return BootOptions;
1395 }
1396
1397 /**
1398 Return the index of the boot option in the boot option array.
1399
1400 The function compares the Description, FilePath, OptionalData.
1401
1402 @param Key The input boot option which is compared with.
1403 @param Array The input boot option array.
1404 @param Count The count of the input boot options.
1405
1406 @retval The index of the input boot option in the array.
1407
1408 **/
1409 INTN
1410 LegacyBmFindBootOption (
1411 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
1412 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
1413 IN UINTN Count
1414 )
1415 {
1416 UINTN Index;
1417
1418 for (Index = 0; Index < Count; Index++) {
1419 if ((StrCmp (Key->Description, Array[Index].Description) == 0) &&
1420 (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
1421 (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
1422 (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
1423 return (INTN) Index;
1424 }
1425 }
1426
1427 return -1;
1428 }
1429
1430 /**
1431 Refresh all legacy boot options.
1432
1433 **/
1434 VOID
1435 EFIAPI
1436 LegacyBmRefreshAllBootOption (
1437 VOID
1438 )
1439 {
1440 EFI_STATUS Status;
1441 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
1442 UINTN RootBridgeHandleCount;
1443 EFI_HANDLE *RootBridgeHandleBuffer;
1444 UINTN HandleCount;
1445 EFI_HANDLE *HandleBuffer;
1446 UINTN RootBridgeIndex;
1447 UINTN Index;
1448 UINTN Flags;
1449 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
1450 UINTN BootOptionCount;
1451 EFI_BOOT_MANAGER_LOAD_OPTION *ExistingBootOptions;
1452 UINTN ExistingBootOptionCount;
1453
1454 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
1455 if (EFI_ERROR (Status)) {
1456 LegacyBmDeleteAllBootOptions ();
1457 return;
1458 }
1459 PERF_START (NULL, "LegacyBootOptionEnum", "BDS", 0);
1460
1461 //
1462 // Before enumerating the legacy boot option, we need to dispatch all the legacy option roms
1463 // to ensure the GetBbsInfo() counts all the legacy devices.
1464 //
1465 gBS->LocateHandleBuffer (
1466 ByProtocol,
1467 &gEfiPciRootBridgeIoProtocolGuid,
1468 NULL,
1469 &RootBridgeHandleCount,
1470 &RootBridgeHandleBuffer
1471 );
1472 for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
1473 gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
1474 gBS->LocateHandleBuffer (
1475 ByProtocol,
1476 &gEfiPciIoProtocolGuid,
1477 NULL,
1478 &HandleCount,
1479 &HandleBuffer
1480 );
1481 for (Index = 0; Index < HandleCount; Index++) {
1482 //
1483 // Start the thunk driver so that the legacy option rom gets dispatched.
1484 // Note: We don't directly call InstallPciRom because some thunk drivers
1485 // (e.g. BlockIo thunk driver) depend on the immediate result after dispatching
1486 //
1487 Status = LegacyBios->CheckPciRom (
1488 LegacyBios,
1489 HandleBuffer[Index],
1490 NULL,
1491 NULL,
1492 &Flags
1493 );
1494 if (!EFI_ERROR (Status)) {
1495 gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
1496 }
1497 }
1498 }
1499
1500 //
1501 // Same algorithm pattern as the EfiBootManagerRefreshAllBootOption
1502 // Firstly delete the invalid legacy boot options,
1503 // then enumreate and save the newly appeared legacy boot options
1504 // the last step is legacy boot option special action to refresh the LegacyDevOrder variable
1505 //
1506 LegacyBmDeleteAllInvalidBootOptions ();
1507
1508 ExistingBootOptions = EfiBootManagerGetLoadOptions (&ExistingBootOptionCount, LoadOptionTypeBoot);
1509 BootOptions = LegacyBmEnumerateAllBootOptions (&BootOptionCount);
1510
1511 for (Index = 0; Index < BootOptionCount; Index++) {
1512 if (LegacyBmFindBootOption (&BootOptions[Index], ExistingBootOptions, ExistingBootOptionCount) == -1) {
1513 Status = EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
1514 DEBUG ((
1515 EFI_D_INFO, "[LegacyBds] New Boot Option: Boot%04x Bbs0x%04x %s %r\n",
1516 (UINTN) BootOptions[Index].OptionNumber,
1517 (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOptions[Index].OptionalData)->BbsIndex,
1518 BootOptions[Index].Description,
1519 Status
1520 ));
1521 //
1522 // Continue upon failure to add boot option.
1523 //
1524 }
1525 }
1526
1527 EfiBootManagerFreeLoadOptions (ExistingBootOptions, ExistingBootOptionCount);
1528 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
1529
1530 //
1531 // Failure to create LegacyDevOrder variable only impacts the boot order.
1532 //
1533 LegacyBmUpdateDevOrder ();
1534
1535 PERF_END (NULL, "LegacyBootOptionEnum", "BDS", 0);
1536 }