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