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