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