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