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