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