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