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