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