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