]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / GenericBdsLib / BdsBoot.c
CommitLineData
5c08e117 1/** @file\r
2 BDS Lib functions which relate with create or process the boot option.\r
3\r
b8d06293 4Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
c0a00b14 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
5c08e117 6\r
7**/\r
8\r
9#include "InternalBdsLib.h"\r
9aa7ba01 10#include "String.h"\r
5c08e117 11\r
12BOOLEAN mEnumBootDevice = FALSE;\r
9aa7ba01 13EFI_HII_HANDLE gBdsLibStringPackHandle = NULL;\r
5c08e117 14\r
b8d06293
DB
15/**\r
16\r
17 End Perf entry of BDS\r
18\r
19 @param Event The triggered event.\r
20 @param Context Context for this event.\r
21\r
22**/\r
23VOID\r
24EFIAPI\r
25BmEndOfBdsPerfCode (\r
26 IN EFI_EVENT Event,\r
27 IN VOID *Context\r
28 )\r
29{\r
30 //\r
31 // Record the performance data for End of BDS\r
32 //\r
33 PERF_END(NULL, "BDS", NULL, 0);\r
34\r
35 return ;\r
36}\r
37\r
9aa7ba01 38/**\r
39 The constructor function register UNI strings into imageHandle.\r
0a6f4824
LG
40\r
41 It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.\r
9aa7ba01 42\r
43 @param ImageHandle The firmware allocated handle for the EFI image.\r
44 @param SystemTable A pointer to the EFI System Table.\r
0a6f4824 45\r
9aa7ba01 46 @retval EFI_SUCCESS The constructor successfully added string package.\r
47 @retval Other value The constructor can't add string package.\r
48\r
49**/\r
50EFI_STATUS\r
51EFIAPI\r
52GenericBdsLibConstructor (\r
53 IN EFI_HANDLE ImageHandle,\r
54 IN EFI_SYSTEM_TABLE *SystemTable\r
55 )\r
56{\r
57\r
58 gBdsLibStringPackHandle = HiiAddPackages (\r
e24fc103 59 &gBdsLibStringPackageGuid,\r
09363eca 60 ImageHandle,\r
9aa7ba01 61 GenericBdsLibStrings,\r
62 NULL\r
63 );\r
64\r
65 ASSERT (gBdsLibStringPackHandle != NULL);\r
66\r
67 return EFI_SUCCESS;\r
68}\r
69\r
16e5944a
RN
70/**\r
71 Deletete the Boot Option from EFI Variable. The Boot Order Arrray\r
72 is also updated.\r
73\r
74 @param OptionNumber The number of Boot option want to be deleted.\r
75 @param BootOrder The Boot Order array.\r
76 @param BootOrderSize The size of the Boot Order Array.\r
77\r
78 @retval EFI_SUCCESS The Boot Option Variable was found and removed\r
79 @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible\r
80 @retval EFI_NOT_FOUND The Boot Option Variable was not found\r
81**/\r
82EFI_STATUS\r
83EFIAPI\r
84BdsDeleteBootOption (\r
85 IN UINTN OptionNumber,\r
86 IN OUT UINT16 *BootOrder,\r
87 IN OUT UINTN *BootOrderSize\r
88 )\r
89{\r
90 CHAR16 BootOption[9];\r
91 UINTN Index;\r
92 EFI_STATUS Status;\r
93\r
94 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);\r
95 Status = gRT->SetVariable (\r
96 BootOption,\r
97 &gEfiGlobalVariableGuid,\r
98 0,\r
99 0,\r
100 NULL\r
101 );\r
69fc8f08
RN
102 //\r
103 // Deleting variable with existing variable implementation shouldn't fail.\r
104 //\r
105 ASSERT_EFI_ERROR (Status);\r
16e5944a
RN
106\r
107 //\r
108 // adjust boot order array\r
109 //\r
110 for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {\r
111 if (BootOrder[Index] == OptionNumber) {\r
112 CopyMem (&BootOrder[Index], &BootOrder[Index+1], *BootOrderSize - (Index+1) * sizeof (UINT16));\r
113 *BootOrderSize -= sizeof (UINT16);\r
114 break;\r
115 }\r
116 }\r
117\r
118 return Status;\r
119}\r
120/**\r
121\r
122 Translate the first n characters of an Ascii string to\r
123 Unicode characters. The count n is indicated by parameter\r
124 Size. If Size is greater than the length of string, then\r
125 the entire string is translated.\r
126\r
127\r
128 @param AStr Pointer to input Ascii string.\r
129 @param Size The number of characters to translate.\r
130 @param UStr Pointer to output Unicode string buffer.\r
131\r
132**/\r
133VOID\r
134AsciiToUnicodeSize (\r
135 IN UINT8 *AStr,\r
136 IN UINTN Size,\r
137 OUT UINT16 *UStr\r
138 )\r
139{\r
140 UINTN Idx;\r
141\r
142 Idx = 0;\r
143 while (AStr[Idx] != 0) {\r
144 UStr[Idx] = (CHAR16) AStr[Idx];\r
145 if (Idx == Size) {\r
146 break;\r
147 }\r
148\r
149 Idx++;\r
150 }\r
151 UStr[Idx] = 0;\r
152}\r
153\r
154/**\r
155 Build Legacy Device Name String according.\r
156\r
157 @param CurBBSEntry BBS Table.\r
158 @param Index Index.\r
159 @param BufSize The buffer size.\r
160 @param BootString The output string.\r
161\r
162**/\r
163VOID\r
164BdsBuildLegacyDevNameString (\r
165 IN BBS_TABLE *CurBBSEntry,\r
166 IN UINTN Index,\r
167 IN UINTN BufSize,\r
168 OUT CHAR16 *BootString\r
169 )\r
170{\r
171 CHAR16 *Fmt;\r
172 CHAR16 *Type;\r
173 UINT8 *StringDesc;\r
174 CHAR16 Temp[80];\r
175\r
176 switch (Index) {\r
177 //\r
178 // Primary Master\r
179 //\r
180 case 1:\r
181 Fmt = L"Primary Master %s";\r
182 break;\r
183\r
184 //\r
185 // Primary Slave\r
186 //\r
187 case 2:\r
188 Fmt = L"Primary Slave %s";\r
189 break;\r
190\r
191 //\r
192 // Secondary Master\r
193 //\r
194 case 3:\r
195 Fmt = L"Secondary Master %s";\r
196 break;\r
197\r
198 //\r
199 // Secondary Slave\r
200 //\r
201 case 4:\r
202 Fmt = L"Secondary Slave %s";\r
203 break;\r
204\r
205 default:\r
206 Fmt = L"%s";\r
207 break;\r
208 }\r
209\r
210 switch (CurBBSEntry->DeviceType) {\r
211 case BBS_FLOPPY:\r
212 Type = L"Floppy";\r
213 break;\r
214\r
215 case BBS_HARDDISK:\r
216 Type = L"Harddisk";\r
217 break;\r
218\r
219 case BBS_CDROM:\r
220 Type = L"CDROM";\r
221 break;\r
222\r
223 case BBS_PCMCIA:\r
224 Type = L"PCMCIAe";\r
225 break;\r
226\r
227 case BBS_USB:\r
228 Type = L"USB";\r
229 break;\r
230\r
231 case BBS_EMBED_NETWORK:\r
232 Type = L"Network";\r
233 break;\r
234\r
235 case BBS_BEV_DEVICE:\r
236 Type = L"BEVe";\r
237 break;\r
238\r
239 case BBS_UNKNOWN:\r
240 default:\r
241 Type = L"Unknown";\r
242 break;\r
243 }\r
244 //\r
245 // If current BBS entry has its description then use it.\r
246 //\r
aa5f60ae 247 StringDesc = (UINT8 *) (((UINTN) CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);\r
16e5944a
RN
248 if (NULL != StringDesc) {\r
249 //\r
250 // Only get fisrt 32 characters, this is suggested by BBS spec\r
251 //\r
252 AsciiToUnicodeSize (StringDesc, 32, Temp);\r
253 Fmt = L"%s";\r
254 Type = Temp;\r
255 }\r
256\r
257 //\r
258 // BbsTable 16 entries are for onboard IDE.\r
259 // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11\r
260 //\r
261 if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {\r
262 Fmt = L"%s %d";\r
263 UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);\r
264 } else {\r
265 UnicodeSPrint (BootString, BufSize, Fmt, Type);\r
266 }\r
267}\r
268\r
269/**\r
270\r
271 Create a legacy boot option for the specified entry of\r
272 BBS table, save it as variable, and append it to the boot\r
273 order list.\r
274\r
275\r
276 @param CurrentBbsEntry Pointer to current BBS table.\r
277 @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS\r
278 @param Index Index of the specified entry in BBS table.\r
279 @param BootOrderList On input, the original boot order list.\r
280 On output, the new boot order list attached with the\r
281 created node.\r
282 @param BootOrderListSize On input, the original size of boot order list.\r
283 On output, the size of new boot order list.\r
284\r
285 @retval EFI_SUCCESS Boot Option successfully created.\r
286 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.\r
287 @retval Other Error occurs while setting variable.\r
288\r
289**/\r
290EFI_STATUS\r
291BdsCreateLegacyBootOption (\r
292 IN BBS_TABLE *CurrentBbsEntry,\r
293 IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath,\r
294 IN UINTN Index,\r
295 IN OUT UINT16 **BootOrderList,\r
296 IN OUT UINTN *BootOrderListSize\r
297 )\r
298{\r
299 EFI_STATUS Status;\r
300 UINT16 CurrentBootOptionNo;\r
301 UINT16 BootString[10];\r
302 CHAR16 BootDesc[100];\r
303 CHAR8 HelpString[100];\r
304 UINT16 *NewBootOrderList;\r
305 UINTN BufferSize;\r
306 UINTN StringLen;\r
307 VOID *Buffer;\r
308 UINT8 *Ptr;\r
309 UINT16 CurrentBbsDevPathSize;\r
310 UINTN BootOrderIndex;\r
311 UINTN BootOrderLastIndex;\r
312 UINTN ArrayIndex;\r
313 BOOLEAN IndexNotFound;\r
314 BBS_BBS_DEVICE_PATH *NewBbsDevPathNode;\r
315\r
316 if ((*BootOrderList) == NULL) {\r
317 CurrentBootOptionNo = 0;\r
318 } else {\r
319 for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {\r
320 IndexNotFound = TRUE;\r
321 for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {\r
322 if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {\r
323 IndexNotFound = FALSE;\r
324 break;\r
325 }\r
326 }\r
327\r
328 if (!IndexNotFound) {\r
329 continue;\r
330 } else {\r
331 break;\r
332 }\r
333 }\r
334\r
335 CurrentBootOptionNo = (UINT16) ArrayIndex;\r
336 }\r
337\r
338 UnicodeSPrint (\r
339 BootString,\r
340 sizeof (BootString),\r
341 L"Boot%04x",\r
342 CurrentBootOptionNo\r
343 );\r
344\r
345 BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);\r
346\r
347 //\r
348 // Create new BBS device path node with description string\r
349 //\r
9b82facd 350 UnicodeStrToAsciiStrS (BootDesc, HelpString, sizeof (HelpString));\r
16e5944a
RN
351\r
352 StringLen = AsciiStrLen (HelpString);\r
353 NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen);\r
354 if (NewBbsDevPathNode == NULL) {\r
355 return EFI_OUT_OF_RESOURCES;\r
356 }\r
357 CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH));\r
358 CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1);\r
359 SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen);\r
360\r
361 //\r
362 // Create entire new CurrentBbsDevPath with end node\r
363 //\r
364 CurrentBbsDevPath = AppendDevicePathNode (\r
365 NULL,\r
366 (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode\r
367 );\r
368 if (CurrentBbsDevPath == NULL) {\r
369 FreePool (NewBbsDevPathNode);\r
370 return EFI_OUT_OF_RESOURCES;\r
371 }\r
372\r
373 CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));\r
374\r
375 BufferSize = sizeof (UINT32) +\r
376 sizeof (UINT16) +\r
377 StrSize (BootDesc) +\r
378 CurrentBbsDevPathSize +\r
379 sizeof (BBS_TABLE) +\r
380 sizeof (UINT16);\r
381\r
382 Buffer = AllocateZeroPool (BufferSize);\r
383 if (Buffer == NULL) {\r
384 FreePool (NewBbsDevPathNode);\r
385 FreePool (CurrentBbsDevPath);\r
386 return EFI_OUT_OF_RESOURCES;\r
387 }\r
388\r
389 Ptr = (UINT8 *) Buffer;\r
390\r
391 *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;\r
392 Ptr += sizeof (UINT32);\r
393\r
394 *((UINT16 *) Ptr) = CurrentBbsDevPathSize;\r
395 Ptr += sizeof (UINT16);\r
396\r
397 CopyMem (\r
398 Ptr,\r
399 BootDesc,\r
400 StrSize (BootDesc)\r
401 );\r
402 Ptr += StrSize (BootDesc);\r
403\r
404 CopyMem (\r
405 Ptr,\r
406 CurrentBbsDevPath,\r
407 CurrentBbsDevPathSize\r
408 );\r
409 Ptr += CurrentBbsDevPathSize;\r
410\r
411 CopyMem (\r
412 Ptr,\r
413 CurrentBbsEntry,\r
414 sizeof (BBS_TABLE)\r
415 );\r
416\r
417 Ptr += sizeof (BBS_TABLE);\r
418 *((UINT16 *) Ptr) = (UINT16) Index;\r
419\r
420 Status = gRT->SetVariable (\r
421 BootString,\r
422 &gEfiGlobalVariableGuid,\r
423 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
424 BufferSize,\r
425 Buffer\r
426 );\r
5c08e117 427\r
16e5944a 428 FreePool (Buffer);\r
0a6f4824 429\r
16e5944a
RN
430 Buffer = NULL;\r
431\r
432 NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));\r
433 if (NULL == NewBootOrderList) {\r
434 FreePool (NewBbsDevPathNode);\r
435 FreePool (CurrentBbsDevPath);\r
436 return EFI_OUT_OF_RESOURCES;\r
437 }\r
438\r
439 if (*BootOrderList != NULL) {\r
440 CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);\r
441 FreePool (*BootOrderList);\r
442 }\r
443\r
444 BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16));\r
445 NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo;\r
446 *BootOrderListSize += sizeof (UINT16);\r
447 *BootOrderList = NewBootOrderList;\r
448\r
449 FreePool (NewBbsDevPathNode);\r
450 FreePool (CurrentBbsDevPath);\r
451 return Status;\r
452}\r
453\r
454/**\r
455 Check if the boot option is a legacy one.\r
456\r
457 @param BootOptionVar The boot option data payload.\r
458 @param BbsEntry The BBS Table.\r
459 @param BbsIndex The table index.\r
460\r
461 @retval TRUE It is a legacy boot option.\r
462 @retval FALSE It is not a legacy boot option.\r
463\r
464**/\r
465BOOLEAN\r
466BdsIsLegacyBootOption (\r
467 IN UINT8 *BootOptionVar,\r
468 OUT BBS_TABLE **BbsEntry,\r
469 OUT UINT16 *BbsIndex\r
470 )\r
471{\r
472 UINT8 *Ptr;\r
473 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
474 BOOLEAN Ret;\r
475 UINT16 DevPathLen;\r
476\r
477 Ptr = BootOptionVar;\r
478 Ptr += sizeof (UINT32);\r
479 DevPathLen = *(UINT16 *) Ptr;\r
480 Ptr += sizeof (UINT16);\r
481 Ptr += StrSize ((UINT16 *) Ptr);\r
482 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
483 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
484 Ptr += DevPathLen;\r
485 *BbsEntry = (BBS_TABLE *) Ptr;\r
486 Ptr += sizeof (BBS_TABLE);\r
487 *BbsIndex = *(UINT16 *) Ptr;\r
488 Ret = TRUE;\r
489 } else {\r
490 *BbsEntry = NULL;\r
491 Ret = FALSE;\r
492 }\r
493\r
494 return Ret;\r
495}\r
496\r
497/**\r
498 Delete all the invalid legacy boot options.\r
499\r
500 @retval EFI_SUCCESS All invalide legacy boot options are deleted.\r
501 @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.\r
502 @retval EFI_NOT_FOUND Fail to retrive variable of boot order.\r
503**/\r
504EFI_STATUS\r
505EFIAPI\r
506BdsDeleteAllInvalidLegacyBootOptions (\r
507 VOID\r
508 )\r
509{\r
510 UINT16 *BootOrder;\r
511 UINT8 *BootOptionVar;\r
512 UINTN BootOrderSize;\r
513 UINTN BootOptionSize;\r
514 EFI_STATUS Status;\r
515 UINT16 HddCount;\r
516 UINT16 BbsCount;\r
517 HDD_INFO *LocalHddInfo;\r
518 BBS_TABLE *LocalBbsTable;\r
519 BBS_TABLE *BbsEntry;\r
520 UINT16 BbsIndex;\r
521 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
522 UINTN Index;\r
523 UINT16 BootOption[10];\r
524 UINT16 BootDesc[100];\r
525 BOOLEAN DescStringMatch;\r
526\r
527 Status = EFI_SUCCESS;\r
528 BootOrder = NULL;\r
529 BootOrderSize = 0;\r
530 HddCount = 0;\r
531 BbsCount = 0;\r
532 LocalHddInfo = NULL;\r
533 LocalBbsTable = NULL;\r
534 BbsEntry = NULL;\r
535\r
536 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
537 if (EFI_ERROR (Status)) {\r
538 return Status;\r
539 }\r
540\r
16e5944a
RN
541 BootOrder = BdsLibGetVariableAndSize (\r
542 L"BootOrder",\r
543 &gEfiGlobalVariableGuid,\r
544 &BootOrderSize\r
545 );\r
546 if (BootOrder == NULL) {\r
1187b10f 547 return EFI_NOT_FOUND;\r
16e5944a
RN
548 }\r
549\r
1187b10f
RN
550 LegacyBios->GetBbsInfo (\r
551 LegacyBios,\r
552 &HddCount,\r
553 &LocalHddInfo,\r
554 &BbsCount,\r
555 &LocalBbsTable\r
556 );\r
557\r
16e5944a
RN
558 Index = 0;\r
559 while (Index < BootOrderSize / sizeof (UINT16)) {\r
560 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
561 BootOptionVar = BdsLibGetVariableAndSize (\r
562 BootOption,\r
563 &gEfiGlobalVariableGuid,\r
564 &BootOptionSize\r
565 );\r
566 if (NULL == BootOptionVar) {\r
567 BootOptionSize = 0;\r
568 Status = gRT->GetVariable (\r
569 BootOption,\r
570 &gEfiGlobalVariableGuid,\r
571 NULL,\r
572 &BootOptionSize,\r
573 BootOptionVar\r
574 );\r
575 if (Status == EFI_NOT_FOUND) {\r
576 //\r
577 // Update BootOrder\r
578 //\r
579 BdsDeleteBootOption (\r
580 BootOrder[Index],\r
581 BootOrder,\r
582 &BootOrderSize\r
583 );\r
584 continue;\r
585 } else {\r
586 FreePool (BootOrder);\r
587 return EFI_OUT_OF_RESOURCES;\r
588 }\r
589 }\r
0a6f4824 590\r
16e5944a
RN
591 //\r
592 // Skip Non-Legacy boot option\r
0a6f4824 593 //\r
16e5944a
RN
594 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {\r
595 if (BootOptionVar!= NULL) {\r
596 FreePool (BootOptionVar);\r
597 }\r
598 Index++;\r
599 continue;\r
600 }\r
601\r
602 if (BbsIndex < BbsCount) {\r
603 //\r
604 // Check if BBS Description String is changed\r
605 //\r
606 DescStringMatch = FALSE;\r
607 BdsBuildLegacyDevNameString (\r
608 &LocalBbsTable[BbsIndex],\r
609 BbsIndex,\r
610 sizeof (BootDesc),\r
611 BootDesc\r
612 );\r
613\r
614 if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {\r
615 DescStringMatch = TRUE;\r
616 }\r
617\r
618 if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||\r
619 (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&\r
620 (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&\r
621 DescStringMatch) {\r
622 Index++;\r
623 continue;\r
624 }\r
625 }\r
626\r
627 if (BootOptionVar != NULL) {\r
628 FreePool (BootOptionVar);\r
629 }\r
630 //\r
631 // should delete\r
632 //\r
633 BdsDeleteBootOption (\r
634 BootOrder[Index],\r
635 BootOrder,\r
636 &BootOrderSize\r
637 );\r
638 }\r
639\r
640 //\r
641 // Adjust the number of boot options.\r
642 //\r
643 Status = gRT->SetVariable (\r
644 L"BootOrder",\r
645 &gEfiGlobalVariableGuid,\r
646 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
647 BootOrderSize,\r
648 BootOrder\r
649 );\r
69fc8f08
RN
650 //\r
651 // Shrinking variable with existing variable implementation shouldn't fail.\r
652 //\r
653 ASSERT_EFI_ERROR (Status);\r
1187b10f 654 FreePool (BootOrder);\r
16e5944a
RN
655\r
656 return Status;\r
657}\r
658\r
659/**\r
660 Find all legacy boot option by device type.\r
661\r
662 @param BootOrder The boot order array.\r
663 @param BootOptionNum The number of boot option.\r
664 @param DevType Device type.\r
665 @param DevName Device name.\r
666 @param Attribute The boot option attribute.\r
667 @param BbsIndex The BBS table index.\r
668 @param OptionNumber The boot option index.\r
669\r
670 @retval TRUE The Legacy boot option is found.\r
671 @retval FALSE The legacy boot option is not found.\r
672\r
673**/\r
674BOOLEAN\r
675BdsFindLegacyBootOptionByDevTypeAndName (\r
676 IN UINT16 *BootOrder,\r
677 IN UINTN BootOptionNum,\r
678 IN UINT16 DevType,\r
679 IN CHAR16 *DevName,\r
680 OUT UINT32 *Attribute,\r
681 OUT UINT16 *BbsIndex,\r
682 OUT UINT16 *OptionNumber\r
683 )\r
684{\r
685 UINTN Index;\r
686 CHAR16 BootOption[9];\r
687 UINTN BootOptionSize;\r
688 UINT8 *BootOptionVar;\r
689 BBS_TABLE *BbsEntry;\r
690 BOOLEAN Found;\r
691\r
692 BbsEntry = NULL;\r
693 Found = FALSE;\r
694\r
695 if (NULL == BootOrder) {\r
696 return Found;\r
697 }\r
698\r
699 //\r
700 // Loop all boot option from variable\r
701 //\r
702 for (Index = 0; Index < BootOptionNum; Index++) {\r
703 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]);\r
704 BootOptionVar = BdsLibGetVariableAndSize (\r
705 BootOption,\r
706 &gEfiGlobalVariableGuid,\r
707 &BootOptionSize\r
708 );\r
709 if (NULL == BootOptionVar) {\r
710 continue;\r
711 }\r
712\r
713 //\r
714 // Skip Non-legacy boot option\r
715 //\r
716 if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {\r
717 FreePool (BootOptionVar);\r
718 continue;\r
719 }\r
720\r
721 if (\r
722 (BbsEntry->DeviceType != DevType) ||\r
723 (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0)\r
724 ) {\r
725 FreePool (BootOptionVar);\r
726 continue;\r
727 }\r
728\r
729 *Attribute = *(UINT32 *) BootOptionVar;\r
730 *OptionNumber = BootOrder[Index];\r
731 Found = TRUE;\r
732 FreePool (BootOptionVar);\r
733 break;\r
734 }\r
735\r
736 return Found;\r
737}\r
738\r
739/**\r
740 Create a legacy boot option.\r
741\r
742 @param BbsItem The BBS Table entry.\r
743 @param Index Index of the specified entry in BBS table.\r
744 @param BootOrderList The boot order list.\r
745 @param BootOrderListSize The size of boot order list.\r
746\r
747 @retval EFI_OUT_OF_RESOURCE No enough memory.\r
748 @retval EFI_SUCCESS The function complete successfully.\r
749 @return Other value if the legacy boot option is not created.\r
750\r
751**/\r
752EFI_STATUS\r
753BdsCreateOneLegacyBootOption (\r
754 IN BBS_TABLE *BbsItem,\r
755 IN UINTN Index,\r
756 IN OUT UINT16 **BootOrderList,\r
757 IN OUT UINTN *BootOrderListSize\r
758 )\r
759{\r
760 BBS_BBS_DEVICE_PATH BbsDevPathNode;\r
761 EFI_STATUS Status;\r
762 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
763\r
764 DevPath = NULL;\r
765\r
766 //\r
767 // Create device path node.\r
768 //\r
769 BbsDevPathNode.Header.Type = BBS_DEVICE_PATH;\r
770 BbsDevPathNode.Header.SubType = BBS_BBS_DP;\r
771 SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));\r
772 BbsDevPathNode.DeviceType = BbsItem->DeviceType;\r
773 CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));\r
774\r
775 DevPath = AppendDevicePathNode (\r
776 NULL,\r
777 (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode\r
778 );\r
779 if (NULL == DevPath) {\r
780 return EFI_OUT_OF_RESOURCES;\r
781 }\r
782\r
783 Status = BdsCreateLegacyBootOption (\r
784 BbsItem,\r
785 DevPath,\r
786 Index,\r
787 BootOrderList,\r
788 BootOrderListSize\r
789 );\r
790 BbsItem->BootPriority = 0x00;\r
791\r
792 FreePool (DevPath);\r
793\r
794 return Status;\r
795}\r
796\r
797/**\r
798 Add the legacy boot options from BBS table if they do not exist.\r
799\r
0a6f4824 800 @retval EFI_SUCCESS The boot options are added successfully\r
16e5944a
RN
801 or they are already in boot options.\r
802 @retval EFI_NOT_FOUND No legacy boot options is found.\r
803 @retval EFI_OUT_OF_RESOURCE No enough memory.\r
804 @return Other value LegacyBoot options are not added.\r
805**/\r
806EFI_STATUS\r
807EFIAPI\r
808BdsAddNonExistingLegacyBootOptions (\r
809 VOID\r
810 )\r
811{\r
812 UINT16 *BootOrder;\r
813 UINTN BootOrderSize;\r
814 EFI_STATUS Status;\r
815 CHAR16 Desc[100];\r
816 UINT16 HddCount;\r
817 UINT16 BbsCount;\r
818 HDD_INFO *LocalHddInfo;\r
819 BBS_TABLE *LocalBbsTable;\r
820 UINT16 BbsIndex;\r
821 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
822 UINT16 Index;\r
823 UINT32 Attribute;\r
824 UINT16 OptionNumber;\r
825 BOOLEAN Exist;\r
826\r
827 HddCount = 0;\r
828 BbsCount = 0;\r
829 LocalHddInfo = NULL;\r
830 LocalBbsTable = NULL;\r
831\r
832 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
833 if (EFI_ERROR (Status)) {\r
834 return Status;\r
835 }\r
836\r
837 LegacyBios->GetBbsInfo (\r
838 LegacyBios,\r
839 &HddCount,\r
840 &LocalHddInfo,\r
841 &BbsCount,\r
842 &LocalBbsTable\r
843 );\r
844\r
845 BootOrder = BdsLibGetVariableAndSize (\r
846 L"BootOrder",\r
847 &gEfiGlobalVariableGuid,\r
848 &BootOrderSize\r
849 );\r
850 if (BootOrder == NULL) {\r
851 BootOrderSize = 0;\r
852 }\r
853\r
854 for (Index = 0; Index < BbsCount; Index++) {\r
855 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
856 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)\r
857 ) {\r
858 continue;\r
859 }\r
860\r
861 BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc);\r
862\r
863 Exist = BdsFindLegacyBootOptionByDevTypeAndName (\r
864 BootOrder,\r
865 BootOrderSize / sizeof (UINT16),\r
866 LocalBbsTable[Index].DeviceType,\r
867 Desc,\r
868 &Attribute,\r
869 &BbsIndex,\r
870 &OptionNumber\r
871 );\r
872 if (!Exist) {\r
873 //\r
874 // Not found such type of legacy device in boot options or we found but it's disabled\r
875 // so we have to create one and put it to the tail of boot order list\r
876 //\r
877 Status = BdsCreateOneLegacyBootOption (\r
878 &LocalBbsTable[Index],\r
879 Index,\r
880 &BootOrder,\r
881 &BootOrderSize\r
882 );\r
69fc8f08 883 if (!EFI_ERROR (Status)) {\r
45295cf5 884 ASSERT (BootOrder != NULL);\r
69fc8f08
RN
885 BbsIndex = Index;\r
886 OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1];\r
16e5944a 887 }\r
16e5944a
RN
888 }\r
889\r
890 ASSERT (BbsIndex == Index);\r
891 }\r
892\r
893 Status = gRT->SetVariable (\r
894 L"BootOrder",\r
895 &gEfiGlobalVariableGuid,\r
896 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
897 BootOrderSize,\r
898 BootOrder\r
899 );\r
900 if (BootOrder != NULL) {\r
901 FreePool (BootOrder);\r
902 }\r
903\r
904 return Status;\r
905}\r
906\r
907/**\r
908 Fill the device order buffer.\r
909\r
910 @param BbsTable The BBS table.\r
911 @param BbsType The BBS Type.\r
912 @param BbsCount The BBS Count.\r
913 @param Buf device order buffer.\r
914\r
915 @return The device order buffer.\r
916\r
917**/\r
918UINT16 *\r
919BdsFillDevOrderBuf (\r
920 IN BBS_TABLE *BbsTable,\r
921 IN BBS_TYPE BbsType,\r
922 IN UINTN BbsCount,\r
923 OUT UINT16 *Buf\r
924 )\r
925{\r
926 UINTN Index;\r
927\r
928 for (Index = 0; Index < BbsCount; Index++) {\r
929 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {\r
930 continue;\r
931 }\r
932\r
933 if (BbsTable[Index].DeviceType != BbsType) {\r
934 continue;\r
935 }\r
936\r
937 *Buf = (UINT16) (Index & 0xFF);\r
938 Buf++;\r
939 }\r
940\r
941 return Buf;\r
942}\r
943\r
944/**\r
945 Create the device order buffer.\r
946\r
947 @param BbsTable The BBS table.\r
948 @param BbsCount The BBS Count.\r
949\r
0a6f4824 950 @retval EFI_SUCCES The buffer is created and the EFI variable named\r
16e5944a
RN
951 VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid is\r
952 set correctly.\r
953 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.\r
954 @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail\r
955 because of hardware error.\r
956**/\r
957EFI_STATUS\r
958BdsCreateDevOrder (\r
959 IN BBS_TABLE *BbsTable,\r
960 IN UINT16 BbsCount\r
961 )\r
962{\r
963 UINTN Index;\r
964 UINTN FDCount;\r
965 UINTN HDCount;\r
966 UINTN CDCount;\r
967 UINTN NETCount;\r
968 UINTN BEVCount;\r
969 UINTN TotalSize;\r
970 UINTN HeaderSize;\r
971 LEGACY_DEV_ORDER_ENTRY *DevOrder;\r
972 LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;\r
973 EFI_STATUS Status;\r
974\r
975 FDCount = 0;\r
976 HDCount = 0;\r
977 CDCount = 0;\r
978 NETCount = 0;\r
979 BEVCount = 0;\r
980 TotalSize = 0;\r
981 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);\r
982 DevOrder = NULL;\r
983 Status = EFI_SUCCESS;\r
984\r
985 //\r
986 // Count all boot devices\r
987 //\r
988 for (Index = 0; Index < BbsCount; Index++) {\r
989 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {\r
990 continue;\r
991 }\r
992\r
993 switch (BbsTable[Index].DeviceType) {\r
994 case BBS_FLOPPY:\r
995 FDCount++;\r
996 break;\r
997\r
998 case BBS_HARDDISK:\r
999 HDCount++;\r
1000 break;\r
1001\r
1002 case BBS_CDROM:\r
1003 CDCount++;\r
1004 break;\r
1005\r
1006 case BBS_EMBED_NETWORK:\r
1007 NETCount++;\r
1008 break;\r
1009\r
1010 case BBS_BEV_DEVICE:\r
1011 BEVCount++;\r
1012 break;\r
1013\r
1014 default:\r
1015 break;\r
1016 }\r
1017 }\r
1018\r
1019 TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);\r
1020 TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);\r
1021 TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);\r
1022 TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);\r
1023 TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);\r
1024\r
1025 //\r
1026 // Create buffer to hold all boot device order\r
1027 //\r
1028 DevOrder = AllocateZeroPool (TotalSize);\r
1029 if (NULL == DevOrder) {\r
1030 return EFI_OUT_OF_RESOURCES;\r
1031 }\r
1032 DevOrderPtr = DevOrder;\r
1033\r
1034 DevOrderPtr->BbsType = BBS_FLOPPY;\r
1035 DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));\r
1036 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);\r
1037\r
1038 DevOrderPtr->BbsType = BBS_HARDDISK;\r
1039 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));\r
1040 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);\r
0a6f4824 1041\r
16e5944a
RN
1042 DevOrderPtr->BbsType = BBS_CDROM;\r
1043 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));\r
1044 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);\r
0a6f4824 1045\r
16e5944a
RN
1046 DevOrderPtr->BbsType = BBS_EMBED_NETWORK;\r
1047 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));\r
1048 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);\r
1049\r
1050 DevOrderPtr->BbsType = BBS_BEV_DEVICE;\r
1051 DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));\r
1052 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);\r
1053\r
4ff5fd20 1054 ASSERT (TotalSize == ((UINTN) DevOrderPtr - (UINTN) DevOrder));\r
16e5944a
RN
1055\r
1056 //\r
1057 // Save device order for legacy boot device to variable.\r
1058 //\r
1059 Status = gRT->SetVariable (\r
1060 VAR_LEGACY_DEV_ORDER,\r
1061 &gEfiLegacyDevOrderVariableGuid,\r
32d258b5 1062 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
16e5944a
RN
1063 TotalSize,\r
1064 DevOrder\r
1065 );\r
1066 FreePool (DevOrder);\r
1067\r
1068 return Status;\r
1069}\r
1070\r
1071/**\r
0a6f4824 1072 Add the legacy boot devices from BBS table into\r
16e5944a
RN
1073 the legacy device boot order.\r
1074\r
1075 @retval EFI_SUCCESS The boot devices are added successfully.\r
1076 @retval EFI_NOT_FOUND The legacy boot devices are not found.\r
1077 @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.\r
1078 @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable\r
1079 because of hardware error.\r
1080**/\r
1081EFI_STATUS\r
1082EFIAPI\r
1083BdsUpdateLegacyDevOrder (\r
1084 VOID\r
1085 )\r
1086{\r
1087 LEGACY_DEV_ORDER_ENTRY *DevOrder;\r
1088 LEGACY_DEV_ORDER_ENTRY *NewDevOrder;\r
1089 LEGACY_DEV_ORDER_ENTRY *Ptr;\r
1090 LEGACY_DEV_ORDER_ENTRY *NewPtr;\r
1091 UINTN DevOrderSize;\r
1092 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
1093 EFI_STATUS Status;\r
1094 UINT16 HddCount;\r
1095 UINT16 BbsCount;\r
1096 HDD_INFO *LocalHddInfo;\r
1097 BBS_TABLE *LocalBbsTable;\r
1098 UINTN Index;\r
1099 UINTN Index2;\r
1100 UINTN *Idx;\r
1101 UINTN FDCount;\r
1102 UINTN HDCount;\r
1103 UINTN CDCount;\r
1104 UINTN NETCount;\r
1105 UINTN BEVCount;\r
1106 UINTN TotalSize;\r
1107 UINTN HeaderSize;\r
1108 UINT16 *NewFDPtr;\r
1109 UINT16 *NewHDPtr;\r
1110 UINT16 *NewCDPtr;\r
1111 UINT16 *NewNETPtr;\r
1112 UINT16 *NewBEVPtr;\r
1113 UINT16 *NewDevPtr;\r
1114 UINTN FDIndex;\r
1115 UINTN HDIndex;\r
1116 UINTN CDIndex;\r
1117 UINTN NETIndex;\r
1118 UINTN BEVIndex;\r
1119\r
1120 Idx = NULL;\r
1121 FDCount = 0;\r
1122 HDCount = 0;\r
1123 CDCount = 0;\r
1124 NETCount = 0;\r
1125 BEVCount = 0;\r
1126 TotalSize = 0;\r
1127 HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);\r
1128 FDIndex = 0;\r
1129 HDIndex = 0;\r
1130 CDIndex = 0;\r
1131 NETIndex = 0;\r
1132 BEVIndex = 0;\r
1133 NewDevPtr = NULL;\r
1134\r
1135 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
1136 if (EFI_ERROR (Status)) {\r
1137 return Status;\r
1138 }\r
1139\r
1140 Status = LegacyBios->GetBbsInfo (\r
1141 LegacyBios,\r
1142 &HddCount,\r
1143 &LocalHddInfo,\r
1144 &BbsCount,\r
1145 &LocalBbsTable\r
1146 );\r
1147 if (EFI_ERROR (Status)) {\r
1148 return Status;\r
1149 }\r
1150\r
1151 DevOrder = BdsLibGetVariableAndSize (\r
1152 VAR_LEGACY_DEV_ORDER,\r
1153 &gEfiLegacyDevOrderVariableGuid,\r
1154 &DevOrderSize\r
1155 );\r
1156 if (NULL == DevOrder) {\r
1157 return BdsCreateDevOrder (LocalBbsTable, BbsCount);\r
1158 }\r
1159 //\r
1160 // First we figure out how many boot devices with same device type respectively\r
1161 //\r
1162 for (Index = 0; Index < BbsCount; Index++) {\r
1163 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
1164 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)\r
1165 ) {\r
1166 continue;\r
1167 }\r
1168\r
1169 switch (LocalBbsTable[Index].DeviceType) {\r
1170 case BBS_FLOPPY:\r
1171 FDCount++;\r
1172 break;\r
1173\r
1174 case BBS_HARDDISK:\r
1175 HDCount++;\r
1176 break;\r
1177\r
1178 case BBS_CDROM:\r
1179 CDCount++;\r
1180 break;\r
1181\r
1182 case BBS_EMBED_NETWORK:\r
1183 NETCount++;\r
1184 break;\r
1185\r
1186 case BBS_BEV_DEVICE:\r
1187 BEVCount++;\r
1188 break;\r
1189\r
1190 default:\r
1191 break;\r
1192 }\r
1193 }\r
1194\r
1195 TotalSize += (HeaderSize + FDCount * sizeof (UINT16));\r
1196 TotalSize += (HeaderSize + HDCount * sizeof (UINT16));\r
1197 TotalSize += (HeaderSize + CDCount * sizeof (UINT16));\r
1198 TotalSize += (HeaderSize + NETCount * sizeof (UINT16));\r
1199 TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));\r
1200\r
1201 NewDevOrder = AllocateZeroPool (TotalSize);\r
1202 if (NULL == NewDevOrder) {\r
1203 return EFI_OUT_OF_RESOURCES;\r
1204 }\r
1205\r
1206\r
1207\r
1208 //\r
1209 // copy FD\r
1210 //\r
1211 Ptr = DevOrder;\r
1212 NewPtr = NewDevOrder;\r
1213 NewPtr->BbsType = Ptr->BbsType;\r
1214 NewPtr->Length = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));\r
1215 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
1216 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||\r
1217 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
1218 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY\r
1219 ) {\r
1220 continue;\r
1221 }\r
1222\r
1223 NewPtr->Data[FDIndex] = Ptr->Data[Index];\r
1224 FDIndex++;\r
1225 }\r
1226 NewFDPtr = NewPtr->Data;\r
1227\r
1228 //\r
1229 // copy HD\r
1230 //\r
1231 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
1232 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
1233 NewPtr->BbsType = Ptr->BbsType;\r
1234 NewPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));\r
1235 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
1236 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||\r
1237 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
1238 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||\r
1239 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK\r
1240 ) {\r
1241 continue;\r
1242 }\r
1243\r
1244 NewPtr->Data[HDIndex] = Ptr->Data[Index];\r
1245 HDIndex++;\r
1246 }\r
1247 NewHDPtr = NewPtr->Data;\r
1248\r
1249 //\r
1250 // copy CD\r
1251 //\r
1252 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
1253 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
1254 NewPtr->BbsType = Ptr->BbsType;\r
1255 NewPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));\r
1256 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
1257 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||\r
1258 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
1259 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||\r
1260 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM\r
1261 ) {\r
1262 continue;\r
1263 }\r
1264\r
1265 NewPtr->Data[CDIndex] = Ptr->Data[Index];\r
1266 CDIndex++;\r
1267 }\r
1268 NewCDPtr = NewPtr->Data;\r
1269\r
1270 //\r
1271 // copy NET\r
1272 //\r
1273 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
1274 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
1275 NewPtr->BbsType = Ptr->BbsType;\r
1276 NewPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));\r
1277 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
1278 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||\r
1279 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
1280 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||\r
1281 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK\r
1282 ) {\r
1283 continue;\r
1284 }\r
1285\r
1286 NewPtr->Data[NETIndex] = Ptr->Data[Index];\r
1287 NETIndex++;\r
1288 }\r
1289 NewNETPtr = NewPtr->Data;\r
0a6f4824 1290\r
16e5944a
RN
1291 //\r
1292 // copy BEV\r
1293 //\r
1294 Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);\r
1295 NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);\r
1296 NewPtr->BbsType = Ptr->BbsType;\r
1297 NewPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));\r
1298 for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {\r
1299 if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||\r
1300 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
1301 LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||\r
1302 LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE\r
1303 ) {\r
1304 continue;\r
1305 }\r
1306\r
1307 NewPtr->Data[BEVIndex] = Ptr->Data[Index];\r
1308 BEVIndex++;\r
1309 }\r
1310 NewBEVPtr = NewPtr->Data;\r
1311\r
1312 for (Index = 0; Index < BbsCount; Index++) {\r
1313 if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
1314 (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)\r
1315 ) {\r
1316 continue;\r
1317 }\r
1318\r
1319 switch (LocalBbsTable[Index].DeviceType) {\r
1320 case BBS_FLOPPY:\r
1321 Idx = &FDIndex;\r
1322 NewDevPtr = NewFDPtr;\r
1323 break;\r
1324\r
1325 case BBS_HARDDISK:\r
1326 Idx = &HDIndex;\r
1327 NewDevPtr = NewHDPtr;\r
1328 break;\r
1329\r
1330 case BBS_CDROM:\r
1331 Idx = &CDIndex;\r
1332 NewDevPtr = NewCDPtr;\r
1333 break;\r
1334\r
1335 case BBS_EMBED_NETWORK:\r
1336 Idx = &NETIndex;\r
1337 NewDevPtr = NewNETPtr;\r
1338 break;\r
1339\r
1340 case BBS_BEV_DEVICE:\r
1341 Idx = &BEVIndex;\r
1342 NewDevPtr = NewBEVPtr;\r
1343 break;\r
1344\r
1345 default:\r
1346 Idx = NULL;\r
1347 break;\r
1348 }\r
1349 //\r
1350 // at this point we have copied those valid indexes to new buffer\r
1351 // and we should check if there is any new appeared boot device\r
1352 //\r
1353 if (Idx != NULL) {\r
1354 for (Index2 = 0; Index2 < *Idx; Index2++) {\r
1355 if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {\r
1356 break;\r
1357 }\r
1358 }\r
1359\r
1360 if (Index2 == *Idx) {\r
1361 //\r
1362 // Index2 == *Idx means we didn't find Index\r
1363 // so Index is a new appeared device's index in BBS table\r
1364 // insert it before disabled indexes.\r
1365 //\r
1366 for (Index2 = 0; Index2 < *Idx; Index2++) {\r
1367 if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {\r
1368 break;\r
1369 }\r
1370 }\r
1371 CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16));\r
1372 NewDevPtr[Index2] = (UINT16) (Index & 0xFF);\r
1373 (*Idx)++;\r
1374 }\r
1375 }\r
1376 }\r
1377\r
1378 FreePool (DevOrder);\r
1379\r
1380 Status = gRT->SetVariable (\r
1381 VAR_LEGACY_DEV_ORDER,\r
1382 &gEfiLegacyDevOrderVariableGuid,\r
32d258b5 1383 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
16e5944a
RN
1384 TotalSize,\r
1385 NewDevOrder\r
1386 );\r
1387 FreePool (NewDevOrder);\r
1388\r
1389 return Status;\r
1390}\r
1391\r
1392/**\r
1393 Set Boot Priority for specified device type.\r
1394\r
1395 @param DeviceType The device type.\r
1396 @param BbsIndex The BBS index to set the highest priority. Ignore when -1.\r
1397 @param LocalBbsTable The BBS table.\r
1398 @param Priority The prority table.\r
1399\r
1400 @retval EFI_SUCCESS The function completes successfully.\r
1401 @retval EFI_NOT_FOUND Failed to find device.\r
1402 @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.\r
1403\r
1404**/\r
1405EFI_STATUS\r
1406BdsSetBootPriority4SameTypeDev (\r
1407 IN UINT16 DeviceType,\r
1408 IN UINTN BbsIndex,\r
1409 IN OUT BBS_TABLE *LocalBbsTable,\r
1410 IN OUT UINT16 *Priority\r
1411 )\r
1412{\r
1413 LEGACY_DEV_ORDER_ENTRY *DevOrder;\r
1414 LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;\r
1415 UINTN DevOrderSize;\r
1416 UINTN Index;\r
1417\r
1418 DevOrder = BdsLibGetVariableAndSize (\r
1419 VAR_LEGACY_DEV_ORDER,\r
1420 &gEfiLegacyDevOrderVariableGuid,\r
1421 &DevOrderSize\r
1422 );\r
1423 if (NULL == DevOrder) {\r
1424 return EFI_OUT_OF_RESOURCES;\r
1425 }\r
1426\r
1427 DevOrderPtr = DevOrder;\r
1428 while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {\r
1429 if (DevOrderPtr->BbsType == DeviceType) {\r
1430 break;\r
1431 }\r
1432\r
1a45b15e 1433 DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length);\r
16e5944a
RN
1434 }\r
1435\r
1436 if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {\r
1437 FreePool (DevOrder);\r
1438 return EFI_NOT_FOUND;\r
1439 }\r
1440\r
1441 if (BbsIndex != (UINTN) -1) {\r
1442 LocalBbsTable[BbsIndex].BootPriority = *Priority;\r
1443 (*Priority)++;\r
1444 }\r
1445 //\r
1446 // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.\r
1447 //\r
1448 for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {\r
1449 if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {\r
1450 //\r
1451 // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;\r
1452 //\r
1453 } else if (DevOrderPtr->Data[Index] != BbsIndex) {\r
1454 LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;\r
1455 (*Priority)++;\r
1456 }\r
1457 }\r
1458\r
1459 FreePool (DevOrder);\r
1460 return EFI_SUCCESS;\r
1461}\r
1462\r
1463/**\r
1464 Print the BBS Table.\r
1465\r
1466 @param LocalBbsTable The BBS table.\r
1467 @param BbsCount The count of entry in BBS table.\r
1468**/\r
1469VOID\r
1470PrintBbsTable (\r
1471 IN BBS_TABLE *LocalBbsTable,\r
1472 IN UINT16 BbsCount\r
1473 )\r
1474{\r
1475 UINT16 Idx;\r
1476\r
1477 DEBUG ((DEBUG_ERROR, "\n"));\r
1478 DEBUG ((DEBUG_ERROR, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));\r
1479 DEBUG ((DEBUG_ERROR, "=============================================\n"));\r
1480 for (Idx = 0; Idx < BbsCount; Idx++) {\r
1481 if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) ||\r
1482 (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) ||\r
1483 (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY)\r
1484 ) {\r
1485 continue;\r
1486 }\r
1487\r
1488 DEBUG (\r
1489 (DEBUG_ERROR,\r
1490 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",\r
1491 (UINTN) Idx,\r
1492 (UINTN) LocalBbsTable[Idx].BootPriority,\r
1493 (UINTN) LocalBbsTable[Idx].Bus,\r
1494 (UINTN) LocalBbsTable[Idx].Device,\r
1495 (UINTN) LocalBbsTable[Idx].Function,\r
1496 (UINTN) LocalBbsTable[Idx].Class,\r
1497 (UINTN) LocalBbsTable[Idx].SubClass,\r
1498 (UINTN) LocalBbsTable[Idx].DeviceType,\r
1499 (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,\r
1500 (UINTN) LocalBbsTable[Idx].BootHandlerSegment,\r
1501 (UINTN) LocalBbsTable[Idx].BootHandlerOffset,\r
1502 (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),\r
1503 (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset))\r
1504 );\r
1505 }\r
1506\r
1507 DEBUG ((DEBUG_ERROR, "\n"));\r
1508}\r
1509\r
1510/**\r
1511 Set the boot priority for BBS entries based on boot option entry and boot order.\r
1512\r
1513 @param Entry The boot option is to be checked for refresh BBS table.\r
0a6f4824 1514\r
16e5944a
RN
1515 @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.\r
1516 @retval EFI_NOT_FOUND BBS entries can't be found.\r
1517 @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.\r
1518**/\r
1519EFI_STATUS\r
1520EFIAPI\r
1521BdsRefreshBbsTableForBoot (\r
1522 IN BDS_COMMON_OPTION *Entry\r
1523 )\r
1524{\r
1525 EFI_STATUS Status;\r
1526 UINT16 BbsIndex;\r
1527 UINT16 HddCount;\r
1528 UINT16 BbsCount;\r
1529 HDD_INFO *LocalHddInfo;\r
1530 BBS_TABLE *LocalBbsTable;\r
1531 UINT16 DevType;\r
1532 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
1533 UINTN Index;\r
1534 UINT16 Priority;\r
1535 UINT16 *BootOrder;\r
1536 UINTN BootOrderSize;\r
1537 UINT8 *BootOptionVar;\r
1538 UINTN BootOptionSize;\r
1539 CHAR16 BootOption[9];\r
1540 UINT8 *Ptr;\r
1541 UINT16 DevPathLen;\r
1542 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
1543 UINT16 *DeviceType;\r
1544 UINTN DeviceTypeCount;\r
1545 UINTN DeviceTypeIndex;\r
1546\r
1547 HddCount = 0;\r
1548 BbsCount = 0;\r
1549 LocalHddInfo = NULL;\r
1550 LocalBbsTable = NULL;\r
1551 DevType = BBS_UNKNOWN;\r
1552\r
1553 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
1554 if (EFI_ERROR (Status)) {\r
1555 return Status;\r
1556 }\r
1557\r
1558 LegacyBios->GetBbsInfo (\r
1559 LegacyBios,\r
1560 &HddCount,\r
1561 &LocalHddInfo,\r
1562 &BbsCount,\r
1563 &LocalBbsTable\r
1564 );\r
1565 //\r
1566 // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY\r
1567 // We will set them according to the settings setup by user\r
1568 //\r
1569 for (Index = 0; Index < BbsCount; Index++) {\r
1570 if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) ||\r
1571 (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) ||\r
1572 (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) {\r
1573 LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
1574 }\r
1575 }\r
1576 //\r
1577 // boot priority always starts at 0\r
1578 //\r
1579 Priority = 0;\r
1580 if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) {\r
1581 //\r
1582 // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.\r
1583 //\r
1584 DevType = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType;\r
1585 BbsIndex = *(UINT16 *) ((BBS_TABLE *) Entry->LoadOptions + 1);\r
1586 Status = BdsSetBootPriority4SameTypeDev (\r
1587 DevType,\r
1588 BbsIndex,\r
1589 LocalBbsTable,\r
1590 &Priority\r
1591 );\r
1592 if (EFI_ERROR (Status)) {\r
1593 return Status;\r
1594 }\r
1595 }\r
1596 //\r
1597 // we have to set the boot priority for other BBS entries with different device types\r
1598 //\r
1599 BootOrder = BdsLibGetVariableAndSize (\r
1600 L"BootOrder",\r
1601 &gEfiGlobalVariableGuid,\r
1602 &BootOrderSize\r
1603 );\r
1604 DeviceType = AllocatePool (BootOrderSize + sizeof (UINT16));\r
1605 ASSERT (DeviceType != NULL);\r
1606\r
1607 DeviceType[0] = DevType;\r
1608 DeviceTypeCount = 1;\r
1609 for (Index = 0; ((BootOrder != NULL) && (Index < BootOrderSize / sizeof (UINT16))); Index++) {\r
1610 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
1611 BootOptionVar = BdsLibGetVariableAndSize (\r
1612 BootOption,\r
1613 &gEfiGlobalVariableGuid,\r
1614 &BootOptionSize\r
1615 );\r
1616 if (NULL == BootOptionVar) {\r
1617 continue;\r
1618 }\r
1619\r
1620 Ptr = BootOptionVar;\r
1621\r
1622 Ptr += sizeof (UINT32);\r
1623 DevPathLen = *(UINT16 *) Ptr;\r
1624 Ptr += sizeof (UINT16);\r
1625 Ptr += StrSize ((UINT16 *) Ptr);\r
1626 DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
1627 if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {\r
1628 FreePool (BootOptionVar);\r
1629 continue;\r
1630 }\r
1631\r
1632 Ptr += DevPathLen;\r
1633 DevType = ((BBS_TABLE *) Ptr)->DeviceType;\r
1634 for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) {\r
1635 if (DeviceType[DeviceTypeIndex] == DevType) {\r
1636 break;\r
1637 }\r
1638 }\r
1639 if (DeviceTypeIndex < DeviceTypeCount) {\r
1640 //\r
1641 // We don't want to process twice for a device type\r
1642 //\r
1643 FreePool (BootOptionVar);\r
1644 continue;\r
1645 }\r
1646\r
1647 DeviceType[DeviceTypeCount] = DevType;\r
1648 DeviceTypeCount++;\r
1649\r
1650 Status = BdsSetBootPriority4SameTypeDev (\r
1651 DevType,\r
1652 (UINTN) -1,\r
1653 LocalBbsTable,\r
1654 &Priority\r
1655 );\r
1656 FreePool (BootOptionVar);\r
1657 if (EFI_ERROR (Status)) {\r
1658 break;\r
1659 }\r
1660 }\r
1661\r
673c8930
ED
1662 FreePool (DeviceType);\r
1663\r
16e5944a
RN
1664 if (BootOrder != NULL) {\r
1665 FreePool (BootOrder);\r
1666 }\r
1667\r
1668 DEBUG_CODE_BEGIN();\r
1669 PrintBbsTable (LocalBbsTable, BbsCount);\r
1670 DEBUG_CODE_END();\r
1671\r
1672 return Status;\r
1673}\r
5c08e117 1674\r
1675/**\r
1676 Boot the legacy system with the boot option\r
1677\r
1678 @param Option The legacy boot option which have BBS device path\r
1679\r
1680 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support\r
1681 legacy boot.\r
1682 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().\r
1683\r
1684**/\r
1685EFI_STATUS\r
1686BdsLibDoLegacyBoot (\r
1687 IN BDS_COMMON_OPTION *Option\r
1688 )\r
1689{\r
1690 EFI_STATUS Status;\r
1691 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
26c0ba77 1692 EFI_EVENT LegacyBootEvent;\r
5c08e117 1693\r
1694 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);\r
1695 if (EFI_ERROR (Status)) {\r
1696 //\r
1697 // If no LegacyBios protocol we do not support legacy boot\r
1698 //\r
1699 return EFI_UNSUPPORTED;\r
1700 }\r
1701 //\r
1702 // Notes: if we separate the int 19, then we don't need to refresh BBS\r
1703 //\r
1704 BdsRefreshBbsTableForBoot (Option);\r
1705\r
1706 //\r
cd6a3b15 1707 // Write boot to OS performance data for legacy boot.\r
5c08e117 1708 //\r
1709 PERF_CODE (\r
26c0ba77
SZ
1710 //\r
1711 // Create an event to be signalled when Legacy Boot occurs to write performance data.\r
1712 //\r
1713 Status = EfiCreateEventLegacyBootEx(\r
1714 TPL_NOTIFY,\r
b8d06293 1715 BmEndOfBdsPerfCode,\r
0a6f4824 1716 NULL,\r
26c0ba77
SZ
1717 &LegacyBootEvent\r
1718 );\r
1719 ASSERT_EFI_ERROR (Status);\r
5c08e117 1720 );\r
1721\r
1722 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));\r
1723 return LegacyBios->LegacyBoot (\r
1724 LegacyBios,\r
1725 (BBS_BBS_DEVICE_PATH *) Option->DevicePath,\r
1726 Option->LoadOptionsSize,\r
1727 Option->LoadOptions\r
1728 );\r
1729}\r
1730\r
3d7decbc 1731/**\r
1732 Internal function to check if the input boot option is a valid EFI NV Boot####.\r
1733\r
1734 @param OptionToCheck Boot option to be checked.\r
1735\r
1736 @retval TRUE This boot option matches a valid EFI NV Boot####.\r
1737 @retval FALSE If not.\r
128efbbc 1738\r
3d7decbc 1739**/\r
3d7decbc 1740BOOLEAN\r
1741IsBootOptionValidNVVarialbe (\r
1742 IN BDS_COMMON_OPTION *OptionToCheck\r
1743 )\r
1744{\r
1745 LIST_ENTRY TempList;\r
1746 BDS_COMMON_OPTION *BootOption;\r
1747 BOOLEAN Valid;\r
1748 CHAR16 OptionName[20];\r
1749\r
1750 Valid = FALSE;\r
1751\r
1752 InitializeListHead (&TempList);\r
1753 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToCheck->BootCurrent);\r
5c08e117 1754\r
3d7decbc 1755 BootOption = BdsLibVariableToOption (&TempList, OptionName);\r
1756 if (BootOption == NULL) {\r
1757 return FALSE;\r
1758 }\r
1759\r
1760 //\r
128efbbc 1761 // If the Boot Option Number and Device Path matches, OptionToCheck matches a\r
3d7decbc 1762 // valid EFI NV Boot####.\r
1763 //\r
1764 if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) &&\r
1765 (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0))\r
1766 {\r
1767 Valid = TRUE;\r
1768 }\r
1769\r
1770 FreePool (BootOption);\r
128efbbc 1771\r
3d7decbc 1772 return Valid;\r
1773}\r
7389fdd0 1774\r
1775/**\r
1776 Check whether a USB device match the specified USB Class device path. This\r
1777 function follows "Load Option Processing" behavior in UEFI specification.\r
1778\r
1779 @param UsbIo USB I/O protocol associated with the USB device.\r
1780 @param UsbClass The USB Class device path to match.\r
1781\r
1782 @retval TRUE The USB device match the USB Class device path.\r
1783 @retval FALSE The USB device does not match the USB Class device path.\r
1784\r
1785**/\r
1786BOOLEAN\r
1787BdsMatchUsbClass (\r
1788 IN EFI_USB_IO_PROTOCOL *UsbIo,\r
1789 IN USB_CLASS_DEVICE_PATH *UsbClass\r
1790 )\r
1791{\r
1792 EFI_STATUS Status;\r
1793 EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
1794 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;\r
1795 UINT8 DeviceClass;\r
1796 UINT8 DeviceSubClass;\r
1797 UINT8 DeviceProtocol;\r
1798\r
1799 if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||\r
1800 (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){\r
1801 return FALSE;\r
1802 }\r
1803\r
1804 //\r
1805 // Check Vendor Id and Product Id.\r
1806 //\r
1807 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
1808 if (EFI_ERROR (Status)) {\r
1809 return FALSE;\r
1810 }\r
1811\r
1812 if ((UsbClass->VendorId != 0xffff) &&\r
1813 (UsbClass->VendorId != DevDesc.IdVendor)) {\r
1814 return FALSE;\r
1815 }\r
1816\r
1817 if ((UsbClass->ProductId != 0xffff) &&\r
1818 (UsbClass->ProductId != DevDesc.IdProduct)) {\r
1819 return FALSE;\r
1820 }\r
1821\r
1822 DeviceClass = DevDesc.DeviceClass;\r
1823 DeviceSubClass = DevDesc.DeviceSubClass;\r
1824 DeviceProtocol = DevDesc.DeviceProtocol;\r
1825 if (DeviceClass == 0) {\r
1826 //\r
1827 // If Class in Device Descriptor is set to 0, use the Class, SubClass and\r
1828 // Protocol in Interface Descriptor instead.\r
1829 //\r
1830 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
1831 if (EFI_ERROR (Status)) {\r
1832 return FALSE;\r
1833 }\r
1834\r
1835 DeviceClass = IfDesc.InterfaceClass;\r
1836 DeviceSubClass = IfDesc.InterfaceSubClass;\r
1837 DeviceProtocol = IfDesc.InterfaceProtocol;\r
1838 }\r
1839\r
1840 //\r
1841 // Check Class, SubClass and Protocol.\r
1842 //\r
1843 if ((UsbClass->DeviceClass != 0xff) &&\r
1844 (UsbClass->DeviceClass != DeviceClass)) {\r
1845 return FALSE;\r
1846 }\r
1847\r
1848 if ((UsbClass->DeviceSubClass != 0xff) &&\r
1849 (UsbClass->DeviceSubClass != DeviceSubClass)) {\r
1850 return FALSE;\r
1851 }\r
1852\r
1853 if ((UsbClass->DeviceProtocol != 0xff) &&\r
1854 (UsbClass->DeviceProtocol != DeviceProtocol)) {\r
1855 return FALSE;\r
1856 }\r
1857\r
1858 return TRUE;\r
1859}\r
1860\r
1861/**\r
1862 Check whether a USB device match the specified USB WWID device path. This\r
1863 function follows "Load Option Processing" behavior in UEFI specification.\r
1864\r
1865 @param UsbIo USB I/O protocol associated with the USB device.\r
1866 @param UsbWwid The USB WWID device path to match.\r
1867\r
1868 @retval TRUE The USB device match the USB WWID device path.\r
1869 @retval FALSE The USB device does not match the USB WWID device path.\r
1870\r
1871**/\r
1872BOOLEAN\r
1873BdsMatchUsbWwid (\r
1874 IN EFI_USB_IO_PROTOCOL *UsbIo,\r
1875 IN USB_WWID_DEVICE_PATH *UsbWwid\r
1876 )\r
1877{\r
1878 EFI_STATUS Status;\r
1879 EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
1880 EFI_USB_INTERFACE_DESCRIPTOR IfDesc;\r
1881 UINT16 *LangIdTable;\r
1882 UINT16 TableSize;\r
1883 UINT16 Index;\r
1884 CHAR16 *CompareStr;\r
1885 UINTN CompareLen;\r
1886 CHAR16 *SerialNumberStr;\r
1887 UINTN Length;\r
1888\r
1889 if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||\r
1890 (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP )){\r
1891 return FALSE;\r
1892 }\r
1893\r
1894 //\r
1895 // Check Vendor Id and Product Id.\r
1896 //\r
1897 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
1898 if (EFI_ERROR (Status)) {\r
1899 return FALSE;\r
1900 }\r
1901 if ((DevDesc.IdVendor != UsbWwid->VendorId) ||\r
1902 (DevDesc.IdProduct != UsbWwid->ProductId)) {\r
1903 return FALSE;\r
1904 }\r
1905\r
1906 //\r
1907 // Check Interface Number.\r
1908 //\r
1909 Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);\r
1910 if (EFI_ERROR (Status)) {\r
1911 return FALSE;\r
1912 }\r
1913 if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {\r
1914 return FALSE;\r
1915 }\r
1916\r
1917 //\r
1918 // Check Serial Number.\r
1919 //\r
1920 if (DevDesc.StrSerialNumber == 0) {\r
1921 return FALSE;\r
1922 }\r
1923\r
1924 //\r
1925 // Get all supported languages.\r
1926 //\r
1927 TableSize = 0;\r
1928 LangIdTable = NULL;\r
1929 Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);\r
1930 if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {\r
1931 return FALSE;\r
1932 }\r
1933\r
1934 //\r
1935 // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.\r
1936 //\r
1937 CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);\r
1938 CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);\r
1939 if (CompareStr[CompareLen - 1] == L'\0') {\r
1940 CompareLen--;\r
1941 }\r
1942\r
1943 //\r
1944 // Compare serial number in each supported language.\r
1945 //\r
1946 for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {\r
1947 SerialNumberStr = NULL;\r
1948 Status = UsbIo->UsbGetStringDescriptor (\r
1949 UsbIo,\r
1950 LangIdTable[Index],\r
1951 DevDesc.StrSerialNumber,\r
1952 &SerialNumberStr\r
1953 );\r
1954 if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {\r
1955 continue;\r
1956 }\r
1957\r
1958 Length = StrLen (SerialNumberStr);\r
1959 if ((Length >= CompareLen) &&\r
1960 (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {\r
1961 FreePool (SerialNumberStr);\r
1962 return TRUE;\r
1963 }\r
1964\r
1965 FreePool (SerialNumberStr);\r
1966 }\r
1967\r
1968 return FALSE;\r
1969}\r
1970\r
1971/**\r
9972247d 1972 Find a USB device path which match the specified short-form device path start\r
0a6f4824 1973 with USB Class or USB WWID device path and load the boot file then return the\r
9972247d 1974 image handle. If ParentDevicePath is NULL, this function will search in all USB\r
1975 devices of the platform. If ParentDevicePath is not NULL,this function will only\r
1976 search in its child devices.\r
7389fdd0 1977\r
1978 @param ParentDevicePath The device path of the parent.\r
1979 @param ShortFormDevicePath The USB Class or USB WWID device path to match.\r
1980\r
9972247d 1981 @return The image Handle if find load file from specified short-form device path\r
1982 or NULL if not found.\r
7389fdd0 1983\r
1984**/\r
1985EFI_HANDLE *\r
1986BdsFindUsbDevice (\r
1987 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
1988 IN EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath\r
1989 )\r
1990{\r
1991 EFI_STATUS Status;\r
1992 UINTN UsbIoHandleCount;\r
1993 EFI_HANDLE *UsbIoHandleBuffer;\r
1994 EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;\r
1995 EFI_USB_IO_PROTOCOL *UsbIo;\r
1996 UINTN Index;\r
1997 UINTN ParentSize;\r
1998 UINTN Size;\r
9972247d 1999 EFI_HANDLE ImageHandle;\r
2000 EFI_HANDLE Handle;\r
2001 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;\r
2002 EFI_DEVICE_PATH_PROTOCOL *NextDevicePath;\r
2003\r
2004 FullDevicePath = NULL;\r
2005 ImageHandle = NULL;\r
7389fdd0 2006\r
2007 //\r
2008 // Get all UsbIo Handles.\r
2009 //\r
2010 UsbIoHandleCount = 0;\r
2011 UsbIoHandleBuffer = NULL;\r
2012 Status = gBS->LocateHandleBuffer (\r
2013 ByProtocol,\r
2014 &gEfiUsbIoProtocolGuid,\r
2015 NULL,\r
2016 &UsbIoHandleCount,\r
2017 &UsbIoHandleBuffer\r
2018 );\r
2019 if (EFI_ERROR (Status) || (UsbIoHandleCount == 0) || (UsbIoHandleBuffer == NULL)) {\r
2020 return NULL;\r
2021 }\r
2022\r
7389fdd0 2023 ParentSize = (ParentDevicePath == NULL) ? 0 : GetDevicePathSize (ParentDevicePath);\r
2024 for (Index = 0; Index < UsbIoHandleCount; Index++) {\r
2025 //\r
2026 // Get the Usb IO interface.\r
2027 //\r
2028 Status = gBS->HandleProtocol(\r
2029 UsbIoHandleBuffer[Index],\r
2030 &gEfiUsbIoProtocolGuid,\r
2031 (VOID **) &UsbIo\r
2032 );\r
2033 if (EFI_ERROR (Status)) {\r
2034 continue;\r
2035 }\r
2036\r
9972247d 2037 UsbIoDevicePath = DevicePathFromHandle (UsbIoHandleBuffer[Index]);\r
2038 if (UsbIoDevicePath == NULL) {\r
2039 continue;\r
2040 }\r
2041\r
7389fdd0 2042 if (ParentDevicePath != NULL) {\r
2043 //\r
2044 // Compare starting part of UsbIoHandle's device path with ParentDevicePath.\r
2045 //\r
7389fdd0 2046 Size = GetDevicePathSize (UsbIoDevicePath);\r
2047 if ((Size < ParentSize) ||\r
2048 (CompareMem (UsbIoDevicePath, ParentDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0)) {\r
2049 continue;\r
2050 }\r
2051 }\r
2052\r
2053 if (BdsMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ShortFormDevicePath) ||\r
2054 BdsMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ShortFormDevicePath)) {\r
9972247d 2055 //\r
2056 // Try to find if there is the boot file in this DevicePath\r
2057 //\r
2058 NextDevicePath = NextDevicePathNode (ShortFormDevicePath);\r
2059 if (!IsDevicePathEnd (NextDevicePath)) {\r
2060 FullDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePath);\r
2061 //\r
2062 // Connect the full device path, so that Simple File System protocol\r
2063 // could be installed for this USB device.\r
2064 //\r
2065 BdsLibConnectDevicePath (FullDevicePath);\r
79b7a6a1 2066 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
9972247d 2067 Status = gBS->LoadImage (\r
2068 TRUE,\r
2069 gImageHandle,\r
2070 FullDevicePath,\r
2071 NULL,\r
2072 0,\r
2073 &ImageHandle\r
2074 );\r
2075 FreePool (FullDevicePath);\r
2076 } else {\r
2077 FullDevicePath = UsbIoDevicePath;\r
2078 Status = EFI_NOT_FOUND;\r
2079 }\r
2080\r
2081 //\r
2082 // If we didn't find an image directly, we need to try as if it is a removable device boot option\r
2083 // and load the image according to the default boot behavior for removable device.\r
2084 //\r
2085 if (EFI_ERROR (Status)) {\r
2086 //\r
2087 // check if there is a bootable removable media could be found in this device path ,\r
2088 // and get the bootable media handle\r
2089 //\r
2090 Handle = BdsLibGetBootableHandle(UsbIoDevicePath);\r
2091 if (Handle == NULL) {\r
2092 continue;\r
2093 }\r
2094 //\r
2095 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media\r
2096 // machinename is ia32, ia64, x64, ...\r
2097 //\r
2098 FullDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
2099 if (FullDevicePath != NULL) {\r
79b7a6a1 2100 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
9972247d 2101 Status = gBS->LoadImage (\r
2102 TRUE,\r
2103 gImageHandle,\r
2104 FullDevicePath,\r
2105 NULL,\r
2106 0,\r
2107 &ImageHandle\r
2108 );\r
2109 if (EFI_ERROR (Status)) {\r
2110 //\r
2111 // The DevicePath failed, and it's not a valid\r
2112 // removable media device.\r
2113 //\r
2114 continue;\r
2115 }\r
2116 } else {\r
2117 continue;\r
2118 }\r
2119 }\r
7389fdd0 2120 break;\r
2121 }\r
2122 }\r
2123\r
2124 FreePool (UsbIoHandleBuffer);\r
9972247d 2125 return ImageHandle;\r
7389fdd0 2126}\r
2127\r
2128/**\r
2129 Expand USB Class or USB WWID device path node to be full device path of a USB\r
0a6f4824 2130 device in platform then load the boot file on this full device path and return the\r
9972247d 2131 image handle.\r
7389fdd0 2132\r
2133 This function support following 4 cases:\r
2134 1) Boot Option device path starts with a USB Class or USB WWID device path,\r
2135 and there is no Media FilePath device path in the end.\r
2136 In this case, it will follow Removable Media Boot Behavior.\r
2137 2) Boot Option device path starts with a USB Class or USB WWID device path,\r
2138 and ended with Media FilePath device path.\r
2139 3) Boot Option device path starts with a full device path to a USB Host Controller,\r
2140 contains a USB Class or USB WWID device path node, while not ended with Media\r
2141 FilePath device path. In this case, it will follow Removable Media Boot Behavior.\r
2142 4) Boot Option device path starts with a full device path to a USB Host Controller,\r
2143 contains a USB Class or USB WWID device path node, and ended with Media\r
2144 FilePath device path.\r
2145\r
2146 @param DevicePath The Boot Option device path.\r
2147\r
9972247d 2148 @return The image handle of boot file, or NULL if there is no boot file found in\r
2149 the specified USB Class or USB WWID device path.\r
7389fdd0 2150\r
2151**/\r
9972247d 2152EFI_HANDLE *\r
7389fdd0 2153BdsExpandUsbShortFormDevicePath (\r
2154 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
2155 )\r
2156{\r
9972247d 2157 EFI_HANDLE *ImageHandle;\r
7389fdd0 2158 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
7389fdd0 2159 EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath;\r
2160\r
2161 //\r
2162 // Search for USB Class or USB WWID device path node.\r
2163 //\r
2164 ShortFormDevicePath = NULL;\r
9972247d 2165 ImageHandle = NULL;\r
2166 TempDevicePath = DevicePath;\r
7389fdd0 2167 while (!IsDevicePathEnd (TempDevicePath)) {\r
2168 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
2169 ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||\r
2170 (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {\r
2171 ShortFormDevicePath = TempDevicePath;\r
2172 break;\r
2173 }\r
7389fdd0 2174 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
2175 }\r
2176\r
2177 if (ShortFormDevicePath == NULL) {\r
2178 //\r
2179 // No USB Class or USB WWID device path node found, do nothing.\r
2180 //\r
2181 return NULL;\r
2182 }\r
2183\r
2184 if (ShortFormDevicePath == DevicePath) {\r
2185 //\r
2186 // Boot Option device path starts with USB Class or USB WWID device path.\r
2187 //\r
9972247d 2188 ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);\r
2189 if (ImageHandle == NULL) {\r
7389fdd0 2190 //\r
2191 // Failed to find a match in existing devices, connect the short form USB\r
2192 // device path and try again.\r
2193 //\r
2194 BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath);\r
9972247d 2195 ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);\r
7389fdd0 2196 }\r
2197 } else {\r
2198 //\r
2199 // Boot Option device path contains USB Class or USB WWID device path node.\r
2200 //\r
2201\r
2202 //\r
2203 // Prepare the parent device path for search.\r
2204 //\r
2205 TempDevicePath = DuplicateDevicePath (DevicePath);\r
2206 ASSERT (TempDevicePath != NULL);\r
2207 SetDevicePathEndNode (((UINT8 *) TempDevicePath) + ((UINTN) ShortFormDevicePath - (UINTN) DevicePath));\r
2208\r
2209 //\r
9972247d 2210 // The USB Host Controller device path is already in Boot Option device path\r
7389fdd0 2211 // and USB Bus driver already support RemainingDevicePath starts with USB\r
2212 // Class or USB WWID device path, so just search in existing USB devices and\r
2213 // doesn't perform ConnectController here.\r
2214 //\r
9972247d 2215 ImageHandle = BdsFindUsbDevice (TempDevicePath, ShortFormDevicePath);\r
7389fdd0 2216 FreePool (TempDevicePath);\r
2217 }\r
2218\r
9972247d 2219 return ImageHandle;\r
7389fdd0 2220}\r
2221\r
5c08e117 2222/**\r
2223 Process the boot option follow the UEFI specification and\r
2224 special treat the legacy boot option with BBS_DEVICE_PATH.\r
2225\r
2226 @param Option The boot option need to be processed\r
2227 @param DevicePath The device path which describe where to load the\r
2228 boot image or the legacy BBS device path to boot\r
2229 the legacy OS\r
2230 @param ExitDataSize The size of exit data.\r
2231 @param ExitData Data returned when Boot image failed.\r
2232\r
2233 @retval EFI_SUCCESS Boot from the input boot option successfully.\r
2234 @retval EFI_NOT_FOUND If the Device Path is not found in the system\r
2235\r
2236**/\r
2237EFI_STATUS\r
2238EFIAPI\r
2239BdsLibBootViaBootOption (\r
2240 IN BDS_COMMON_OPTION *Option,\r
2241 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
2242 OUT UINTN *ExitDataSize,\r
2243 OUT CHAR16 **ExitData OPTIONAL\r
2244 )\r
2245{\r
2246 EFI_STATUS Status;\r
2df686c6 2247 EFI_STATUS StatusLogo;\r
5c08e117 2248 EFI_HANDLE Handle;\r
2249 EFI_HANDLE ImageHandle;\r
2250 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
2251 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
2252 EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;\r
5c08e117 2253 LIST_ENTRY TempBootLists;\r
2df686c6 2254 EFI_BOOT_LOGO_PROTOCOL *BootLogo;\r
5c08e117 2255\r
1999fb31 2256 Status = EFI_SUCCESS;\r
5c08e117 2257 *ExitDataSize = 0;\r
2258 *ExitData = NULL;\r
2259\r
5c08e117 2260 //\r
2261 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a\r
2262 // full device path\r
2263 //\r
2264 WorkingDevicePath = NULL;\r
2265 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&\r
2266 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {\r
2267 WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (\r
2268 (HARDDRIVE_DEVICE_PATH *)DevicePath\r
2269 );\r
2270 if (WorkingDevicePath != NULL) {\r
2271 DevicePath = WorkingDevicePath;\r
2272 }\r
2273 }\r
7389fdd0 2274\r
5c08e117 2275 //\r
2276 // Set Boot Current\r
2277 //\r
3d7decbc 2278 if (IsBootOptionValidNVVarialbe (Option)) {\r
2279 //\r
2280 // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid.\r
2281 // In this case, "BootCurrent" is not created.\r
2282 // Only create the BootCurrent variable when it points to a valid Boot#### variable.\r
2283 //\r
69fc8f08 2284 SetVariableAndReportStatusCodeOnError (\r
3d7decbc 2285 L"BootCurrent",\r
2286 &gEfiGlobalVariableGuid,\r
2287 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2288 sizeof (UINT16),\r
2289 &Option->BootCurrent\r
2290 );\r
2291 }\r
5c08e117 2292\r
cb38c322 2293 //\r
c8a2836a 2294 // Signal the EVT_SIGNAL_READY_TO_BOOT event\r
cb38c322 2295 //\r
c8a2836a 2296 EfiSignalEventReadyToBoot();\r
cb38c322 2297\r
72861c22 2298 //\r
c8a2836a 2299 // Report Status Code to indicate ReadyToBoot event was signalled\r
72861c22 2300 //\r
c8a2836a 2301 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));\r
72861c22 2302\r
2303 //\r
2304 // Expand USB Class or USB WWID device path node to be full device path of a USB\r
2305 // device in platform then load the boot file on this full device path and get the\r
2306 // image handle.\r
2307 //\r
2308 ImageHandle = BdsExpandUsbShortFormDevicePath (DevicePath);\r
2309\r
2310 //\r
2311 // Adjust the different type memory page number just before booting\r
2312 // and save the updated info into the variable for next boot to use\r
2313 //\r
2314 BdsSetMemoryTypeInformationVariable ();\r
2315\r
5c08e117 2316 //\r
9972247d 2317 // By expanding the USB Class or WWID device path, the ImageHandle has returnned.\r
2318 // Here get the ImageHandle for the non USB class or WWID device path.\r
5c08e117 2319 //\r
9972247d 2320 if (ImageHandle == NULL) {\r
2321 ASSERT (Option->DevicePath != NULL);\r
2322 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&\r
2323 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)\r
2324 ) {\r
2325 //\r
2326 // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
2327 //\r
2328 return BdsLibDoLegacyBoot (Option);\r
5c08e117 2329 }\r
128efbbc 2330\r
5c08e117 2331 //\r
9972247d 2332 // If the boot option point to Internal FV shell, make sure it is valid\r
5c08e117 2333 //\r
9972247d 2334 Status = BdsLibUpdateFvFileDevicePath (&DevicePath, PcdGetPtr(PcdShellFile));\r
2335 if (!EFI_ERROR(Status)) {\r
2336 if (Option->DevicePath != NULL) {\r
2337 FreePool(Option->DevicePath);\r
2338 }\r
2339 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));\r
2340 ASSERT(Option->DevicePath != NULL);\r
2341 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));\r
2342 //\r
2343 // Update the shell boot option\r
2344 //\r
2345 InitializeListHead (&TempBootLists);\r
2346 BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");\r
2347\r
2348 //\r
2349 // free the temporary device path created by BdsLibUpdateFvFileDevicePath()\r
2350 //\r
2351 FreePool (DevicePath);\r
2352 DevicePath = Option->DevicePath;\r
2353 }\r
5c08e117 2354\r
9972247d 2355 DEBUG_CODE_BEGIN();\r
5c08e117 2356\r
9aa7ba01 2357 if (Option->Description == NULL) {\r
2358 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting from unknown device path\n"));\r
2359 } else {\r
2360 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));\r
ab8cc80b 2361 }\r
0a6f4824 2362\r
9972247d 2363 DEBUG_CODE_END();\r
0a6f4824 2364\r
79b7a6a1 2365 //\r
2366 // Report status code for OS Loader LoadImage.\r
2367 //\r
2368 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
9972247d 2369 Status = gBS->LoadImage (\r
2370 TRUE,\r
2371 gImageHandle,\r
2372 DevicePath,\r
2373 NULL,\r
2374 0,\r
2375 &ImageHandle\r
2376 );\r
5c08e117 2377\r
5c08e117 2378 //\r
9972247d 2379 // If we didn't find an image directly, we need to try as if it is a removable device boot option\r
2380 // and load the image according to the default boot behavior for removable device.\r
5c08e117 2381 //\r
9972247d 2382 if (EFI_ERROR (Status)) {\r
2383 //\r
2384 // check if there is a bootable removable media could be found in this device path ,\r
2385 // and get the bootable media handle\r
2386 //\r
2387 Handle = BdsLibGetBootableHandle(DevicePath);\r
cb38c322 2388 if (Handle != NULL) {\r
2389 //\r
2390 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media\r
2391 // machinename is ia32, ia64, x64, ...\r
2392 //\r
2393 FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
2394 if (FilePath != NULL) {\r
2395 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));\r
2396 Status = gBS->LoadImage (\r
2397 TRUE,\r
2398 gImageHandle,\r
2399 FilePath,\r
2400 NULL,\r
2401 0,\r
2402 &ImageHandle\r
2403 );\r
9972247d 2404 }\r
2405 }\r
5c08e117 2406 }\r
5c08e117 2407 }\r
2408 //\r
2409 // Provide the image with it's load options\r
2410 //\r
cb38c322 2411 if ((ImageHandle == NULL) || (EFI_ERROR(Status))) {\r
2412 //\r
2413 // Report Status Code to indicate that the failure to load boot option\r
2414 //\r
2415 REPORT_STATUS_CODE (\r
2416 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
2417 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)\r
0a6f4824 2418 );\r
9972247d 2419 goto Done;\r
2420 }\r
cb38c322 2421\r
5c08e117 2422 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
2423 ASSERT_EFI_ERROR (Status);\r
2424\r
2425 if (Option->LoadOptionsSize != 0) {\r
2426 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;\r
2427 ImageInfo->LoadOptions = Option->LoadOptions;\r
2428 }\r
bf0712ae
ED
2429\r
2430 //\r
2431 // Clean to NULL because the image is loaded directly from the firmwares boot manager.\r
2432 //\r
2433 ImageInfo->ParentHandle = NULL;\r
2434\r
5c08e117 2435 //\r
2436 // Before calling the image, enable the Watchdog Timer for\r
2437 // the 5 Minute period\r
2438 //\r
2439 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
2440\r
cd6a3b15 2441 //\r
2442 // Write boot to OS performance data for UEFI boot\r
2443 //\r
2444 PERF_CODE (\r
b8d06293 2445 BmEndOfBdsPerfCode (NULL, NULL);\r
cd6a3b15 2446 );\r
2447\r
79b7a6a1 2448 //\r
2449 // Report status code for OS Loader StartImage.\r
2450 //\r
2451 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));\r
2452\r
5c08e117 2453 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);\r
2454 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));\r
cb38c322 2455 if (EFI_ERROR (Status)) {\r
2456 //\r
2457 // Report Status Code to indicate that boot failure\r
2458 //\r
2459 REPORT_STATUS_CODE (\r
2460 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
2461 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)\r
2462 );\r
2463 }\r
5c08e117 2464\r
2465 //\r
2466 // Clear the Watchdog Timer after the image returns\r
2467 //\r
2468 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
2469\r
2470Done:\r
2df686c6 2471 //\r
2472 // Set Logo status invalid after trying one boot option\r
2473 //\r
2474 BootLogo = NULL;\r
2475 StatusLogo = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);\r
2476 if (!EFI_ERROR (StatusLogo) && (BootLogo != NULL)) {\r
2477 BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);\r
2478 }\r
2479\r
5c08e117 2480 //\r
2481 // Clear Boot Current\r
69fc8f08 2482 // Deleting variable with current implementation shouldn't fail.\r
5c08e117 2483 //\r
2484 gRT->SetVariable (\r
2485 L"BootCurrent",\r
2486 &gEfiGlobalVariableGuid,\r
2487 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
2488 0,\r
69fc8f08 2489 NULL\r
5c08e117 2490 );\r
2491\r
2492 return Status;\r
2493}\r
2494\r
2495\r
2496/**\r
2497 Expand a device path that starts with a hard drive media device path node to be a\r
2498 full device path that includes the full hardware path to the device. We need\r
2499 to do this so it can be booted. As an optimization the front match (the part point\r
2500 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable\r
2501 so a connect all is not required on every boot. All successful history device path\r
2502 which point to partition node (the front part) will be saved.\r
2503\r
2504 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard\r
2505 drive media device path.\r
2506 @return A Pointer to the full device path or NULL if a valid Hard Drive devic path\r
2507 cannot be found.\r
2508\r
2509**/\r
2510EFI_DEVICE_PATH_PROTOCOL *\r
2511EFIAPI\r
2512BdsExpandPartitionPartialDevicePathToFull (\r
2513 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath\r
2514 )\r
2515{\r
2516 EFI_STATUS Status;\r
2517 UINTN BlockIoHandleCount;\r
2518 EFI_HANDLE *BlockIoBuffer;\r
2519 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;\r
2520 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;\r
2521 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2522 UINTN Index;\r
2523 UINTN InstanceNum;\r
2524 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;\r
2525 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;\r
2526 UINTN CachedDevicePathSize;\r
2527 BOOLEAN DeviceExist;\r
2528 BOOLEAN NeedAdjust;\r
2529 EFI_DEVICE_PATH_PROTOCOL *Instance;\r
2530 UINTN Size;\r
2531\r
2532 FullDevicePath = NULL;\r
2533 //\r
e24fc103 2534 // Check if there is prestore HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.\r
5c08e117 2535 // If exist, search the front path which point to partition node in the variable instants.\r
e24fc103 2536 // If fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, reconnect all and search in all system\r
5c08e117 2537 //\r
f3fc9d8d
RN
2538 GetVariable2 (\r
2539 HD_BOOT_DEVICE_PATH_VARIABLE_NAME,\r
2540 &gHdBootDevicePathVariablGuid,\r
2541 (VOID **) &CachedDevicePath,\r
2542 &CachedDevicePathSize\r
2543 );\r
2544\r
2545 //\r
2546 // Delete the invalid HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.\r
2547 //\r
2548 if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {\r
2549 FreePool (CachedDevicePath);\r
2550 CachedDevicePath = NULL;\r
2551 Status = gRT->SetVariable (\r
2552 HD_BOOT_DEVICE_PATH_VARIABLE_NAME,\r
2553 &gHdBootDevicePathVariablGuid,\r
2554 0,\r
2555 0,\r
2556 NULL\r
2557 );\r
2558 ASSERT_EFI_ERROR (Status);\r
2559 }\r
128efbbc 2560\r
5c08e117 2561 if (CachedDevicePath != NULL) {\r
2562 TempNewDevicePath = CachedDevicePath;\r
2563 DeviceExist = FALSE;\r
2564 NeedAdjust = FALSE;\r
2565 do {\r
2566 //\r
2567 // Check every instance of the variable\r
2568 // First, check whether the instance contain the partition node, which is needed for distinguishing multi\r
2569 // partial partition boot option. Second, check whether the instance could be connected.\r
2570 //\r
2571 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);\r
2572 if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {\r
2573 //\r
2574 // Connect the device path instance, the device path point to hard drive media device path node\r
2575 // e.g. ACPI() /PCI()/ATA()/Partition()\r
2576 //\r
2577 Status = BdsLibConnectDevicePath (Instance);\r
2578 if (!EFI_ERROR (Status)) {\r
2579 DeviceExist = TRUE;\r
2580 break;\r
2581 }\r
2582 }\r
2583 //\r
2584 // Come here means the first instance is not matched\r
2585 //\r
2586 NeedAdjust = TRUE;\r
2587 FreePool(Instance);\r
2588 } while (TempNewDevicePath != NULL);\r
2589\r
2590 if (DeviceExist) {\r
2591 //\r
2592 // Find the matched device path.\r
2593 // Append the file path information from the boot option and return the fully expanded device path.\r
2594 //\r
2595 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
2596 FullDevicePath = AppendDevicePath (Instance, DevicePath);\r
2597\r
2598 //\r
e24fc103 2599 // Adjust the HD_BOOT_DEVICE_PATH_VARIABLE_NAME instances sequence if the matched one is not first one.\r
5c08e117 2600 //\r
2601 if (NeedAdjust) {\r
2602 //\r
2603 // First delete the matched instance.\r
2604 //\r
2605 TempNewDevicePath = CachedDevicePath;\r
2606 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );\r
2607 FreePool (TempNewDevicePath);\r
128efbbc 2608\r
5c08e117 2609 //\r
2610 // Second, append the remaining path after the matched instance\r
2611 //\r
2612 TempNewDevicePath = CachedDevicePath;\r
2613 CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );\r
2614 FreePool (TempNewDevicePath);\r
2615 //\r
2616 // Save the matching Device Path so we don't need to do a connect all next time\r
69fc8f08 2617 // Failure to set the variable only impacts the performance when next time expanding the short-form device path.\r
5c08e117 2618 //\r
2619 Status = gRT->SetVariable (\r
e24fc103
LG
2620 HD_BOOT_DEVICE_PATH_VARIABLE_NAME,\r
2621 &gHdBootDevicePathVariablGuid,\r
f3fc9d8d 2622 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
5c08e117 2623 GetDevicePathSize (CachedDevicePath),\r
2624 CachedDevicePath\r
2625 );\r
2626 }\r
128efbbc 2627\r
5c08e117 2628 FreePool (Instance);\r
2629 FreePool (CachedDevicePath);\r
2630 return FullDevicePath;\r
2631 }\r
2632 }\r
2633\r
2634 //\r
e24fc103 2635 // If we get here we fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, and now we need\r
5c08e117 2636 // to search all devices in the system for a matched partition\r
2637 //\r
2638 BdsLibConnectAllDriversToAllControllers ();\r
2639 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);\r
2640 if (EFI_ERROR (Status) || BlockIoHandleCount == 0 || BlockIoBuffer == NULL) {\r
2641 //\r
2642 // If there was an error or there are no device handles that support\r
2643 // the BLOCK_IO Protocol, then return.\r
2644 //\r
2645 return NULL;\r
2646 }\r
2647 //\r
2648 // Loop through all the device handles that support the BLOCK_IO Protocol\r
2649 //\r
2650 for (Index = 0; Index < BlockIoHandleCount; Index++) {\r
2651\r
2652 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);\r
2653 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {\r
2654 continue;\r
2655 }\r
2656\r
2657 if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {\r
2658 //\r
2659 // Find the matched partition device path\r
2660 //\r
2661 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
2662 FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);\r
2663\r
2664 //\r
e24fc103 2665 // Save the matched partition device path in HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable\r
5c08e117 2666 //\r
2667 if (CachedDevicePath != NULL) {\r
2668 //\r
e24fc103 2669 // Save the matched partition device path as first instance of HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable\r
5c08e117 2670 //\r
2671 if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {\r
2672 TempNewDevicePath = CachedDevicePath;\r
2673 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);\r
2674 FreePool(TempNewDevicePath);\r
e5a9b63c 2675 }\r
5c08e117 2676\r
e5a9b63c 2677 if (CachedDevicePath != NULL) {\r
5c08e117 2678 TempNewDevicePath = CachedDevicePath;\r
2679 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);\r
2680 FreePool(TempNewDevicePath);\r
e5a9b63c
RN
2681 } else {\r
2682 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);\r
5c08e117 2683 }\r
e5a9b63c 2684\r
5c08e117 2685 //\r
2686 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller\r
0a6f4824 2687 // If the user try to boot many OS in different HDs or partitions, in theory,\r
e24fc103 2688 // the HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable maybe become larger and larger.\r
5c08e117 2689 //\r
2690 InstanceNum = 0;\r
2691 ASSERT (CachedDevicePath != NULL);\r
2692 TempNewDevicePath = CachedDevicePath;\r
2693 while (!IsDevicePathEnd (TempNewDevicePath)) {\r
2694 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);\r
2695 //\r
2696 // Parse one instance\r
2697 //\r
2698 while (!IsDevicePathEndType (TempNewDevicePath)) {\r
2699 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);\r
2700 }\r
2701 InstanceNum++;\r
2702 //\r
2703 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.\r
2704 //\r
2705 if (InstanceNum >= 12) {\r
2706 SetDevicePathEndNode (TempNewDevicePath);\r
2707 break;\r
2708 }\r
2709 }\r
2710 } else {\r
2711 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);\r
2712 }\r
2713\r
2714 //\r
2715 // Save the matching Device Path so we don't need to do a connect all next time\r
69fc8f08 2716 // Failure to set the variable only impacts the performance when next time expanding the short-form device path.\r
5c08e117 2717 //\r
2718 Status = gRT->SetVariable (\r
e24fc103
LG
2719 HD_BOOT_DEVICE_PATH_VARIABLE_NAME,\r
2720 &gHdBootDevicePathVariablGuid,\r
f3fc9d8d 2721 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
5c08e117 2722 GetDevicePathSize (CachedDevicePath),\r
2723 CachedDevicePath\r
2724 );\r
2725\r
2726 break;\r
2727 }\r
2728 }\r
128efbbc 2729\r
cd730ec0 2730 if (CachedDevicePath != NULL) {\r
2731 FreePool (CachedDevicePath);\r
2732 }\r
5c08e117 2733 if (BlockIoBuffer != NULL) {\r
2734 FreePool (BlockIoBuffer);\r
2735 }\r
2736 return FullDevicePath;\r
2737}\r
2738\r
2739/**\r
2740 Check whether there is a instance in BlockIoDevicePath, which contain multi device path\r
2741 instances, has the same partition node with HardDriveDevicePath device path\r
2742\r
2743 @param BlockIoDevicePath Multi device path instances which need to check\r
2744 @param HardDriveDevicePath A device path which starts with a hard drive media\r
2745 device path.\r
2746\r
2747 @retval TRUE There is a matched device path instance.\r
2748 @retval FALSE There is no matched device path instance.\r
2749\r
2750**/\r
2751BOOLEAN\r
2752EFIAPI\r
2753MatchPartitionDevicePathNode (\r
2754 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,\r
2755 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath\r
2756 )\r
2757{\r
2758 HARDDRIVE_DEVICE_PATH *TmpHdPath;\r
2759 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2760 BOOLEAN Match;\r
2761 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;\r
2762\r
2763 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {\r
2764 return FALSE;\r
2765 }\r
128efbbc 2766\r
5c08e117 2767 //\r
2768 // Make PreviousDevicePath == the device path node before the end node\r
2769 //\r
2770 DevicePath = BlockIoDevicePath;\r
2771 BlockIoHdDevicePathNode = NULL;\r
2772\r
2773 //\r
2774 // find the partition device path node\r
2775 //\r
2776 while (!IsDevicePathEnd (DevicePath)) {\r
2777 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&\r
2778 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)\r
2779 ) {\r
2780 BlockIoHdDevicePathNode = DevicePath;\r
2781 break;\r
2782 }\r
2783\r
2784 DevicePath = NextDevicePathNode (DevicePath);\r
2785 }\r
2786\r
2787 if (BlockIoHdDevicePathNode == NULL) {\r
2788 return FALSE;\r
2789 }\r
2790 //\r
2791 // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
2792 //\r
2793 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;\r
2794 Match = FALSE;\r
128efbbc 2795\r
5c08e117 2796 //\r
2797 // Check for the match\r
2798 //\r
2799 if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&\r
2800 (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {\r
2801 switch (TmpHdPath->SignatureType) {\r
2802 case SIGNATURE_TYPE_GUID:\r
2803 Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature);\r
2804 break;\r
2805 case SIGNATURE_TYPE_MBR:\r
2806 Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));\r
2807 break;\r
2808 default:\r
2809 Match = FALSE;\r
2810 break;\r
2811 }\r
2812 }\r
2813\r
2814 return Match;\r
2815}\r
2816\r
2817/**\r
2818 Delete the boot option associated with the handle passed in.\r
2819\r
2820 @param Handle The handle which present the device path to create\r
2821 boot option\r
2822\r
2823 @retval EFI_SUCCESS Delete the boot option success\r
2824 @retval EFI_NOT_FOUND If the Device Path is not found in the system\r
2825 @retval EFI_OUT_OF_RESOURCES Lack of memory resource\r
2826 @retval Other Error return value from SetVariable()\r
2827\r
2828**/\r
2829EFI_STATUS\r
2830BdsLibDeleteOptionFromHandle (\r
2831 IN EFI_HANDLE Handle\r
2832 )\r
2833{\r
2834 UINT16 *BootOrder;\r
2835 UINT8 *BootOptionVar;\r
2836 UINTN BootOrderSize;\r
2837 UINTN BootOptionSize;\r
2838 EFI_STATUS Status;\r
2839 UINTN Index;\r
2840 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];\r
2841 UINTN DevicePathSize;\r
2842 UINTN OptionDevicePathSize;\r
2843 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
2844 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
2845 UINT8 *TempPtr;\r
2846\r
2847 Status = EFI_SUCCESS;\r
2848 BootOrder = NULL;\r
2849 BootOrderSize = 0;\r
2850\r
2851 //\r
2852 // Check "BootOrder" variable, if no, means there is no any boot order.\r
2853 //\r
2854 BootOrder = BdsLibGetVariableAndSize (\r
2855 L"BootOrder",\r
2856 &gEfiGlobalVariableGuid,\r
2857 &BootOrderSize\r
2858 );\r
2859 if (BootOrder == NULL) {\r
2860 return EFI_NOT_FOUND;\r
2861 }\r
2862\r
2863 //\r
2864 // Convert device handle to device path protocol instance\r
2865 //\r
2866 DevicePath = DevicePathFromHandle (Handle);\r
2867 if (DevicePath == NULL) {\r
2868 return EFI_NOT_FOUND;\r
2869 }\r
2870 DevicePathSize = GetDevicePathSize (DevicePath);\r
2871\r
2872 //\r
2873 // Loop all boot order variable and find the matching device path\r
2874 //\r
2875 Index = 0;\r
2876 while (Index < BootOrderSize / sizeof (UINT16)) {\r
2877 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
2878 BootOptionVar = BdsLibGetVariableAndSize (\r
2879 BootOption,\r
2880 &gEfiGlobalVariableGuid,\r
2881 &BootOptionSize\r
2882 );\r
128efbbc 2883\r
5c08e117 2884 if (BootOptionVar == NULL) {\r
2885 FreePool (BootOrder);\r
2886 return EFI_OUT_OF_RESOURCES;\r
2887 }\r
2888\r
8c08a567
ED
2889 if (!ValidateOption(BootOptionVar, BootOptionSize)) {\r
2890 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);\r
2891 FreePool (BootOptionVar);\r
2892 Index++;\r
2893 continue;\r
2894 }\r
2895\r
5c08e117 2896 TempPtr = BootOptionVar;\r
2897 TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
2898 TempPtr += StrSize ((CHAR16 *) TempPtr);\r
2899 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
2900 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);\r
2901\r
2902 //\r
2903 // Check whether the device path match\r
2904 //\r
2905 if ((OptionDevicePathSize == DevicePathSize) &&\r
2906 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {\r
2907 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);\r
2908 FreePool (BootOptionVar);\r
2909 break;\r
2910 }\r
2911\r
2912 FreePool (BootOptionVar);\r
2913 Index++;\r
2914 }\r
2915\r
2916 //\r
2917 // Adjust number of boot option for "BootOrder" variable.\r
2918 //\r
2919 Status = gRT->SetVariable (\r
2920 L"BootOrder",\r
2921 &gEfiGlobalVariableGuid,\r
2922 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
2923 BootOrderSize,\r
2924 BootOrder\r
2925 );\r
69fc8f08
RN
2926 //\r
2927 // Shrinking variable with existing variable implementation shouldn't fail.\r
2928 //\r
2929 ASSERT_EFI_ERROR (Status);\r
5c08e117 2930\r
2931 FreePool (BootOrder);\r
2932\r
2933 return Status;\r
2934}\r
2935\r
2936\r
2937/**\r
3384a9bc 2938 Delete all invalid EFI boot options.\r
5c08e117 2939\r
2940 @retval EFI_SUCCESS Delete all invalid boot option success\r
2941 @retval EFI_NOT_FOUND Variable "BootOrder" is not found\r
2942 @retval EFI_OUT_OF_RESOURCES Lack of memory resource\r
2943 @retval Other Error return value from SetVariable()\r
2944\r
2945**/\r
2946EFI_STATUS\r
2947BdsDeleteAllInvalidEfiBootOption (\r
2948 VOID\r
2949 )\r
2950{\r
2951 UINT16 *BootOrder;\r
2952 UINT8 *BootOptionVar;\r
2953 UINTN BootOrderSize;\r
2954 UINTN BootOptionSize;\r
2955 EFI_STATUS Status;\r
2956 UINTN Index;\r
2957 UINTN Index2;\r
2958 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];\r
2959 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
2960 UINT8 *TempPtr;\r
3384a9bc 2961 CHAR16 *Description;\r
8c08a567 2962 BOOLEAN Corrupted;\r
5c08e117 2963\r
8c08a567
ED
2964 Status = EFI_SUCCESS;\r
2965 BootOrder = NULL;\r
2966 Description = NULL;\r
2967 OptionDevicePath = NULL;\r
2968 BootOrderSize = 0;\r
2969 Corrupted = FALSE;\r
5c08e117 2970\r
2971 //\r
2972 // Check "BootOrder" variable firstly, this variable hold the number of boot options\r
2973 //\r
2974 BootOrder = BdsLibGetVariableAndSize (\r
2975 L"BootOrder",\r
2976 &gEfiGlobalVariableGuid,\r
2977 &BootOrderSize\r
2978 );\r
2979 if (NULL == BootOrder) {\r
2980 return EFI_NOT_FOUND;\r
2981 }\r
2982\r
2983 Index = 0;\r
2984 while (Index < BootOrderSize / sizeof (UINT16)) {\r
2985 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
2986 BootOptionVar = BdsLibGetVariableAndSize (\r
2987 BootOption,\r
2988 &gEfiGlobalVariableGuid,\r
2989 &BootOptionSize\r
2990 );\r
2991 if (NULL == BootOptionVar) {\r
2992 FreePool (BootOrder);\r
2993 return EFI_OUT_OF_RESOURCES;\r
2994 }\r
2995\r
8c08a567
ED
2996 if (!ValidateOption(BootOptionVar, BootOptionSize)) {\r
2997 Corrupted = TRUE;\r
2998 } else {\r
2999 TempPtr = BootOptionVar;\r
3000 TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
3001 Description = (CHAR16 *) TempPtr;\r
3002 TempPtr += StrSize ((CHAR16 *) TempPtr);\r
3003 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
5c08e117 3004\r
8c08a567
ED
3005 //\r
3006 // Skip legacy boot option (BBS boot device)\r
3007 //\r
3008 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&\r
3009 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {\r
3010 FreePool (BootOptionVar);\r
3011 Index++;\r
3012 continue;\r
3013 }\r
5c08e117 3014 }\r
3015\r
8c08a567 3016 if (Corrupted || !BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) {\r
5c08e117 3017 //\r
3018 // Delete this invalid boot option "Boot####"\r
3019 //\r
3020 Status = gRT->SetVariable (\r
3021 BootOption,\r
3022 &gEfiGlobalVariableGuid,\r
3023 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
3024 0,\r
3025 NULL\r
3026 );\r
3027 //\r
69fc8f08
RN
3028 // Deleting variable with current variable implementation shouldn't fail.\r
3029 //\r
3030 ASSERT_EFI_ERROR (Status);\r
3031 //\r
5c08e117 3032 // Mark this boot option in boot order as deleted\r
3033 //\r
3034 BootOrder[Index] = 0xffff;\r
8c08a567 3035 Corrupted = FALSE;\r
5c08e117 3036 }\r
3037\r
3038 FreePool (BootOptionVar);\r
3039 Index++;\r
3040 }\r
3041\r
3042 //\r
3043 // Adjust boot order array\r
3044 //\r
3045 Index2 = 0;\r
3046 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
3047 if (BootOrder[Index] != 0xffff) {\r
3048 BootOrder[Index2] = BootOrder[Index];\r
3049 Index2 ++;\r
3050 }\r
3051 }\r
3052 Status = gRT->SetVariable (\r
3053 L"BootOrder",\r
3054 &gEfiGlobalVariableGuid,\r
3055 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
3056 Index2 * sizeof (UINT16),\r
3057 BootOrder\r
3058 );\r
69fc8f08
RN
3059 //\r
3060 // Shrinking variable with current variable implementation shouldn't fail.\r
3061 //\r
3062 ASSERT_EFI_ERROR (Status);\r
5c08e117 3063\r
3064 FreePool (BootOrder);\r
3065\r
3066 return Status;\r
3067}\r
3068\r
3069\r
3070/**\r
3384a9bc 3071 For EFI boot option, BDS separate them as six types:\r
128efbbc 3072 1. Network - The boot option points to the SimpleNetworkProtocol device.\r
3384a9bc 3073 Bds will try to automatically create this type boot option when enumerate.\r
128efbbc 3074 2. Shell - The boot option points to internal flash shell.\r
3384a9bc 3075 Bds will try to automatically create this type boot option when enumerate.\r
3076 3. Removable BlockIo - The boot option only points to the removable media\r
3077 device, like USB flash disk, DVD, Floppy etc.\r
3078 These device should contain a *removable* blockIo\r
3079 protocol in their device handle.\r
128efbbc 3080 Bds will try to automatically create this type boot option\r
3384a9bc 3081 when enumerate.\r
128efbbc 3082 4. Fixed BlockIo - The boot option only points to a Fixed blockIo device,\r
3384a9bc 3083 like HardDisk.\r
3084 These device should contain a *fixed* blockIo\r
3085 protocol in their device handle.\r
3086 BDS will skip fixed blockIo devices, and NOT\r
128efbbc 3087 automatically create boot option for them. But BDS\r
3088 will help to delete those fixed blockIo boot option,\r
3384a9bc 3089 whose description rule conflict with other auto-created\r
3090 boot options.\r
128efbbc 3091 5. Non-BlockIo Simplefile - The boot option points to a device whose handle\r
3384a9bc 3092 has SimpleFileSystem Protocol, but has no blockio\r
3093 protocol. These devices do not offer blockIo\r
128efbbc 3094 protocol, but BDS still can get the\r
3384a9bc 3095 \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem\r
3096 Protocol.\r
128efbbc 3097 6. File - The boot option points to a file. These boot options are usually\r
3384a9bc 3098 created by user manually or OS loader. BDS will not delete or modify\r
128efbbc 3099 these boot options.\r
3100\r
3384a9bc 3101 This function will enumerate all possible boot device in the system, and\r
128efbbc 3102 automatically create boot options for Network, Shell, Removable BlockIo,\r
3384a9bc 3103 and Non-BlockIo Simplefile devices.\r
8d3b5aff 3104 It will only execute once of every boot.\r
128efbbc 3105\r
5c08e117 3106 @param BdsBootOptionList The header of the link list which indexed all\r
3107 current boot options\r
3108\r
3109 @retval EFI_SUCCESS Finished all the boot device enumerate and create\r
3110 the boot option base on that boot device\r
3111\r
e83c9064 3112 @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create the boot option list\r
5c08e117 3113**/\r
3114EFI_STATUS\r
3115EFIAPI\r
3116BdsLibEnumerateAllBootOption (\r
3117 IN OUT LIST_ENTRY *BdsBootOptionList\r
3118 )\r
3119{\r
3120 EFI_STATUS Status;\r
3121 UINT16 FloppyNumber;\r
889a4bc2 3122 UINT16 HarddriveNumber;\r
5c08e117 3123 UINT16 CdromNumber;\r
3124 UINT16 UsbNumber;\r
3125 UINT16 MiscNumber;\r
8d3b5aff 3126 UINT16 ScsiNumber;\r
5c08e117 3127 UINT16 NonBlockNumber;\r
3128 UINTN NumberBlockIoHandles;\r
3129 EFI_HANDLE *BlockIoHandles;\r
3130 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
35bc0e9f
RN
3131 BOOLEAN Removable[2];\r
3132 UINTN RemovableIndex;\r
5c08e117 3133 UINTN Index;\r
a7a523e0 3134 UINTN NumOfLoadFileHandles;\r
3135 EFI_HANDLE *LoadFileHandles;\r
5c08e117 3136 UINTN FvHandleCount;\r
3137 EFI_HANDLE *FvHandleBuffer;\r
3138 EFI_FV_FILETYPE Type;\r
3139 UINTN Size;\r
3140 EFI_FV_FILE_ATTRIBUTES Attributes;\r
3141 UINT32 AuthenticationStatus;\r
8d3b5aff 3142 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
3143 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
5c08e117 3144 UINTN DevicePathType;\r
3145 CHAR16 Buffer[40];\r
3146 EFI_HANDLE *FileSystemHandles;\r
3147 UINTN NumberFileSystemHandles;\r
3148 BOOLEAN NeedDelete;\r
3149 EFI_IMAGE_DOS_HEADER DosHeader;\r
9aa7ba01 3150 CHAR8 *PlatLang;\r
3151 CHAR8 *LastLang;\r
5c08e117 3152 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;\r
3153 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
3154\r
889a4bc2
RN
3155 FloppyNumber = 0;\r
3156 HarddriveNumber = 0;\r
3157 CdromNumber = 0;\r
3158 UsbNumber = 0;\r
3159 MiscNumber = 0;\r
3160 ScsiNumber = 0;\r
3161 PlatLang = NULL;\r
3162 LastLang = NULL;\r
5c08e117 3163 ZeroMem (Buffer, sizeof (Buffer));\r
128efbbc 3164\r
5c08e117 3165 //\r
3166 // If the boot device enumerate happened, just get the boot\r
3167 // device from the boot order variable\r
3168 //\r
3169 if (mEnumBootDevice) {\r
f01b91ae
ED
3170 GetVariable2 (LAST_ENUM_LANGUAGE_VARIABLE_NAME, &gLastEnumLangGuid, (VOID**)&LastLang, NULL);\r
3171 GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatLang, NULL);\r
0fa3ac1b
RN
3172 ASSERT (PlatLang != NULL);\r
3173 if ((LastLang != NULL) && (AsciiStrCmp (LastLang, PlatLang) == 0)) {\r
9aa7ba01 3174 Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
0fa3ac1b
RN
3175 FreePool (LastLang);\r
3176 FreePool (PlatLang);\r
9aa7ba01 3177 return Status;\r
3178 } else {\r
3179 Status = gRT->SetVariable (\r
e24fc103
LG
3180 LAST_ENUM_LANGUAGE_VARIABLE_NAME,\r
3181 &gLastEnumLangGuid,\r
9aa7ba01 3182 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
0fa3ac1b 3183 AsciiStrSize (PlatLang),\r
9aa7ba01 3184 PlatLang\r
3185 );\r
69fc8f08
RN
3186 //\r
3187 // Failure to set the variable only impacts the performance next time enumerating the boot options.\r
3188 //\r
0fa3ac1b
RN
3189\r
3190 if (LastLang != NULL) {\r
3191 FreePool (LastLang);\r
3192 }\r
3193 FreePool (PlatLang);\r
9aa7ba01 3194 }\r
5c08e117 3195 }\r
128efbbc 3196\r
5c08e117 3197 //\r
3198 // Notes: this dirty code is to get the legacy boot option from the\r
3199 // BBS table and create to variable as the EFI boot option, it should\r
3200 // be removed after the CSM can provide legacy boot option directly\r
3201 //\r
3202 REFRESH_LEGACY_BOOT_OPTIONS;\r
3203\r
3204 //\r
3205 // Delete invalid boot option\r
3206 //\r
3207 BdsDeleteAllInvalidEfiBootOption ();\r
128efbbc 3208\r
5c08e117 3209 //\r
701e17e5 3210 // Parse removable media followed by fixed media.\r
0a6f4824 3211 // The Removable[] array is used by the for-loop below to create removable media boot options\r
701e17e5 3212 // at first, and then to create fixed media boot options.\r
5c08e117 3213 //\r
701e17e5
RN
3214 Removable[0] = FALSE;\r
3215 Removable[1] = TRUE;\r
3216\r
5c08e117 3217 gBS->LocateHandleBuffer (\r
3218 ByProtocol,\r
3219 &gEfiBlockIoProtocolGuid,\r
3220 NULL,\r
3221 &NumberBlockIoHandles,\r
3222 &BlockIoHandles\r
3223 );\r
128efbbc 3224\r
35bc0e9f
RN
3225 for (RemovableIndex = 0; RemovableIndex < 2; RemovableIndex++) {\r
3226 for (Index = 0; Index < NumberBlockIoHandles; Index++) {\r
3227 Status = gBS->HandleProtocol (\r
3228 BlockIoHandles[Index],\r
3229 &gEfiBlockIoProtocolGuid,\r
3230 (VOID **) &BlkIo\r
3231 );\r
3232 //\r
7d84fbbb 3233 // skip the logical partition\r
35bc0e9f 3234 //\r
7d84fbbb
RN
3235 if (EFI_ERROR (Status) || BlkIo->Media->LogicalPartition) {\r
3236 continue;\r
3237 }\r
3238\r
3239 //\r
3240 // firstly fixed block io then the removable block io\r
3241 //\r
3242 if (BlkIo->Media->RemovableMedia == Removable[RemovableIndex]) {\r
5c08e117 3243 continue;\r
3244 }\r
35bc0e9f
RN
3245 DevicePath = DevicePathFromHandle (BlockIoHandles[Index]);\r
3246 DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);\r
5c08e117 3247\r
35bc0e9f
RN
3248 switch (DevicePathType) {\r
3249 case BDS_EFI_ACPI_FLOPPY_BOOT:\r
3250 if (FloppyNumber != 0) {\r
3251 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)), FloppyNumber);\r
3252 } else {\r
3253 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)));\r
3254 }\r
3255 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
3256 FloppyNumber++;\r
3257 break;\r
128efbbc 3258\r
35bc0e9f 3259 //\r
889a4bc2 3260 // Assume a removable SATA device should be the DVD/CD device, a fixed SATA device should be the Hard Drive device.\r
35bc0e9f
RN
3261 //\r
3262 case BDS_EFI_MESSAGE_ATAPI_BOOT:\r
3263 case BDS_EFI_MESSAGE_SATA_BOOT:\r
889a4bc2
RN
3264 if (BlkIo->Media->RemovableMedia) {\r
3265 if (CdromNumber != 0) {\r
3266 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)), CdromNumber);\r
3267 } else {\r
3268 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)));\r
3269 }\r
3270 CdromNumber++;\r
35bc0e9f 3271 } else {\r
889a4bc2
RN
3272 if (HarddriveNumber != 0) {\r
3273 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)), HarddriveNumber);\r
3274 } else {\r
3275 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)));\r
3276 }\r
3277 HarddriveNumber++;\r
35bc0e9f
RN
3278 }\r
3279 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Buffer: %S\n", Buffer));\r
3280 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
35bc0e9f
RN
3281 break;\r
3282\r
3283 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:\r
3284 if (UsbNumber != 0) {\r
3285 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)), UsbNumber);\r
3286 } else {\r
3287 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)));\r
3288 }\r
3289 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
3290 UsbNumber++;\r
3291 break;\r
5c08e117 3292\r
35bc0e9f
RN
3293 case BDS_EFI_MESSAGE_SCSI_BOOT:\r
3294 if (ScsiNumber != 0) {\r
3295 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)), ScsiNumber);\r
3296 } else {\r
3297 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)));\r
3298 }\r
3299 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
3300 ScsiNumber++;\r
3301 break;\r
5c08e117 3302\r
35bc0e9f 3303 case BDS_EFI_MESSAGE_MISC_BOOT:\r
277fe9aa 3304 default:\r
35bc0e9f
RN
3305 if (MiscNumber != 0) {\r
3306 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)), MiscNumber);\r
3307 } else {\r
3308 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)));\r
3309 }\r
3310 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);\r
3311 MiscNumber++;\r
3312 break;\r
9aa7ba01 3313 }\r
5c08e117 3314 }\r
3315 }\r
3316\r
3317 if (NumberBlockIoHandles != 0) {\r
3318 FreePool (BlockIoHandles);\r
3319 }\r
3320\r
3321 //\r
3322 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.\r
3323 //\r
3324 NonBlockNumber = 0;\r
3325 gBS->LocateHandleBuffer (\r
3326 ByProtocol,\r
3327 &gEfiSimpleFileSystemProtocolGuid,\r
3328 NULL,\r
3329 &NumberFileSystemHandles,\r
3330 &FileSystemHandles\r
3331 );\r
3332 for (Index = 0; Index < NumberFileSystemHandles; Index++) {\r
3333 Status = gBS->HandleProtocol (\r
3334 FileSystemHandles[Index],\r
3335 &gEfiBlockIoProtocolGuid,\r
3336 (VOID **) &BlkIo\r
3337 );\r
3338 if (!EFI_ERROR (Status)) {\r
3339 //\r
3340 // Skip if the file system handle supports a BlkIo protocol,\r
3341 //\r
3342 continue;\r
3343 }\r
3344\r
3345 //\r
3346 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI\r
3347 // machinename is ia32, ia64, x64, ...\r
3348 //\r
35bc0e9f 3349 Hdr.Union = &HdrData;\r
5c08e117 3350 NeedDelete = TRUE;\r
3351 Status = BdsLibGetImageHeader (\r
3352 FileSystemHandles[Index],\r
c62dbf31 3353 EFI_REMOVABLE_MEDIA_FILE_NAME,\r
5c08e117 3354 &DosHeader,\r
3355 Hdr\r
3356 );\r
3357 if (!EFI_ERROR (Status) &&\r
3358 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&\r
3359 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
3360 NeedDelete = FALSE;\r
3361 }\r
3362\r
3363 if (NeedDelete) {\r
3364 //\r
3365 // No such file or the file is not a EFI application, delete this boot option\r
3366 //\r
3367 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);\r
3368 } else {\r
9aa7ba01 3369 if (NonBlockNumber != 0) {\r
3370 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)), NonBlockNumber);\r
3371 } else {\r
3372 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)));\r
3373 }\r
5c08e117 3374 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);\r
3375 NonBlockNumber++;\r
3376 }\r
3377 }\r
3378\r
3379 if (NumberFileSystemHandles != 0) {\r
3380 FreePool (FileSystemHandles);\r
3381 }\r
3382\r
3383 //\r
3384 // Parse Network Boot Device\r
3385 //\r
a7a523e0 3386 NumOfLoadFileHandles = 0;\r
ff482c56 3387 //\r
a7a523e0 3388 // Search Load File protocol for PXE boot option.\r
ff482c56 3389 //\r
5c08e117 3390 gBS->LocateHandleBuffer (\r
3391 ByProtocol,\r
a7a523e0 3392 &gEfiLoadFileProtocolGuid,\r
5c08e117 3393 NULL,\r
a7a523e0 3394 &NumOfLoadFileHandles,\r
3395 &LoadFileHandles\r
5c08e117 3396 );\r
8d3b5aff 3397\r
a7a523e0 3398 for (Index = 0; Index < NumOfLoadFileHandles; Index++) {\r
9aa7ba01 3399 if (Index != 0) {\r
3400 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)), Index);\r
3401 } else {\r
3402 UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)));\r
3403 }\r
a7a523e0 3404 BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList, Buffer);\r
5c08e117 3405 }\r
3406\r
a7a523e0 3407 if (NumOfLoadFileHandles != 0) {\r
3408 FreePool (LoadFileHandles);\r
5c08e117 3409 }\r
3410\r
3411 //\r
3412 // Check if we have on flash shell\r
3413 //\r
3414 gBS->LocateHandleBuffer (\r
3415 ByProtocol,\r
3416 &gEfiFirmwareVolume2ProtocolGuid,\r
3417 NULL,\r
3418 &FvHandleCount,\r
3419 &FvHandleBuffer\r
3420 );\r
3421 for (Index = 0; Index < FvHandleCount; Index++) {\r
5c08e117 3422 gBS->HandleProtocol (\r
3423 FvHandleBuffer[Index],\r
3424 &gEfiFirmwareVolume2ProtocolGuid,\r
3425 (VOID **) &Fv\r
3426 );\r
3427\r
3428 Status = Fv->ReadFile (\r
3429 Fv,\r
d46f3632 3430 PcdGetPtr(PcdShellFile),\r
5c08e117 3431 NULL,\r
3432 &Size,\r
3433 &Type,\r
3434 &Attributes,\r
3435 &AuthenticationStatus\r
3436 );\r
3437 if (EFI_ERROR (Status)) {\r
3438 //\r
3439 // Skip if no shell file in the FV\r
3440 //\r
3441 continue;\r
3442 }\r
3443 //\r
3444 // Build the shell boot option\r
3445 //\r
3446 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);\r
3447 }\r
3448\r
3449 if (FvHandleCount != 0) {\r
3450 FreePool (FvHandleBuffer);\r
3451 }\r
3452 //\r
3453 // Make sure every boot only have one time\r
3454 // boot device enumerate\r
3455 //\r
e83c9064 3456 Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
5c08e117 3457 mEnumBootDevice = TRUE;\r
3458\r
e83c9064 3459 return Status;\r
5c08e117 3460}\r
3461\r
3462/**\r
3463 Build the boot option with the handle parsed in\r
3464\r
3465 @param Handle The handle which present the device path to create\r
3466 boot option\r
3467 @param BdsBootOptionList The header of the link list which indexed all\r
3468 current boot options\r
3469 @param String The description of the boot option.\r
3470\r
3471**/\r
3472VOID\r
3473EFIAPI\r
3474BdsLibBuildOptionFromHandle (\r
3475 IN EFI_HANDLE Handle,\r
3476 IN LIST_ENTRY *BdsBootOptionList,\r
3477 IN CHAR16 *String\r
3478 )\r
3479{\r
3480 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
128efbbc 3481\r
8d3b5aff 3482 DevicePath = DevicePathFromHandle (Handle);\r
5c08e117 3483\r
3484 //\r
3485 // Create and register new boot option\r
3486 //\r
3487 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");\r
3488}\r
3489\r
3490\r
3491/**\r
3492 Build the on flash shell boot option with the handle parsed in.\r
3493\r
3494 @param Handle The handle which present the device path to create\r
3495 on flash shell boot option\r
3496 @param BdsBootOptionList The header of the link list which indexed all\r
3497 current boot options\r
3498\r
3499**/\r
3500VOID\r
3501EFIAPI\r
3502BdsLibBuildOptionFromShell (\r
3503 IN EFI_HANDLE Handle,\r
3504 IN OUT LIST_ENTRY *BdsBootOptionList\r
3505 )\r
3506{\r
3507 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
3508 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;\r
3509\r
3510 DevicePath = DevicePathFromHandle (Handle);\r
3511\r
3512 //\r
3513 // Build the shell device path\r
3514 //\r
d46f3632 3515 EfiInitializeFwVolDevicepathNode (&ShellNode, PcdGetPtr(PcdShellFile));\r
5c08e117 3516\r
3517 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);\r
3518\r
3519 //\r
3520 // Create and register the shell boot option\r
3521 //\r
3522 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");\r
3523\r
3524}\r
3525\r
3526/**\r
3527 Boot from the UEFI spec defined "BootNext" variable.\r
3528\r
3529**/\r
3530VOID\r
3531EFIAPI\r
3532BdsLibBootNext (\r
3533 VOID\r
3534 )\r
3535{\r
69fc8f08 3536 EFI_STATUS Status;\r
5c08e117 3537 UINT16 *BootNext;\r
3538 UINTN BootNextSize;\r
3539 CHAR16 Buffer[20];\r
3540 BDS_COMMON_OPTION *BootOption;\r
3541 LIST_ENTRY TempList;\r
3542 UINTN ExitDataSize;\r
3543 CHAR16 *ExitData;\r
3544\r
3545 //\r
3546 // Init the boot option name buffer and temp link list\r
3547 //\r
3548 InitializeListHead (&TempList);\r
3549 ZeroMem (Buffer, sizeof (Buffer));\r
3550\r
3551 BootNext = BdsLibGetVariableAndSize (\r
3552 L"BootNext",\r
3553 &gEfiGlobalVariableGuid,\r
3554 &BootNextSize\r
3555 );\r
3556\r
3557 //\r
3558 // Clear the boot next variable first\r
3559 //\r
3560 if (BootNext != NULL) {\r
69fc8f08
RN
3561 Status = gRT->SetVariable (\r
3562 L"BootNext",\r
3563 &gEfiGlobalVariableGuid,\r
3564 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
3565 0,\r
3566 NULL\r
3567 );\r
3568 //\r
3569 // Deleting variable with current variable implementation shouldn't fail.\r
3570 //\r
3571 ASSERT_EFI_ERROR (Status);\r
5c08e117 3572\r
3573 //\r
3574 // Start to build the boot option and try to boot\r
3575 //\r
3576 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);\r
3577 BootOption = BdsLibVariableToOption (&TempList, Buffer);\r
3578 ASSERT (BootOption != NULL);\r
3579 BdsLibConnectDevicePath (BootOption->DevicePath);\r
3580 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
46737a64
CF
3581 FreePool(BootOption);\r
3582 FreePool(BootNext);\r
5c08e117 3583 }\r
3584\r
3585}\r
3586\r
3587/**\r
3588 Return the bootable media handle.\r
3589 First, check the device is connected\r
3590 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,\r
3591 Third, detect the the default boot file in the Media, and return the removable Media handle.\r
3592\r
e83c9064 3593 @param DevicePath Device Path to a bootable device\r
5c08e117 3594\r
e83c9064 3595 @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.\r
5c08e117 3596\r
3597**/\r
3598EFI_HANDLE\r
3599EFIAPI\r
3600BdsLibGetBootableHandle (\r
3601 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
3602 )\r
3603{\r
3604 EFI_STATUS Status;\r
ef949581 3605 EFI_TPL OldTpl;\r
5c08e117 3606 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;\r
3607 EFI_DEVICE_PATH_PROTOCOL *DupDevicePath;\r
3608 EFI_HANDLE Handle;\r
3609 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
3610 VOID *Buffer;\r
3611 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
3612 UINTN Size;\r
3613 UINTN TempSize;\r
3614 EFI_HANDLE ReturnHandle;\r
3615 EFI_HANDLE *SimpleFileSystemHandles;\r
3616\r
3617 UINTN NumberSimpleFileSystemHandles;\r
3618 UINTN Index;\r
3619 EFI_IMAGE_DOS_HEADER DosHeader;\r
3620 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;\r
3621 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
3622\r
3623 UpdatedDevicePath = DevicePath;\r
128efbbc 3624\r
ef949581 3625 //\r
0a6f4824 3626 // Enter to critical section to protect the acquired BlockIo instance\r
ef949581
RN
3627 // from getting released due to the USB mass storage hotplug event\r
3628 //\r
3629 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
3630\r
5c08e117 3631 //\r
3632 // Check whether the device is connected\r
3633 //\r
3634 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);\r
3635 if (EFI_ERROR (Status)) {\r
3636 //\r
3637 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,\r
3638 //\r
3639 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);\r
3640 if (EFI_ERROR (Status)) {\r
3641 //\r
3642 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly\r
3643 //\r
3644 UpdatedDevicePath = DevicePath;\r
3645 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);\r
3646 gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
3647 }\r
3648 } else {\r
e74f510b 3649 //\r
0a6f4824
LG
3650 // For removable device boot option, its contained device path only point to the removable device handle,\r
3651 // should make sure all its children handles (its child partion or media handles) are created and connected.\r
e74f510b 3652 //\r
0a6f4824 3653 gBS->ConnectController (Handle, NULL, NULL, TRUE);\r
5c08e117 3654 //\r
3655 // Get BlockIo protocol and check removable attribute\r
3656 //\r
3657 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);\r
ef949581
RN
3658 ASSERT_EFI_ERROR (Status);\r
3659\r
5c08e117 3660 //\r
3661 // Issue a dummy read to the device to check for media change.\r
3662 // When the removable media is changed, any Block IO read/write will\r
3663 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is\r
3664 // returned. After the Block IO protocol is reinstalled, subsequent\r
3665 // Block IO read/write will success.\r
3666 //\r
3667 Buffer = AllocatePool (BlockIo->Media->BlockSize);\r
3668 if (Buffer != NULL) {\r
3669 BlockIo->ReadBlocks (\r
3670 BlockIo,\r
3671 BlockIo->Media->MediaId,\r
3672 0,\r
3673 BlockIo->Media->BlockSize,\r
3674 Buffer\r
3675 );\r
3676 FreePool(Buffer);\r
3677 }\r
3678 }\r
3679\r
3680 //\r
3681 // Detect the the default boot file from removable Media\r
3682 //\r
3683\r
3684 //\r
3685 // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus\r
3686 // Try to locate the USB node device path first, if fail then use its previous PCI node to search\r
3687 //\r
3688 DupDevicePath = DuplicateDevicePath (DevicePath);\r
3689 ASSERT (DupDevicePath != NULL);\r
128efbbc 3690\r
5c08e117 3691 UpdatedDevicePath = DupDevicePath;\r
3692 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);\r
3693 //\r
3694 // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node\r
3695 // Acpi()/Pci()/Usb() --> Acpi()/Pci()\r
3696 //\r
3697 if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&\r
3698 (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {\r
3699 //\r
3700 // Remove the usb node, let the device path only point to PCI node\r
3701 //\r
3702 SetDevicePathEndNode (UpdatedDevicePath);\r
3703 UpdatedDevicePath = DupDevicePath;\r
3704 } else {\r
3705 UpdatedDevicePath = DevicePath;\r
3706 }\r
3707\r
3708 //\r
3709 // Get the device path size of boot option\r
3710 //\r
3711 Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node\r
3712 ReturnHandle = NULL;\r
3713 gBS->LocateHandleBuffer (\r
3714 ByProtocol,\r
3715 &gEfiSimpleFileSystemProtocolGuid,\r
3716 NULL,\r
3717 &NumberSimpleFileSystemHandles,\r
3718 &SimpleFileSystemHandles\r
3719 );\r
3720 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {\r
3721 //\r
3722 // Get the device path size of SimpleFileSystem handle\r
3723 //\r
3724 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);\r
3725 TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node\r
3726 //\r
3727 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path\r
3728 //\r
3729 if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {\r
3730 //\r
3731 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media\r
3732 // machinename is ia32, ia64, x64, ...\r
3733 //\r
3734 Hdr.Union = &HdrData;\r
3735 Status = BdsLibGetImageHeader (\r
3736 SimpleFileSystemHandles[Index],\r
c62dbf31 3737 EFI_REMOVABLE_MEDIA_FILE_NAME,\r
5c08e117 3738 &DosHeader,\r
3739 Hdr\r
3740 );\r
3741 if (!EFI_ERROR (Status) &&\r
3742 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&\r
3743 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {\r
3744 ReturnHandle = SimpleFileSystemHandles[Index];\r
3745 break;\r
3746 }\r
3747 }\r
3748 }\r
3749\r
3750 FreePool(DupDevicePath);\r
3751\r
3752 if (SimpleFileSystemHandles != NULL) {\r
3753 FreePool(SimpleFileSystemHandles);\r
3754 }\r
3755\r
ef949581
RN
3756 gBS->RestoreTPL (OldTpl);\r
3757\r
5c08e117 3758 return ReturnHandle;\r
3759}\r
3760\r
3761/**\r
3762 Check to see if the network cable is plugged in. If the DevicePath is not\r
3763 connected it will be connected.\r
3764\r
3765 @param DevicePath Device Path to check\r
3766\r
3767 @retval TRUE DevicePath points to an Network that is connected\r
3768 @retval FALSE DevicePath does not point to a bootable network\r
3769\r
3770**/\r
3771BOOLEAN\r
3772BdsLibNetworkBootWithMediaPresent (\r
3773 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
3774 )\r
3775{\r
3776 EFI_STATUS Status;\r
3777 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;\r
3778 EFI_HANDLE Handle;\r
3779 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
3780 BOOLEAN MediaPresent;\r
e51e619e 3781 UINT32 InterruptStatus;\r
5c08e117 3782\r
3783 MediaPresent = FALSE;\r
3784\r
3785 UpdatedDevicePath = DevicePath;\r
ff482c56 3786 //\r
a7a523e0 3787 // Locate Load File Protocol for PXE boot option first\r
ff482c56 3788 //\r
a7a523e0 3789 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);\r
5c08e117 3790 if (EFI_ERROR (Status)) {\r
3791 //\r
3792 // Device not present so see if we need to connect it\r
3793 //\r
3794 Status = BdsLibConnectDevicePath (DevicePath);\r
3795 if (!EFI_ERROR (Status)) {\r
3796 //\r
3797 // This one should work after we did the connect\r
3798 //\r
a7a523e0 3799 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);\r
5c08e117 3800 }\r
3801 }\r
3802\r
3803 if (!EFI_ERROR (Status)) {\r
3804 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);\r
ff482c56 3805 if (EFI_ERROR (Status)) {\r
3806 //\r
3807 // Failed to open SNP from this handle, try to get SNP from parent handle\r
3808 //\r
3809 UpdatedDevicePath = DevicePathFromHandle (Handle);\r
3810 if (UpdatedDevicePath != NULL) {\r
3811 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);\r
3812 if (!EFI_ERROR (Status)) {\r
3813 //\r
3814 // SNP handle found, get SNP from it\r
3815 //\r
3816 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &Snp);\r
3817 }\r
3818 }\r
3819 }\r
3820\r
5c08e117 3821 if (!EFI_ERROR (Status)) {\r
3822 if (Snp->Mode->MediaPresentSupported) {\r
3823 if (Snp->Mode->State == EfiSimpleNetworkInitialized) {\r
e51e619e 3824 //\r
3825 // Invoke Snp->GetStatus() to refresh the media status\r
3826 //\r
3827 Snp->GetStatus (Snp, &InterruptStatus, NULL);\r
3828\r
5c08e117 3829 //\r
3830 // In case some one else is using the SNP check to see if it's connected\r
3831 //\r
3832 MediaPresent = Snp->Mode->MediaPresent;\r
3833 } else {\r
3834 //\r
3835 // No one is using SNP so we need to Start and Initialize so\r
3836 // MediaPresent will be valid.\r
3837 //\r
3838 Status = Snp->Start (Snp);\r
3839 if (!EFI_ERROR (Status)) {\r
3840 Status = Snp->Initialize (Snp, 0, 0);\r
3841 if (!EFI_ERROR (Status)) {\r
3842 MediaPresent = Snp->Mode->MediaPresent;\r
3843 Snp->Shutdown (Snp);\r
3844 }\r
3845 Snp->Stop (Snp);\r
3846 }\r
3847 }\r
3848 } else {\r
3849 MediaPresent = TRUE;\r
3850 }\r
3851 }\r
3852 }\r
3853\r
3854 return MediaPresent;\r
3855}\r
3856\r
3857/**\r
3858 For a bootable Device path, return its boot type.\r
3859\r
3860 @param DevicePath The bootable device Path to check\r
3861\r
128efbbc 3862 @retval BDS_EFI_MEDIA_HD_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node\r
11c5022d 3863 which subtype is MEDIA_HARDDRIVE_DP\r
3864 @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node\r
3865 which subtype is MEDIA_CDROM_DP\r
3866 @retval BDS_EFI_ACPI_FLOPPY_BOOT If given device path contains ACPI_DEVICE_PATH type device path node\r
3867 which HID is floppy device.\r
3868 @retval BDS_EFI_MESSAGE_ATAPI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node\r
3869 and its last device path node's subtype is MSG_ATAPI_DP.\r
3870 @retval BDS_EFI_MESSAGE_SCSI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node\r
3871 and its last device path node's subtype is MSG_SCSI_DP.\r
3872 @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node\r
3873 and its last device path node's subtype is MSG_USB_DP.\r
5c08e117 3874 @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media device path node, and\r
11c5022d 3875 its last device path node point to a message device path node.\r
3876 @retval BDS_LEGACY_BBS_BOOT If given device path contains BBS_DEVICE_PATH type device path node.\r
128efbbc 3877 @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message device,\r
5c08e117 3878\r
3879**/\r
3880UINT32\r
3881EFIAPI\r
3882BdsGetBootTypeFromDevicePath (\r
3883 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
3884 )\r
3885{\r
3886 ACPI_HID_DEVICE_PATH *Acpi;\r
3887 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
3888 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;\r
ff482c56 3889 UINT32 BootType;\r
5c08e117 3890\r
3891 if (NULL == DevicePath) {\r
3892 return BDS_EFI_UNSUPPORT;\r
3893 }\r
3894\r
3895 TempDevicePath = DevicePath;\r
3896\r
3897 while (!IsDevicePathEndType (TempDevicePath)) {\r
3898 switch (DevicePathType (TempDevicePath)) {\r
3899 case BBS_DEVICE_PATH:\r
3900 return BDS_LEGACY_BBS_BOOT;\r
3901 case MEDIA_DEVICE_PATH:\r
3902 if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {\r
3903 return BDS_EFI_MEDIA_HD_BOOT;\r
3904 } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {\r
3905 return BDS_EFI_MEDIA_CDROM_BOOT;\r
128efbbc 3906 }\r
5c08e117 3907 break;\r
3908 case ACPI_DEVICE_PATH:\r
3909 Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;\r
3910 if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {\r
3911 return BDS_EFI_ACPI_FLOPPY_BOOT;\r
3912 }\r
3913 break;\r
3914 case MESSAGING_DEVICE_PATH:\r
3915 //\r
3916 // Get the last device path node\r
3917 //\r
3918 LastDeviceNode = NextDevicePathNode (TempDevicePath);\r
3919 if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {\r
3920 //\r
3921 // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),\r
ff482c56 3922 // skip it\r
5c08e117 3923 //\r
3924 LastDeviceNode = NextDevicePathNode (LastDeviceNode);\r
3925 }\r
3926 //\r
3927 // if the device path not only point to driver device, it is not a messaging device path,\r
3928 //\r
3929 if (!IsDevicePathEndType (LastDeviceNode)) {\r
128efbbc 3930 break;\r
5c08e117 3931 }\r
3932\r
ff482c56 3933 switch (DevicePathSubType (TempDevicePath)) {\r
3934 case MSG_ATAPI_DP:\r
3935 BootType = BDS_EFI_MESSAGE_ATAPI_BOOT;\r
3936 break;\r
3937\r
3938 case MSG_USB_DP:\r
3939 BootType = BDS_EFI_MESSAGE_USB_DEVICE_BOOT;\r
3940 break;\r
3941\r
3942 case MSG_SCSI_DP:\r
3943 BootType = BDS_EFI_MESSAGE_SCSI_BOOT;\r
3944 break;\r
3945\r
3946 case MSG_SATA_DP:\r
3947 BootType = BDS_EFI_MESSAGE_SATA_BOOT;\r
3948 break;\r
3949\r
3950 case MSG_MAC_ADDR_DP:\r
3951 case MSG_VLAN_DP:\r
a7a523e0 3952 case MSG_IPv4_DP:\r
3953 case MSG_IPv6_DP:\r
ff482c56 3954 BootType = BDS_EFI_MESSAGE_MAC_BOOT;\r
3955 break;\r
3956\r
3957 default:\r
3958 BootType = BDS_EFI_MESSAGE_MISC_BOOT;\r
3959 break;\r
5c08e117 3960 }\r
ff482c56 3961 return BootType;\r
3962\r
5c08e117 3963 default:\r
3964 break;\r
3965 }\r
3966 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
3967 }\r
3968\r
3969 return BDS_EFI_UNSUPPORT;\r
3970}\r
3971\r
3972/**\r
3973 Check whether the Device path in a boot option point to a valid bootable device,\r
3974 And if CheckMedia is true, check the device is ready to boot now.\r
3975\r
3976 @param DevPath the Device path in a boot option\r
3977 @param CheckMedia if true, check the device is ready to boot now.\r
3978\r
3979 @retval TRUE the Device path is valid\r
3980 @retval FALSE the Device path is invalid .\r
3981\r
3982**/\r
3983BOOLEAN\r
3984EFIAPI\r
3985BdsLibIsValidEFIBootOptDevicePath (\r
3986 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,\r
3987 IN BOOLEAN CheckMedia\r
3988 )\r
3384a9bc 3989{\r
3990 return BdsLibIsValidEFIBootOptDevicePathExt (DevPath, CheckMedia, NULL);\r
3991}\r
3992\r
3993/**\r
3994 Check whether the Device path in a boot option point to a valid bootable device,\r
3995 And if CheckMedia is true, check the device is ready to boot now.\r
3996 If Description is not NULL and the device path point to a fixed BlockIo\r
3997 device, check the description whether conflict with other auto-created\r
3998 boot options.\r
3999\r
4000 @param DevPath the Device path in a boot option\r
4001 @param CheckMedia if true, check the device is ready to boot now.\r
4002 @param Description the description in a boot option\r
4003\r
4004 @retval TRUE the Device path is valid\r
4005 @retval FALSE the Device path is invalid .\r
4006\r
4007**/\r
4008BOOLEAN\r
4009EFIAPI\r
4010BdsLibIsValidEFIBootOptDevicePathExt (\r
4011 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,\r
4012 IN BOOLEAN CheckMedia,\r
4013 IN CHAR16 *Description\r
4014 )\r
5c08e117 4015{\r
4016 EFI_STATUS Status;\r
4017 EFI_HANDLE Handle;\r
4018 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
4019 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;\r
4020 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
4021\r
4022 TempDevicePath = DevPath;\r
4023 LastDeviceNode = DevPath;\r
128efbbc 4024\r
5c08e117 4025 //\r
a7a523e0 4026 // Check if it's a valid boot option for network boot device.\r
0a6f4824 4027 // Check if there is EfiLoadFileProtocol installed.\r
a7a523e0 4028 // If yes, that means there is a boot option for network.\r
5c08e117 4029 //\r
4030 Status = gBS->LocateDevicePath (\r
a7a523e0 4031 &gEfiLoadFileProtocolGuid,\r
5c08e117 4032 &TempDevicePath,\r
4033 &Handle\r
4034 );\r
4035 if (EFI_ERROR (Status)) {\r
4036 //\r
4037 // Device not present so see if we need to connect it\r
4038 //\r
4039 TempDevicePath = DevPath;\r
4040 BdsLibConnectDevicePath (TempDevicePath);\r
4041 Status = gBS->LocateDevicePath (\r
a7a523e0 4042 &gEfiLoadFileProtocolGuid,\r
5c08e117 4043 &TempDevicePath,\r
4044 &Handle\r
4045 );\r
4046 }\r
128efbbc 4047\r
5c08e117 4048 if (!EFI_ERROR (Status)) {\r
a7a523e0 4049 if (!IsDevicePathEnd (TempDevicePath)) {\r
4050 //\r
4051 // LoadFile protocol is not installed on handle with exactly the same DevPath\r
4052 //\r
4053 return FALSE;\r
4054 }\r
ff482c56 4055\r
a7a523e0 4056 if (CheckMedia) {\r
4057 //\r
4058 // Test if it is ready to boot now\r
4059 //\r
4060 if (BdsLibNetworkBootWithMediaPresent(DevPath)) {\r
5c08e117 4061 return TRUE;\r
4062 }\r
a7a523e0 4063 } else {\r
4064 return TRUE;\r
0a6f4824 4065 }\r
5c08e117 4066 }\r
4067\r
4068 //\r
4069 // If the boot option point to a file, it is a valid EFI boot option,\r
4070 // and assume it is ready to boot now\r
4071 //\r
4072 while (!IsDevicePathEnd (TempDevicePath)) {\r
7389fdd0 4073 //\r
4074 // If there is USB Class or USB WWID device path node, treat it as valid EFI\r
4075 // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it\r
4076 // to full device path.\r
4077 //\r
4078 if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&\r
4079 ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||\r
4080 (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {\r
4081 return TRUE;\r
4082 }\r
4083\r
4084 LastDeviceNode = TempDevicePath;\r
4085 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
5c08e117 4086 }\r
4087 if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&\r
4088 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {\r
4089 return TRUE;\r
4090 }\r
4091\r
4092 //\r
6617d838 4093 // Check if it's a valid boot option for internal FV application\r
5c08e117 4094 //\r
4095 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {\r
4096 //\r
6617d838 4097 // If the boot option point to internal FV application, make sure it is valid\r
5c08e117 4098 //\r
128efbbc 4099 TempDevicePath = DevPath;\r
6617d838
RN
4100 Status = BdsLibUpdateFvFileDevicePath (\r
4101 &TempDevicePath,\r
4102 EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode)\r
4103 );\r
5c08e117 4104 if (Status == EFI_ALREADY_STARTED) {\r
4105 return TRUE;\r
4106 } else {\r
4107 if (Status == EFI_SUCCESS) {\r
128efbbc 4108 FreePool (TempDevicePath);\r
5c08e117 4109 }\r
4110 return FALSE;\r
4111 }\r
4112 }\r
128efbbc 4113\r
5c08e117 4114 //\r
3384a9bc 4115 // If the boot option point to a blockIO device:\r
8d3b5aff 4116 // if it is a removable blockIo device, it is valid.\r
128efbbc 4117 // if it is a fixed blockIo device, check its description confliction.\r
5c08e117 4118 //\r
4119 TempDevicePath = DevPath;\r
4120 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
4121 if (EFI_ERROR (Status)) {\r
4122 //\r
4123 // Device not present so see if we need to connect it\r
4124 //\r
4125 Status = BdsLibConnectDevicePath (DevPath);\r
4126 if (!EFI_ERROR (Status)) {\r
4127 //\r
4128 // Try again to get the Block Io protocol after we did the connect\r
4129 //\r
4130 TempDevicePath = DevPath;\r
4131 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);\r
4132 }\r
4133 }\r
128efbbc 4134\r
5c08e117 4135 if (!EFI_ERROR (Status)) {\r
4136 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);\r
4137 if (!EFI_ERROR (Status)) {\r
4138 if (CheckMedia) {\r
4139 //\r
4140 // Test if it is ready to boot now\r
4141 //\r
4142 if (BdsLibGetBootableHandle (DevPath) != NULL) {\r
4143 return TRUE;\r
4144 }\r
4145 } else {\r
4146 return TRUE;\r
4147 }\r
4148 }\r
4149 } else {\r
4150 //\r
4151 // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,\r
4152 //\r
4153 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);\r
4154 if (!EFI_ERROR (Status)) {\r
4155 if (CheckMedia) {\r
4156 //\r
4157 // Test if it is ready to boot now\r
4158 //\r
4159 if (BdsLibGetBootableHandle (DevPath) != NULL) {\r
4160 return TRUE;\r
4161 }\r
4162 } else {\r
4163 return TRUE;\r
4164 }\r
4165 }\r
4166 }\r
4167\r
4168 return FALSE;\r
4169}\r
4170\r
4171\r
4172/**\r
4173 According to a file guild, check a Fv file device path is valid. If it is invalid,\r
4174 try to return the valid device path.\r
4175 FV address maybe changes for memory layout adjust from time to time, use this function\r
4176 could promise the Fv file device path is right.\r
4177\r
4178 @param DevicePath on input, the Fv file device path need to check on\r
4179 output, the updated valid Fv file device path\r
4180 @param FileGuid the Fv file guild\r
4181\r
4182 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid\r
4183 parameter\r
4184 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file\r
4185 guild at all\r
4186 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is\r
4187 valid\r
4188 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,\r
4189 and return the updated device path in DevicePath\r
4190\r
4191**/\r
4192EFI_STATUS\r
4193EFIAPI\r
4194BdsLibUpdateFvFileDevicePath (\r
4195 IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,\r
4196 IN EFI_GUID *FileGuid\r
4197 )\r
4198{\r
4199 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
4200 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;\r
4201 EFI_STATUS Status;\r
4202 EFI_GUID *GuidPoint;\r
4203 UINTN Index;\r
4204 UINTN FvHandleCount;\r
4205 EFI_HANDLE *FvHandleBuffer;\r
4206 EFI_FV_FILETYPE Type;\r
4207 UINTN Size;\r
4208 EFI_FV_FILE_ATTRIBUTES Attributes;\r
4209 UINT32 AuthenticationStatus;\r
4210 BOOLEAN FindFvFile;\r
4211 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
4212 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
4213 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;\r
4214 EFI_HANDLE FoundFvHandle;\r
4215 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
4216\r
4217 if ((DevicePath == NULL) || (*DevicePath == NULL)) {\r
4218 return EFI_INVALID_PARAMETER;\r
4219 }\r
4220 if (FileGuid == NULL) {\r
4221 return EFI_INVALID_PARAMETER;\r
4222 }\r
128efbbc 4223\r
5c08e117 4224 //\r
4225 // Check whether the device path point to the default the input Fv file\r
4226 //\r
4227 TempDevicePath = *DevicePath;\r
4228 LastDeviceNode = TempDevicePath;\r
4229 while (!IsDevicePathEnd (TempDevicePath)) {\r
4230 LastDeviceNode = TempDevicePath;\r
4231 TempDevicePath = NextDevicePathNode (TempDevicePath);\r
4232 }\r
4233 GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (\r
4234 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode\r
4235 );\r
4236 if (GuidPoint == NULL) {\r
4237 //\r
4238 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED\r
4239 //\r
4240 return EFI_UNSUPPORTED;\r
4241 }\r
4242 if (!CompareGuid (GuidPoint, FileGuid)) {\r
4243 //\r
4244 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED\r
4245 //\r
4246 return EFI_UNSUPPORTED;\r
4247 }\r
4248\r
4249 //\r
4250 // Check whether the input Fv file device path is valid\r
4251 //\r
4252 TempDevicePath = *DevicePath;\r
4253 FoundFvHandle = NULL;\r
4254 Status = gBS->LocateDevicePath (\r
4255 &gEfiFirmwareVolume2ProtocolGuid,\r
4256 &TempDevicePath,\r
4257 &FoundFvHandle\r
4258 );\r
4259 if (!EFI_ERROR (Status)) {\r
4260 Status = gBS->HandleProtocol (\r
4261 FoundFvHandle,\r
4262 &gEfiFirmwareVolume2ProtocolGuid,\r
4263 (VOID **) &Fv\r
4264 );\r
4265 if (!EFI_ERROR (Status)) {\r
4266 //\r
4267 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there\r
4268 //\r
4269 Status = Fv->ReadFile (\r
4270 Fv,\r
4271 FileGuid,\r
4272 NULL,\r
4273 &Size,\r
4274 &Type,\r
4275 &Attributes,\r
4276 &AuthenticationStatus\r
4277 );\r
4278 if (!EFI_ERROR (Status)) {\r
4279 return EFI_ALREADY_STARTED;\r
4280 }\r
4281 }\r
4282 }\r
4283\r
4284 //\r
4285 // Look for the input wanted FV file in current FV\r
4286 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV\r
4287 //\r
4288 FindFvFile = FALSE;\r
4289 FoundFvHandle = NULL;\r
4290 Status = gBS->HandleProtocol (\r
fefefa4c 4291 gImageHandle,\r
5c08e117 4292 &gEfiLoadedImageProtocolGuid,\r
4293 (VOID **) &LoadedImage\r
4294 );\r
4295 if (!EFI_ERROR (Status)) {\r
4296 Status = gBS->HandleProtocol (\r
4297 LoadedImage->DeviceHandle,\r
4298 &gEfiFirmwareVolume2ProtocolGuid,\r
4299 (VOID **) &Fv\r
4300 );\r
4301 if (!EFI_ERROR (Status)) {\r
4302 Status = Fv->ReadFile (\r
4303 Fv,\r
4304 FileGuid,\r
4305 NULL,\r
4306 &Size,\r
4307 &Type,\r
4308 &Attributes,\r
4309 &AuthenticationStatus\r
4310 );\r
4311 if (!EFI_ERROR (Status)) {\r
4312 FindFvFile = TRUE;\r
4313 FoundFvHandle = LoadedImage->DeviceHandle;\r
4314 }\r
4315 }\r
4316 }\r
4317 //\r
4318 // Second, if fail to find, try to enumerate all FV\r
4319 //\r
4320 if (!FindFvFile) {\r
4321 FvHandleBuffer = NULL;\r
4322 gBS->LocateHandleBuffer (\r
4323 ByProtocol,\r
4324 &gEfiFirmwareVolume2ProtocolGuid,\r
4325 NULL,\r
4326 &FvHandleCount,\r
4327 &FvHandleBuffer\r
4328 );\r
4329 for (Index = 0; Index < FvHandleCount; Index++) {\r
4330 gBS->HandleProtocol (\r
4331 FvHandleBuffer[Index],\r
4332 &gEfiFirmwareVolume2ProtocolGuid,\r
4333 (VOID **) &Fv\r
4334 );\r
4335\r
4336 Status = Fv->ReadFile (\r
4337 Fv,\r
4338 FileGuid,\r
4339 NULL,\r
4340 &Size,\r
4341 &Type,\r
4342 &Attributes,\r
4343 &AuthenticationStatus\r
4344 );\r
4345 if (EFI_ERROR (Status)) {\r
4346 //\r
4347 // Skip if input Fv file not in the FV\r
4348 //\r
4349 continue;\r
4350 }\r
4351 FindFvFile = TRUE;\r
4352 FoundFvHandle = FvHandleBuffer[Index];\r
4353 break;\r
4354 }\r
4355\r
4356 if (FvHandleBuffer != NULL) {\r
128efbbc 4357 FreePool (FvHandleBuffer);\r
5c08e117 4358 }\r
4359 }\r
4360\r
4361 if (FindFvFile) {\r
4362 //\r
4363 // Build the shell device path\r
4364 //\r
4365 NewDevicePath = DevicePathFromHandle (FoundFvHandle);\r
4366 EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);\r
4367 NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);\r
45295cf5 4368 ASSERT (NewDevicePath != NULL);\r
5c08e117 4369 *DevicePath = NewDevicePath;\r
4370 return EFI_SUCCESS;\r
4371 }\r
4372 return EFI_NOT_FOUND;\r
4373}\r