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