]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Library/EdkGenericBdsLib/BdsBoot.c
1. Sync definition of EFI_DEBUG_IMAGE_INFO with UEFI spec
[mirror_edk2.git] / EdkModulePkg / Library / EdkGenericBdsLib / BdsBoot.c
CommitLineData
8033e931 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 BdsBoot.c\r
15\r
16Abstract:\r
17\r
18 BDS Lib functions which relate with create or process the boot\r
19 option.\r
20\r
21--*/\r
22#include "Performance.h"\r
23\r
24BOOLEAN mEnumBootDevice = FALSE;\r
25\r
26EFI_STATUS\r
27BdsLibDoLegacyBoot (\r
28 IN BDS_COMMON_OPTION *Option\r
29 )\r
30/*++\r
31\r
32Routine Description:\r
33 \r
34 Boot the legacy system with the boot option\r
35\r
36Arguments:\r
37\r
38 Option - The legacy boot option which have BBS device path\r
39\r
40Returns:\r
41\r
42 EFI_UNSUPPORTED - There is no legacybios protocol, do not support\r
43 legacy boot.\r
44 \r
45 EFI_STATUS - Return the status of LegacyBios->LegacyBoot ().\r
46\r
47--*/\r
48{\r
49 EFI_STATUS Status;\r
50 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
51\r
52 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL,
53 (void **)&LegacyBios);\r
54 if (EFI_ERROR (Status)) {\r
55 //\r
56 // If no LegacyBios protocol we do not support legacy boot\r
57 //\r
58 return EFI_UNSUPPORTED;\r
59 }\r
60 //\r
61 // Notes: if we seperate the int 19, then we don't need to refresh BBS\r
62 //\r
63 BdsRefreshBbsTableForBoot (Option);\r
64\r
65 //\r
66 // Write boot to OS performance data to a file\r
67 //\r
68 PERF_CODE (\r
69 WriteBootToOsPerformanceData ();\r
70 );\r
71\r
72\r
73 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Legacy Boot: %S\n", Option->Description));\r
74 return LegacyBios->LegacyBoot (\r
75 LegacyBios,\r
76 (BBS_BBS_DEVICE_PATH *) Option->DevicePath,\r
77 Option->LoadOptionsSize,\r
78 Option->LoadOptions\r
79 );\r
80}\r
81\r
82EFI_STATUS\r
83BdsLibBootViaBootOption (\r
84 IN BDS_COMMON_OPTION * Option,\r
85 IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,\r
86 OUT UINTN *ExitDataSize,\r
87 OUT CHAR16 **ExitData OPTIONAL\r
88 )\r
89/*++\r
90\r
91Routine Description:\r
92\r
93 Process the boot option follow the EFI 1.1 specification and \r
94 special treat the legacy boot option with BBS_DEVICE_PATH.\r
95\r
96Arguments:\r
97\r
98 Option - The boot option need to be processed\r
99 \r
100 DevicePath - The device path which describe where to load \r
101 the boot image or the legcy BBS device path \r
102 to boot the legacy OS\r
103\r
104 ExitDataSize - Returned directly from gBS->StartImage ()\r
105\r
106 ExitData - Returned directly from gBS->StartImage ()\r
107\r
108Returns:\r
109\r
110 EFI_SUCCESS - Status from gBS->StartImage (),\r
111 or BdsBootByDiskSignatureAndPartition ()\r
112\r
113 EFI_NOT_FOUND - If the Device Path is not found in the system\r
114\r
115--*/\r
116{\r
117 EFI_STATUS Status;\r
118 EFI_HANDLE Handle;\r
119 EFI_HANDLE ImageHandle;\r
120 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
121 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
122 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
123 EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;\r
124 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
125 VOID *Buffer;\r
126\r
df557cca 127 //\r
128 // Record the performance data for End of BDS\r
129 //\r
130 PERF_END (0, BDS_TOK, NULL, 0);\r
131\r
8033e931 132 *ExitDataSize = 0;\r
133 *ExitData = NULL;\r
134\r
135 //\r
136 // Notes: put EFI64 ROM Shadow Solution\r
137 //\r
138 EFI64_SHADOW_ALL_LEGACY_ROM ();\r
139\r
140 //\r
141 // Notes: this code can be remove after the s3 script table\r
142 // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or\r
143 // EFI_EVENT_SIGNAL_LEGACY_BOOT\r
144 //\r
145 Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL,
146 (VOID **)&AcpiS3Save);\r
147 if (!EFI_ERROR (Status)) {\r
148 AcpiS3Save->S3Save (AcpiS3Save, NULL);\r
149 }\r
150 //\r
151 // If it's Device Path that starts with a hard drive path,\r
152 // this routine will do the booting.\r
153 //\r
154 Status = BdsBootByDiskSignatureAndPartition (\r
155 Option,\r
156 (HARDDRIVE_DEVICE_PATH *) DevicePath,\r
157 Option->LoadOptionsSize,\r
158 Option->LoadOptions,\r
159 ExitDataSize,\r
160 ExitData\r
161 );\r
162 if (!EFI_ERROR (Status)) {\r
163 //\r
164 // If we found a disk signature and partition device path return success\r
165 //\r
166 return EFI_SUCCESS;\r
167 }\r
168\r
169 EfiSignalEventReadyToBoot ();\r
170\r
171 //\r
172 // Set Boot Current\r
173 //\r
174 gRT->SetVariable (\r
175 L"BootCurrent",\r
176 &gEfiGlobalVariableGuid,\r
177 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
178 sizeof (UINT16),\r
179 &Option->BootCurrent\r
180 );\r
181\r
182 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&\r
183 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)\r
184 ) {\r
185 //\r
186 // Check to see if we should legacy BOOT. If yes then do the legacy boot\r
187 //\r
188 return BdsLibDoLegacyBoot (Option);\r
189 }\r
190\r
191 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI 1.1 way %S\n", Option->Description));\r
192\r
193 Status = gBS->LoadImage (\r
194 TRUE,\r
195 mBdsImageHandle,\r
196 DevicePath,\r
197 NULL,\r
198 0,\r
199 &ImageHandle\r
200 );\r
201\r
202 //\r
203 // If we didn't find an image, we may need to load the default\r
204 // boot behavior for the device.\r
205 //\r
206 if (EFI_ERROR (Status)) {\r
207 //\r
208 // Find a Simple File System protocol on the device path. If the remaining\r
209 // device path is set to end then no Files are being specified, so try\r
210 // the removable media file name.\r
211 //\r
212 TempDevicePath = DevicePath;\r
213 Status = gBS->LocateDevicePath (\r
214 &gEfiSimpleFileSystemProtocolGuid,\r
215 &TempDevicePath,\r
216 &Handle\r
217 );\r
218 if (!EFI_ERROR (Status) && IsDevicePathEnd (TempDevicePath)) {\r
219 FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);\r
220 if (FilePath) {\r
221 //\r
222 // Issue a dummy read to the device to check for media change.\r
223 // When the removable media is changed, any Block IO read/write will\r
224 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is\r
225 // returned. After the Block IO protocol is reinstalled, subsequent\r
226 // Block IO read/write will success.\r
227 //\r
228 Status = gBS->HandleProtocol (\r
229 Handle,\r
230 &gEfiBlockIoProtocolGuid,\r
231 (VOID **) &BlkIo\r
232 );\r
233 if (!EFI_ERROR (Status)) {\r
234 Buffer = AllocatePool (BlkIo->Media->BlockSize);\r
235 if (Buffer != NULL) {\r
236 BlkIo->ReadBlocks (\r
237 BlkIo,\r
238 BlkIo->Media->MediaId,\r
239 0,\r
240 BlkIo->Media->BlockSize,\r
241 Buffer\r
242 );\r
243 gBS->FreePool (Buffer);\r
244 }\r
245 }\r
246\r
247 Status = gBS->LoadImage (\r
248 TRUE,\r
249 mBdsImageHandle,\r
250 FilePath,\r
251 NULL,\r
252 0,\r
253 &ImageHandle\r
254 );\r
255 if (EFI_ERROR (Status)) {\r
256 //\r
257 // The DevicePath failed, and it's not a valid\r
258 // removable media device.\r
259 //\r
260 goto Done;\r
261 }\r
262 }\r
263 } else {\r
264 Status = EFI_NOT_FOUND;\r
265 }\r
266 }\r
267\r
268 if (EFI_ERROR (Status)) {\r
269 //\r
270 // It there is any error from the Boot attempt exit now.\r
271 //\r
272 goto Done;\r
273 }\r
274 //\r
275 // Provide the image with it's load options\r
276 //\r
277 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,
278 (VOID **) &ImageInfo);\r
279 ASSERT_EFI_ERROR (Status);\r
280\r
281 if (Option->LoadOptionsSize != 0) {\r
282 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;\r
283 ImageInfo->LoadOptions = Option->LoadOptions;\r
284 }\r
285 //\r
286 // Before calling the image, enable the Watchdog Timer for\r
287 // the 5 Minute period\r
288 //\r
289 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
290\r
291 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);\r
292 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Return Status = %r\n", Status));\r
293\r
294 //\r
295 // Clear the Watchdog Timer after the image returns\r
296 //\r
297 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
298\r
299Done:\r
300 //\r
301 // Clear Boot Current\r
302 //\r
303 gRT->SetVariable (\r
304 L"BootCurrent",\r
305 &gEfiGlobalVariableGuid,\r
306 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
307 0,\r
308 &Option->BootCurrent\r
309 );\r
310\r
311 return Status;\r
312}\r
313\r
314EFI_STATUS\r
315BdsBootByDiskSignatureAndPartition (\r
316 IN BDS_COMMON_OPTION * Option,\r
317 IN HARDDRIVE_DEVICE_PATH * HardDriveDevicePath,\r
318 IN UINT32 LoadOptionsSize,\r
319 IN VOID *LoadOptions,\r
320 OUT UINTN *ExitDataSize,\r
321 OUT CHAR16 **ExitData OPTIONAL\r
322 )\r
323/*++\r
324\r
325Routine Description:\r
326\r
327 Check to see if a hard ware device path was passed in. If it was then search\r
328 all the block IO devices for the passed in hard drive device path. \r
329 \r
330Arguments:\r
331\r
332 Option - The current processing boot option.\r
333\r
334 HardDriveDevicePath - EFI Device Path to boot, if it starts with a hard\r
335 drive device path.\r
336\r
337 LoadOptionsSize - Passed into gBS->StartImage ()\r
338 via the loaded image protocol.\r
339\r
340 LoadOptions - Passed into gBS->StartImage ()\r
341 via the loaded image protocol.\r
342\r
343 ExitDataSize - returned directly from gBS->StartImage ()\r
344\r
345 ExitData - returned directly from gBS->StartImage ()\r
346\r
347Returns:\r
348\r
349 EFI_SUCCESS - Status from gBS->StartImage (),\r
350 or BootByDiskSignatureAndPartition ()\r
351 \r
352 EFI_NOT_FOUND - If the Device Path is not found in the system\r
353\r
354--*/\r
355{\r
356 EFI_STATUS Status;\r
357 UINTN BlockIoHandleCount;\r
358 EFI_HANDLE *BlockIoBuffer;\r
359 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;\r
360 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePath;\r
361 HARDDRIVE_DEVICE_PATH *TmpHdPath;\r
362 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
363 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
364 UINTN Index;\r
365 BOOLEAN DevicePathMatch;\r
366 HARDDRIVE_DEVICE_PATH *TempPath;\r
367\r
368 *ExitDataSize = 0;\r
369 *ExitData = NULL;\r
370\r
371 if ( !((DevicePathType (&HardDriveDevicePath->Header) == MEDIA_DEVICE_PATH) &&\r
372 (DevicePathSubType (&HardDriveDevicePath->Header) == MEDIA_HARDDRIVE_DP))\r
373 ) {\r
374 //\r
375 // If the HardDriveDevicePath does not start with a Hard Drive Device Path\r
376 // exit.\r
377 //\r
378 return EFI_NOT_FOUND;\r
379 }\r
380 //\r
381 // The boot device have already been connected\r
382 //\r
383 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);\r
384 if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {\r
385 //\r
386 // If there was an error or there are no device handles that support\r
387 // the BLOCK_IO Protocol, then return.\r
388 //\r
389 return EFI_NOT_FOUND;\r
390 }\r
391 //\r
392 // Loop through all the device handles that support the BLOCK_IO Protocol\r
393 //\r
394 for (Index = 0; Index < BlockIoHandleCount; Index++) {\r
395\r
396 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);\r
397 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {\r
398 continue;\r
399 }\r
400 //\r
401 // Make PreviousDevicePath == the device path node before the end node\r
402 //\r
403 DevicePath = BlockIoDevicePath;\r
404 BlockIoHdDevicePath = NULL;\r
405\r
406 //\r
407 // find HardDriver device path node\r
408 //\r
409 while (!IsDevicePathEnd (DevicePath)) {\r
410 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && \r
411 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)\r
412 ) {\r
413 BlockIoHdDevicePath = DevicePath;\r
414 break;\r
415 }\r
416\r
417 DevicePath = NextDevicePathNode (DevicePath);\r
418 }\r
419\r
420 if (BlockIoHdDevicePath == NULL) {\r
421 continue;\r
422 }\r
423 //\r
424 // See if the harddrive device path in blockio matches the orig Hard Drive Node\r
425 //\r
426 DevicePathMatch = FALSE;\r
427\r
428 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePath;\r
429 TempPath = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
430\r
431 //\r
432 // Only several fields will be checked. NOT whole NODE\r
433 //\r
434 if ( TmpHdPath->PartitionNumber == TempPath->PartitionNumber &&\r
435 TmpHdPath->MBRType == TempPath->MBRType &&\r
436 TmpHdPath->SignatureType == TempPath->SignatureType &&\r
437 CompareGuid ((EFI_GUID *) TmpHdPath->Signature, (EFI_GUID *) TempPath->Signature)) {\r
438 //\r
439 // Get the matched device path\r
440 //\r
441 DevicePathMatch = TRUE;\r
442 }\r
443 //\r
444 // Only do the boot, when devicepath match\r
445 //\r
446 if (DevicePathMatch) {\r
447 //\r
448 // Combine the Block IO and Hard Drive Device path together and try\r
449 // to boot from it.\r
450 //\r
451 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);\r
452 NewDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);\r
453\r
454 //\r
455 // Recursive boot with new device path\r
456 //\r
457 Status = BdsLibBootViaBootOption (Option, NewDevicePath, ExitDataSize, ExitData);\r
458 if (!EFI_ERROR (Status)) {\r
459 break;\r
460 }\r
461 }\r
462 }\r
463\r
464 gBS->FreePool (BlockIoBuffer);\r
465 return Status;\r
466}\r
467\r
468EFI_STATUS\r
469BdsLibDeleteOptionFromHandle (\r
470 IN EFI_HANDLE Handle\r
471 )\r
472/*++\r
473\r
474Routine Description:\r
475\r
476 Delete the boot option associated with the handle passed in\r
477\r
478Arguments:\r
479\r
480 Handle - The handle which present the device path to create boot option\r
481\r
482Returns:\r
483\r
484 EFI_SUCCESS - Delete the boot option success\r
485\r
486 EFI_NOT_FOUND - If the Device Path is not found in the system\r
487\r
488 EFI_OUT_OF_RESOURCES - Lack of memory resource\r
489\r
490 Other - Error return value from SetVariable()\r
491\r
492--*/\r
493{\r
494 UINT16 *BootOrder;\r
495 UINT8 *BootOptionVar;\r
496 UINTN BootOrderSize;\r
497 UINTN BootOptionSize;\r
498 EFI_STATUS Status;\r
499 UINTN Index;\r
500 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];\r
501 UINTN DevicePathSize;\r
502 UINTN OptionDevicePathSize;\r
503 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
504 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
505 UINT8 *TempPtr;\r
506 CHAR16 *Description;\r
507\r
508 Status = EFI_SUCCESS;\r
509 BootOrder = NULL;\r
510 BootOrderSize = 0;\r
511\r
512 BootOrder = BdsLibGetVariableAndSize (\r
513 L"BootOrder",\r
514 &gEfiGlobalVariableGuid,\r
515 &BootOrderSize\r
516 );\r
517 if (NULL == BootOrder) {\r
518 return EFI_NOT_FOUND;\r
519 }\r
520\r
521 DevicePath = DevicePathFromHandle (Handle);\r
522 if (DevicePath == NULL) {\r
523 return EFI_NOT_FOUND;\r
524 }\r
525 DevicePathSize = GetDevicePathSize (DevicePath);\r
526\r
527 Index = 0;\r
528 while (Index < BootOrderSize / sizeof (UINT16)) {\r
529 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
530 BootOptionVar = BdsLibGetVariableAndSize (\r
531 BootOption,\r
532 &gEfiGlobalVariableGuid,\r
533 &BootOptionSize\r
534 );\r
535 if (NULL == BootOptionVar) {\r
536 gBS->FreePool (BootOrder);\r
537 return EFI_OUT_OF_RESOURCES;\r
538 }\r
539\r
540 TempPtr = BootOptionVar;\r
541 TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
542 Description = (CHAR16 *) TempPtr;\r
543 TempPtr += StrSize ((CHAR16 *) TempPtr);\r
544 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
545 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);\r
546\r
547 //\r
548 // Check whether the device path match\r
549 //\r
550 if ((OptionDevicePathSize == DevicePathSize) &&\r
551 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {\r
552 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);\r
553 gBS->FreePool (BootOptionVar);\r
554 break;\r
555 }\r
556\r
557 gBS->FreePool (BootOptionVar);\r
558 Index++;\r
559 }\r
560\r
561 Status = gRT->SetVariable (\r
562 L"BootOrder",\r
563 &gEfiGlobalVariableGuid,\r
564 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
565 BootOrderSize,\r
566 BootOrder\r
567 );\r
568\r
569 gBS->FreePool (BootOrder);\r
570\r
571 return Status;\r
572}\r
573\r
574EFI_STATUS\r
575BdsDeleteAllInvalidEfiBootOption (\r
576 VOID\r
577 )\r
578/*++\r
579\r
580Routine Description:\r
581\r
582 Delete all invalid EFI boot options. The probable invalid boot option could\r
583 be Removable media or Network boot device.\r
584\r
585Arguments:\r
586\r
587 VOID\r
588\r
589Returns:\r
590\r
591 EFI_SUCCESS - Delete all invalid boot option success\r
592\r
593 EFI_NOT_FOUND - Variable "BootOrder" is not found\r
594\r
595 EFI_OUT_OF_RESOURCES - Lack of memory resource\r
596\r
597 Other - Error return value from SetVariable()\r
598\r
599--*/\r
600{\r
601 UINT16 *BootOrder;\r
602 UINT8 *BootOptionVar;\r
603 UINTN BootOrderSize;\r
604 UINTN BootOptionSize;\r
605 EFI_STATUS Status;\r
606 UINTN Index;\r
607 UINTN Index2;\r
608 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];\r
609 UINTN OptionDevicePathSize;\r
610 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r
611 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;\r
612 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;\r
613 UINT8 *TempPtr;\r
614 CHAR16 *Description;\r
615 EFI_HANDLE Handle;\r
616 BOOLEAN NeedDelete;\r
617\r
618 Status = EFI_SUCCESS;\r
619 BootOrder = NULL;\r
620 BootOrderSize = 0;\r
621\r
622 BootOrder = BdsLibGetVariableAndSize (\r
623 L"BootOrder",\r
624 &gEfiGlobalVariableGuid,\r
625 &BootOrderSize\r
626 );\r
627 if (NULL == BootOrder) {\r
628 return EFI_NOT_FOUND;\r
629 }\r
630\r
631 Index = 0;\r
632 while (Index < BootOrderSize / sizeof (UINT16)) {\r
633 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
634 BootOptionVar = BdsLibGetVariableAndSize (\r
635 BootOption,\r
636 &gEfiGlobalVariableGuid,\r
637 &BootOptionSize\r
638 );\r
639 if (NULL == BootOptionVar) {\r
640 gBS->FreePool (BootOrder);\r
641 return EFI_OUT_OF_RESOURCES;\r
642 }\r
643\r
644 TempPtr = BootOptionVar;\r
645 TempPtr += sizeof (UINT32) + sizeof (UINT16);\r
646 Description = (CHAR16 *) TempPtr;\r
647 TempPtr += StrSize ((CHAR16 *) TempPtr);\r
648 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
649 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);\r
650\r
651 //\r
652 // Skip legacy boot option (BBS boot device)\r
653 //\r
654 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&\r
655 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {\r
656 gBS->FreePool (BootOptionVar);\r
657 Index++;\r
658 continue;\r
659 }\r
660\r
661 TempDevicePath = OptionDevicePath;\r
662 LastDeviceNode = OptionDevicePath;\r
663 while (!EfiIsDevicePathEnd (TempDevicePath)) {\r
664 LastDeviceNode = TempDevicePath;\r
665 TempDevicePath = EfiNextDevicePathNode (TempDevicePath);\r
666 }\r
667 //\r
668 // Skip the boot option that point to a file, since the device path in \r
669 // removable media boot option doesn't contains a file name.\r
670 //\r
671 if (((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&\r
672 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) ||\r
673 //\r
674 // Skip boot option for internal Shell, it's always valid\r
675 //\r
676 (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL)) {\r
677 gBS->FreePool (BootOptionVar);\r
678 Index++;\r
679 continue;\r
680 }\r
681\r
682 NeedDelete = TRUE;\r
683 //\r
684 // Check if it's a valid boot option for removable media\r
685 //\r
686 TempDevicePath = OptionDevicePath;\r
687 Status = gBS->LocateDevicePath (\r
688 &gEfiSimpleFileSystemProtocolGuid,\r
689 &TempDevicePath,\r
690 &Handle\r
691 );\r
692 if (!EFI_ERROR (Status)) {\r
693 NeedDelete = FALSE;\r
694 }\r
695 //\r
696 // Check if it's a valid boot option for network boot device\r
697 //\r
698 TempDevicePath = OptionDevicePath;\r
699 Status = gBS->LocateDevicePath (\r
700 &gEfiLoadFileProtocolGuid,\r
701 &TempDevicePath,\r
702 &Handle\r
703 );\r
704 if (!EFI_ERROR (Status)) {\r
705 NeedDelete = FALSE;\r
706 }\r
707\r
708 if (NeedDelete) {\r
709 //\r
710 // Delete this invalid boot option "Boot####"\r
711 //\r
712 Status = gRT->SetVariable (\r
713 BootOption,\r
714 &gEfiGlobalVariableGuid,\r
715 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
716 0,\r
717 NULL\r
718 );\r
719 //\r
720 // Mark this boot option in boot order as deleted\r
721 //\r
722 BootOrder[Index] = 0xffff;\r
723 }\r
724\r
725 gBS->FreePool (BootOptionVar);\r
726 Index++;\r
727 }\r
728\r
729 //\r
730 // Adjust boot order array\r
731 //\r
732 Index2 = 0;\r
733 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {\r
734 if (BootOrder[Index] != 0xffff) {\r
735 BootOrder[Index2] = BootOrder[Index];\r
736 Index2 ++;\r
737 }\r
738 }\r
739 Status = gRT->SetVariable (\r
740 L"BootOrder",\r
741 &gEfiGlobalVariableGuid,\r
742 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
743 Index2 * sizeof (UINT16),\r
744 BootOrder\r
745 );\r
746\r
747 gBS->FreePool (BootOrder);\r
748\r
749 return Status;\r
750}\r
751\r
752EFI_STATUS\r
753BdsLibEnumerateAllBootOption (\r
754 IN OUT LIST_ENTRY *BdsBootOptionList\r
755 )\r
756/*++\r
757\r
758Routine Description:\r
759\r
760 This function will enumerate all possible boot device in the system,\r
761 it will only excute once of every boot.\r
762\r
763Arguments:\r
764\r
765 BdsBootOptionList - The header of the link list which indexed all\r
766 current boot options\r
767\r
768Returns:\r
769\r
770 EFI_SUCCESS - Finished all the boot device enumerate and create\r
771 the boot option base on that boot device\r
772\r
773--*/\r
774{\r
775 EFI_STATUS Status;\r
776 UINT16 BootOptionNumber;\r
777 UINTN NumberFileSystemHandles;\r
778 EFI_HANDLE *FileSystemHandles;\r
779 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
780 UINTN Index;\r
781 UINTN NumberLoadFileHandles;\r
782 EFI_HANDLE *LoadFileHandles;\r
783 VOID *ProtocolInstance;\r
784 EFI_FIRMWARE_VOLUME_PROTOCOL *Fv;\r
785 UINTN FvHandleCount;\r
786 EFI_HANDLE *FvHandleBuffer;\r
787 EFI_FV_FILETYPE Type;\r
788 UINTN Size;\r
789 EFI_FV_FILE_ATTRIBUTES Attributes;\r
790 UINT32 AuthenticationStatus;\r
791 EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
792 EFI_HANDLE ImageHandle;\r
793 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
794 BOOLEAN NeedDelete;\r
795\r
796 BootOptionNumber = 0;\r
797\r
798 //\r
799 // If the boot device enumerate happened, just get the boot\r
800 // device from the boot order variable\r
801 //\r
802 if (mEnumBootDevice) {\r
803 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
804 return EFI_SUCCESS;\r
805 }\r
806 //\r
807 // Notes: this dirty code is to get the legacy boot option from the\r
808 // BBS table and create to variable as the EFI boot option, it should\r
809 // be removed after the CSM can provide legacy boot option directly\r
810 //\r
811 REFRESH_LEGACY_BOOT_OPTIONS;\r
812\r
813 //\r
814 // Delete invalid boot option\r
815 //\r
816 BdsDeleteAllInvalidEfiBootOption ();\r
817 //\r
818 // Parse removable media\r
819 //\r
820 gBS->LocateHandleBuffer (\r
821 ByProtocol,\r
822 &gEfiSimpleFileSystemProtocolGuid,\r
823 NULL,\r
824 &NumberFileSystemHandles,\r
825 &FileSystemHandles\r
826 );\r
827 for (Index = 0; Index < NumberFileSystemHandles; Index++) {\r
828 Status = gBS->HandleProtocol (\r
829 FileSystemHandles[Index],\r
830 &gEfiBlockIoProtocolGuid,\r
831 (VOID **) &BlkIo\r
832 );\r
833 if (!EFI_ERROR (Status)) {\r
834 if (!BlkIo->Media->RemovableMedia) {\r
835 //\r
836 // If the file system handle supports a BlkIo protocol,\r
837 // skip the removable media devices\r
838 //\r
839 continue;\r
840 }\r
841 }\r
842\r
843 //\r
844 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI\r
845 // machinename is ia32, ia64, x64, ...\r
846 //\r
847 FilePath = FileDevicePath (FileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);\r
848 NeedDelete = TRUE;\r
849 Status = gBS->LoadImage (\r
850 TRUE,\r
851 mBdsImageHandle,\r
852 FilePath,\r
853 NULL,\r
854 0,\r
855 &ImageHandle\r
856 );\r
857 if (!EFI_ERROR(Status)) {\r
858 //\r
859 // Verify the image is a EFI application (and not a driver)\r
860 //\r
861 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
862 ASSERT (!EFI_ERROR(Status));\r
863\r
864 if (ImageInfo->ImageCodeType == EfiLoaderCode) {\r
865 NeedDelete = FALSE;\r
866 }\r
867 }\r
868\r
869 if (NeedDelete) {\r
870 //\r
871 // No such file or the file is not a EFI application, delete this boot option\r
872 //\r
873 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);\r
874 } else {\r
875 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList);\r
876 BootOptionNumber++;\r
877 }\r
878 }\r
879\r
880 if (NumberFileSystemHandles) {\r
881 gBS->FreePool (FileSystemHandles);\r
882 }\r
883 //\r
884 // Parse Network Boot Device\r
885 //\r
886 gBS->LocateHandleBuffer (\r
887 ByProtocol,\r
888 &gEfiSimpleNetworkProtocolGuid,\r
889 NULL,\r
890 &NumberLoadFileHandles,\r
891 &LoadFileHandles\r
892 );\r
893 for (Index = 0; Index < NumberLoadFileHandles; Index++) {\r
894 Status = gBS->HandleProtocol (\r
895 LoadFileHandles[Index],\r
896 &gEfiLoadFileProtocolGuid,\r
897 (VOID **) &ProtocolInstance\r
898 );\r
899 if (EFI_ERROR (Status)) {\r
900 continue;\r
901 }\r
902\r
903 BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList);\r
904 BootOptionNumber++;\r
905 }\r
906\r
907 if (NumberLoadFileHandles) {\r
908 gBS->FreePool (LoadFileHandles);\r
909 }\r
910 //\r
911 // Check if we have on flash shell\r
912 //\r
913 gBS->LocateHandleBuffer (\r
914 ByProtocol,\r
915 &gEfiFirmwareVolumeProtocolGuid,\r
916 NULL,\r
917 &FvHandleCount,\r
918 &FvHandleBuffer\r
919 );\r
920 for (Index = 0; Index < FvHandleCount; Index++) {\r
921 gBS->HandleProtocol (\r
922 FvHandleBuffer[Index],\r
923 &gEfiFirmwareVolumeProtocolGuid,\r
924 (VOID **) &Fv\r
925 );\r
926\r
927 Status = Fv->ReadFile (\r
928 Fv,\r
929 &gEfiShellFileGuid,\r
930 NULL,\r
931 &Size,\r
932 &Type,\r
933 &Attributes,\r
934 &AuthenticationStatus\r
935 );\r
936 if (EFI_ERROR (Status)) {\r
937 //\r
938 // Skip if no shell file in the FV\r
939 //\r
940 continue;\r
941 }\r
942 //\r
943 // Build the shell boot option\r
944 //\r
945 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);\r
946 BootOptionNumber++;\r
947 }\r
948\r
949 if (FvHandleCount) {\r
950 gBS->FreePool (FvHandleBuffer);\r
951 }\r
952 //\r
953 // Make sure every boot only have one time\r
954 // boot device enumerate\r
955 //\r
956 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");\r
957 mEnumBootDevice = TRUE;\r
958\r
959 return EFI_SUCCESS;\r
960}\r
961\r
962VOID\r
963BdsLibBuildOptionFromHandle (\r
964 IN EFI_HANDLE Handle,\r
965 IN LIST_ENTRY *BdsBootOptionList\r
966 )\r
967/*++\r
968\r
969Routine Description:\r
970 \r
971 Build the boot option with the handle parsed in\r
972 \r
973Arguments:\r
974\r
975 Handle - The handle which present the device path to create boot option\r
976 \r
977 BdsBootOptionList - The header of the link list which indexed all current\r
978 boot options\r
979\r
980Returns:\r
981\r
982 VOID\r
983\r
984--*/\r
985{\r
986 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
987 CHAR16 *TempString;\r
988\r
989 DevicePath = DevicePathFromHandle (Handle);\r
990 TempString = DevicePathToStr (DevicePath);\r
991\r
992 //\r
993 // Create and register new boot option\r
994 //\r
995 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, TempString, L"BootOrder");\r
996}\r
997\r
998VOID\r
999BdsLibBuildOptionFromShell (\r
1000 IN EFI_HANDLE Handle,\r
1001 IN OUT LIST_ENTRY *BdsBootOptionList\r
1002 )\r
1003/*++\r
1004\r
1005Routine Description:\r
1006 \r
1007 Build the on flash shell boot option with the handle parsed in\r
1008 \r
1009Arguments:\r
1010\r
1011 Handle - The handle which present the device path to create on flash shell\r
1012 boot option\r
1013 \r
1014 BdsBootOptionList - The header of the link list which indexed all current\r
1015 boot options\r
1016\r
1017Returns:\r
1018\r
1019 None\r
1020\r
1021--*/\r
1022{\r
1023 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1024 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;\r
1025\r
1026 DevicePath = DevicePathFromHandle (Handle);\r
1027\r
1028 //\r
1029 // Build the shell device path\r
1030 //\r
1031 EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);\r
1032 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);\r
1033\r
1034 //\r
1035 // Create and register the shell boot option\r
1036 //\r
1037 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"Internal EFI Shell", L"BootOrder");\r
1038\r
1039}\r
1040\r
1041VOID\r
1042BdsLibBootNext (\r
1043 VOID\r
1044 )\r
1045/*++\r
1046\r
1047Routine Description:\r
1048 \r
1049 Boot from the EFI1.1 spec defined "BootNext" variable\r
1050 \r
1051Arguments:\r
1052\r
1053 None\r
1054 \r
1055Returns:\r
1056\r
1057 None\r
1058\r
1059--*/\r
1060{\r
1061 UINT16 *BootNext;\r
1062 UINTN BootNextSize;\r
1063 CHAR16 Buffer[20];\r
1064 BDS_COMMON_OPTION *BootOption;\r
1065 LIST_ENTRY TempList;\r
1066 UINTN ExitDataSize;\r
1067 CHAR16 *ExitData;\r
1068\r
1069 //\r
1070 // Init the boot option name buffer and temp link list\r
1071 //\r
1072 InitializeListHead (&TempList);\r
1073 ZeroMem (Buffer, sizeof (Buffer));\r
1074\r
1075 BootNext = BdsLibGetVariableAndSize (\r
1076 L"BootNext",\r
1077 &gEfiGlobalVariableGuid,\r
1078 &BootNextSize\r
1079 );\r
1080\r
1081 //\r
1082 // Clear the boot next variable first\r
1083 //\r
1084 if (BootNext != NULL) {\r
1085 gRT->SetVariable (\r
1086 L"BootNext",\r
1087 &gEfiGlobalVariableGuid,\r
1088 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1089 0,\r
1090 BootNext\r
1091 );\r
1092\r
1093 //\r
1094 // Start to build the boot option and try to boot\r
1095 //\r
1096 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);\r
1097 BootOption = BdsLibVariableToOption (&TempList, Buffer);\r
1098 BdsLibConnectDevicePath (BootOption->DevicePath);\r
1099 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);\r
1100 }\r
1101\r
1102}\r