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