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