]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/GenericBdsLib/BdsBoot.c
UEFI HII: Merge UEFI HII support changes from branch.
[mirror_edk2.git] / MdeModulePkg / Library / GenericBdsLib / BdsBoot.c
1 /** @file
2
3 Copyright (c) 2004 - 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
24 #include "InternalBdsLib.h"
25
26 BOOLEAN mEnumBootDevice = FALSE;
27
28 //
29 // This GUID is used for an EFI Variable that stores the front device pathes
30 // for a partial device path that starts with the HD node.
31 //
32 EFI_GUID mHdBootVariablePrivateGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } };
33
34
35
36 /**
37 Boot the legacy system with the boot option
38
39 @param Option The legacy boot option which have BBS device path
40
41 @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
42 legacy boot.
43 @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
44
45 **/
46 EFI_STATUS
47 BdsLibDoLegacyBoot (
48 IN BDS_COMMON_OPTION *Option
49 )
50 {
51 EFI_STATUS Status;
52 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
53
54 Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
55 if (EFI_ERROR (Status)) {
56 //
57 // If no LegacyBios protocol we do not support legacy boot
58 //
59 return EFI_UNSUPPORTED;
60 }
61 //
62 // Notes: if we seperate the int 19, then we don't need to refresh BBS
63 //
64 BdsRefreshBbsTableForBoot (Option);
65
66 //
67 // Write boot to OS performance data to a file
68 //
69 PERF_CODE (
70 WriteBootToOsPerformanceData ();
71 );
72
73 DEBUG ((DEBUG_INFO | DEBUG_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
83 /**
84 Process the boot option follow the EFI 1.1 specification and
85 special treat the legacy boot option with BBS_DEVICE_PATH.
86
87 @param Option The boot option need to be processed
88 @param DevicePath The device path which describe where to load the
89 boot image or the legcy BBS device path to boot
90 the legacy OS
91 @param ExitDataSize Returned directly from gBS->StartImage ()
92 @param ExitData Returned directly from gBS->StartImage ()
93
94 @retval EFI_SUCCESS Status from gBS->StartImage ()
95 @retval EFI_NOT_FOUND If the Device Path is not found in the system
96
97 **/
98 EFI_STATUS
99 BdsLibBootViaBootOption (
100 IN BDS_COMMON_OPTION * Option,
101 IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,
102 OUT UINTN *ExitDataSize,
103 OUT CHAR16 **ExitData OPTIONAL
104 )
105 {
106 EFI_STATUS Status;
107 EFI_HANDLE Handle;
108 EFI_HANDLE ImageHandle;
109 EFI_DEVICE_PATH_PROTOCOL *FilePath;
110 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
111 EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;
112 EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
113 LIST_ENTRY TempBootLists;
114
115 //
116 // Record the performance data for End of BDS
117 //
118 PERF_END (0, BDS_TOK, NULL, 0);
119
120 *ExitDataSize = 0;
121 *ExitData = NULL;
122
123 //
124 // Notes: put EFI64 ROM Shadow Solution
125 //
126 EFI64_SHADOW_ALL_LEGACY_ROM ();
127
128 //
129 // Notes: this code can be remove after the s3 script table
130 // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or
131 // EFI_EVENT_SIGNAL_LEGACY_BOOT
132 //
133 Status = gBS->LocateProtocol (&gEfiAcpiS3SaveProtocolGuid, NULL, (VOID **) &AcpiS3Save);
134 if (!EFI_ERROR (Status)) {
135 AcpiS3Save->S3Save (AcpiS3Save, NULL);
136 }
137 //
138 // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
139 // full device path
140 //
141 WorkingDevicePath = NULL;
142 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
143 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
144 WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (
145 (HARDDRIVE_DEVICE_PATH *)DevicePath
146 );
147 if (WorkingDevicePath != NULL) {
148 DevicePath = WorkingDevicePath;
149 }
150 }
151 //
152 // Signal the EFI_EVENT_SIGNAL_READY_TO_BOOT event
153 //
154 EfiSignalEventReadyToBoot();
155
156
157 //
158 // Set Boot Current
159 //
160 gRT->SetVariable (
161 L"BootCurrent",
162 &gEfiGlobalVariableGuid,
163 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
164 sizeof (UINT16),
165 &Option->BootCurrent
166 );
167
168 if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
169 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
170 ) {
171 //
172 // Check to see if we should legacy BOOT. If yes then do the legacy boot
173 //
174 return BdsLibDoLegacyBoot (Option);
175 }
176
177 //
178 // If the boot option point to Internal FV shell, make sure it is valid
179 //
180 Status = BdsLibUpdateFvFileDevicePath (&DevicePath, &gEfiShellFileGuid);
181 if (!EFI_ERROR(Status)) {
182 if (Option->DevicePath != NULL) {
183 SafeFreePool(Option->DevicePath);
184 }
185 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
186 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
187 //
188 // Update the shell boot option
189 //
190 InitializeListHead (&TempBootLists);
191 BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
192 }
193
194 //
195 // Drop the TPL level from TPL_APPLICATION to TPL_APPLICATION
196 //
197 gBS->RestoreTPL (TPL_APPLICATION);
198
199 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting EFI way %S\n", Option->Description));
200
201 Status = gBS->LoadImage (
202 TRUE,
203 mBdsImageHandle,
204 DevicePath,
205 NULL,
206 0,
207 &ImageHandle
208 );
209
210 //
211 // If we didn't find an image directly, we need to try as if it is a removable device boot opotion
212 // and load the image according to the default boot behavior for removable device.
213 //
214 if (EFI_ERROR (Status)) {
215 //
216 // check if there is a bootable removable media could be found in this device path ,
217 // and get the bootable media handle
218 //
219 Handle = BdsLibGetBootableHandle(DevicePath);
220 if (Handle == NULL) {
221 goto Done;
222 }
223 //
224 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
225 // machinename is ia32, ia64, x64, ...
226 //
227 FilePath = FileDevicePath (Handle, DEFAULT_REMOVABLE_FILE_NAME);
228 if (FilePath) {
229 Status = gBS->LoadImage (
230 TRUE,
231 mBdsImageHandle,
232 FilePath,
233 NULL,
234 0,
235 &ImageHandle
236 );
237 if (EFI_ERROR (Status)) {
238 //
239 // The DevicePath failed, and it's not a valid
240 // removable media device.
241 //
242 goto Done;
243 }
244 }
245 }
246
247 if (EFI_ERROR (Status)) {
248 //
249 // It there is any error from the Boot attempt exit now.
250 //
251 goto Done;
252 }
253 //
254 // Provide the image with it's load options
255 //
256 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
257 ASSERT_EFI_ERROR (Status);
258
259 if (Option->LoadOptionsSize != 0) {
260 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
261 ImageInfo->LoadOptions = Option->LoadOptions;
262 }
263 //
264 // Before calling the image, enable the Watchdog Timer for
265 // the 5 Minute period
266 //
267 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
268
269 Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
270 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
271
272 //
273 // Clear the Watchdog Timer after the image returns
274 //
275 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
276
277 Done:
278 //
279 // Clear Boot Current
280 //
281 gRT->SetVariable (
282 L"BootCurrent",
283 &gEfiGlobalVariableGuid,
284 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
285 0,
286 &Option->BootCurrent
287 );
288
289 //
290 // Raise the TPL level back to TPL_APPLICATION
291 //
292 gBS->RaiseTPL (TPL_APPLICATION);
293
294 return Status;
295 }
296
297
298 /**
299 Expand a device path that starts with a hard drive media device path node to be a
300 full device path that includes the full hardware path to the device. We need
301 to do this so it can be booted. As an optimizaiton the front match (the part point
302 to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
303 so a connect all is not required on every boot. All successful history device path
304 which point to partition node (the front part) will be saved.
305
306 @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
307 drive media device path.
308 A Pointer to the full device path.
309 @retval NULL Cannot find a valid Hard Drive devic path
310
311 **/
312 EFI_DEVICE_PATH_PROTOCOL *
313 BdsExpandPartitionPartialDevicePathToFull (
314 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
315 )
316 {
317 EFI_STATUS Status;
318 UINTN BlockIoHandleCount;
319 EFI_HANDLE *BlockIoBuffer;
320 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
321 EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
322 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
323 UINTN Index;
324 UINTN InstanceNum;
325 EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
326 EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
327 UINTN CachedDevicePathSize;
328 BOOLEAN DeviceExist;
329 BOOLEAN NeedAdjust;
330 EFI_DEVICE_PATH_PROTOCOL *Instance;
331 UINTN Size;
332
333 FullDevicePath = NULL;
334 //
335 // Check if there is prestore 'HDDP' variable.
336 // If exist, search the front path which point to partition node in the variable instants.
337 // If fail to find or 'HDDP' not exist, reconnect all and search in all system
338 //
339 CachedDevicePath = BdsLibGetVariableAndSize (
340 L"HDDP",
341 &mHdBootVariablePrivateGuid,
342 &CachedDevicePathSize
343 );
344 if (CachedDevicePath != NULL) {
345 TempNewDevicePath = CachedDevicePath;
346 DeviceExist = FALSE;
347 NeedAdjust = FALSE;
348 do {
349 //
350 // Check every instance of the variable
351 // First, check wheather the instance contain the partition node, which is needed for distinguishing multi
352 // partial partition boot option. Second, check wheather the instance could be connected.
353 //
354 Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
355 if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {
356 //
357 // Connect the device path instance, the device path point to hard drive media device path node
358 // e.g. ACPI() /PCI()/ATA()/Partition()
359 //
360 Status = BdsLibConnectDevicePath (Instance);
361 if (!EFI_ERROR (Status)) {
362 DeviceExist = TRUE;
363 break;
364 }
365 }
366 //
367 // Come here means the first instance is not matched
368 //
369 NeedAdjust = TRUE;
370 SafeFreePool(Instance);
371 } while (TempNewDevicePath != NULL);
372
373 if (DeviceExist) {
374 //
375 // Find the matched device path.
376 // Append the file path infomration from the boot option and return the fully expanded device path.
377 //
378 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
379 FullDevicePath = AppendDevicePath (Instance, DevicePath);
380
381 //
382 // Adjust the 'HDDP' instances sequense if the matched one is not first one.
383 //
384 if (NeedAdjust) {
385 //
386 // First delete the matched instance.
387 //
388 TempNewDevicePath = CachedDevicePath;
389 CachedDevicePath = BdsLibDelPartMatchInstance ( CachedDevicePath, Instance );
390 SafeFreePool (TempNewDevicePath);
391 //
392 // Second, append the remaining parth after the matched instance
393 //
394 TempNewDevicePath = CachedDevicePath;
395 CachedDevicePath = AppendDevicePathInstance ( Instance, CachedDevicePath );
396 SafeFreePool (TempNewDevicePath);
397 //
398 // Save the matching Device Path so we don't need to do a connect all next time
399 //
400 Status = gRT->SetVariable (
401 L"HDDP",
402 &mHdBootVariablePrivateGuid,
403 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
404 GetDevicePathSize (CachedDevicePath),
405 CachedDevicePath
406 );
407 }
408 SafeFreePool(Instance);
409 gBS->FreePool (CachedDevicePath);
410 return FullDevicePath;
411 }
412 }
413
414 //
415 // If we get here we fail to find or 'HDDP' not exist, and now we need
416 // to seach all devices in the system for a matched partition
417 //
418 BdsLibConnectAllDriversToAllControllers ();
419 Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
420 if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {
421 //
422 // If there was an error or there are no device handles that support
423 // the BLOCK_IO Protocol, then return.
424 //
425 return NULL;
426 }
427 //
428 // Loop through all the device handles that support the BLOCK_IO Protocol
429 //
430 for (Index = 0; Index < BlockIoHandleCount; Index++) {
431
432 Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
433 if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
434 continue;
435 }
436
437 if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {
438 //
439 // Find the matched partition device path
440 //
441 DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
442 FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
443
444 //
445 // Save the matched patition device path in 'HDDP' variable
446 //
447 if (CachedDevicePath != NULL) {
448 //
449 // Save the matched patition device path as first instance of 'HDDP' variable
450 //
451 if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
452 TempNewDevicePath = CachedDevicePath;
453 CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
454 SafeFreePool(TempNewDevicePath);
455
456 TempNewDevicePath = CachedDevicePath;
457 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
458 SafeFreePool(TempNewDevicePath);
459 } else {
460 TempNewDevicePath = CachedDevicePath;
461 CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
462 SafeFreePool(TempNewDevicePath);
463 }
464 //
465 // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
466 // If the user try to boot many OS in different HDs or partitions, in theary, the 'HDDP' variable maybe become larger and larger.
467 //
468 InstanceNum = 0;
469 TempNewDevicePath = CachedDevicePath;
470 while (!IsDevicePathEnd (TempNewDevicePath)) {
471 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
472 //
473 // Parse one instance
474 //
475 while (!IsDevicePathEndType (TempNewDevicePath)) {
476 TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
477 }
478 InstanceNum++;
479 //
480 // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
481 //
482 if (InstanceNum >= 12) {
483 SetDevicePathEndNode (TempNewDevicePath);
484 break;
485 }
486 }
487 } else {
488 CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
489 }
490
491 //
492 // Save the matching Device Path so we don't need to do a connect all next time
493 //
494 Status = gRT->SetVariable (
495 L"HDDP",
496 &mHdBootVariablePrivateGuid,
497 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
498 GetDevicePathSize (CachedDevicePath),
499 CachedDevicePath
500 );
501
502 break;
503 }
504 }
505 gBS->FreePool (CachedDevicePath);
506 gBS->FreePool (BlockIoBuffer);
507 return FullDevicePath;
508 }
509
510
511 /**
512 Check whether there is a instance in BlockIoDevicePath, which contain multi device path
513 instances, has the same partition node with HardDriveDevicePath device path
514
515 @param BlockIoDevicePath Multi device path instances which need to check
516 @param HardDriveDevicePath A device path which starts with a hard drive media
517 device path.
518
519 @retval TRUE There is a matched device path instance FALSE
520 -There is no matched device path instance
521
522 **/
523 BOOLEAN
524 MatchPartitionDevicePathNode (
525 IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
526 IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
527 )
528 {
529 HARDDRIVE_DEVICE_PATH *TmpHdPath;
530 HARDDRIVE_DEVICE_PATH *TempPath;
531 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
532 BOOLEAN Match;
533 EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;
534
535 if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
536 return FALSE;
537 }
538 //
539 // Make PreviousDevicePath == the device path node before the end node
540 //
541 DevicePath = BlockIoDevicePath;
542 BlockIoHdDevicePathNode = NULL;
543
544 //
545 // find the partition device path node
546 //
547 while (!IsDevicePathEnd (DevicePath)) {
548 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
549 (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
550 ) {
551 BlockIoHdDevicePathNode = DevicePath;
552 break;
553 }
554
555 DevicePath = NextDevicePathNode (DevicePath);
556 }
557
558 if (BlockIoHdDevicePathNode == NULL) {
559 return FALSE;
560 }
561 //
562 // See if the harddrive device path in blockio matches the orig Hard Drive Node
563 //
564 TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
565 TempPath = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
566 Match = FALSE;
567 //
568 // Check for the match
569 //
570 if ((TmpHdPath->MBRType == TempPath->MBRType) &&
571 (TmpHdPath->SignatureType == TempPath->SignatureType)) {
572 switch (TmpHdPath->SignatureType) {
573 case SIGNATURE_TYPE_GUID:
574 Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)TempPath->Signature);
575 break;
576 case SIGNATURE_TYPE_MBR:
577 Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == *(UINT32 *)(&(TempPath->Signature[0])));
578 break;
579 default:
580 Match = FALSE;
581 break;
582 }
583 }
584
585 return Match;
586 }
587
588
589 /**
590 Delete the boot option associated with the handle passed in
591
592 @param Handle The handle which present the device path to create
593 boot option
594
595 @retval EFI_SUCCESS Delete the boot option success
596 @retval EFI_NOT_FOUND If the Device Path is not found in the system
597 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
598 @retval Other Error return value from SetVariable()
599
600 **/
601 EFI_STATUS
602 BdsLibDeleteOptionFromHandle (
603 IN EFI_HANDLE Handle
604 )
605 {
606 UINT16 *BootOrder;
607 UINT8 *BootOptionVar;
608 UINTN BootOrderSize;
609 UINTN BootOptionSize;
610 EFI_STATUS Status;
611 UINTN Index;
612 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
613 UINTN DevicePathSize;
614 UINTN OptionDevicePathSize;
615 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
616 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
617 UINT8 *TempPtr;
618
619 Status = EFI_SUCCESS;
620 BootOrder = NULL;
621 BootOrderSize = 0;
622
623 BootOrder = BdsLibGetVariableAndSize (
624 L"BootOrder",
625 &gEfiGlobalVariableGuid,
626 &BootOrderSize
627 );
628 if (NULL == BootOrder) {
629 return EFI_NOT_FOUND;
630 }
631
632 DevicePath = DevicePathFromHandle (Handle);
633 if (DevicePath == NULL) {
634 return EFI_NOT_FOUND;
635 }
636 DevicePathSize = GetDevicePathSize (DevicePath);
637
638 Index = 0;
639 while (Index < BootOrderSize / sizeof (UINT16)) {
640 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
641 BootOptionVar = BdsLibGetVariableAndSize (
642 BootOption,
643 &gEfiGlobalVariableGuid,
644 &BootOptionSize
645 );
646 if (NULL == BootOptionVar) {
647 gBS->FreePool (BootOrder);
648 return EFI_OUT_OF_RESOURCES;
649 }
650
651 TempPtr = BootOptionVar;
652 TempPtr += sizeof (UINT32) + sizeof (UINT16);
653 TempPtr += StrSize ((CHAR16 *) TempPtr);
654 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
655 OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
656
657 //
658 // Check whether the device path match
659 //
660 if ((OptionDevicePathSize == DevicePathSize) &&
661 (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
662 BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
663 gBS->FreePool (BootOptionVar);
664 break;
665 }
666
667 gBS->FreePool (BootOptionVar);
668 Index++;
669 }
670
671 Status = gRT->SetVariable (
672 L"BootOrder",
673 &gEfiGlobalVariableGuid,
674 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
675 BootOrderSize,
676 BootOrder
677 );
678
679 gBS->FreePool (BootOrder);
680
681 return Status;
682 }
683
684
685 /**
686 Delete all invalid EFI boot options. The probable invalid boot option could
687 be Removable media or Network boot device.
688
689 VOID
690
691 @retval EFI_SUCCESS Delete all invalid boot option success
692 @retval EFI_NOT_FOUND Variable "BootOrder" is not found
693 @retval EFI_OUT_OF_RESOURCES Lack of memory resource
694 @retval Other Error return value from SetVariable()
695
696 **/
697 EFI_STATUS
698 BdsDeleteAllInvalidEfiBootOption (
699 VOID
700 )
701 {
702 UINT16 *BootOrder;
703 UINT8 *BootOptionVar;
704 UINTN BootOrderSize;
705 UINTN BootOptionSize;
706 EFI_STATUS Status;
707 UINTN Index;
708 UINTN Index2;
709 UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
710 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
711 UINT8 *TempPtr;
712
713 Status = EFI_SUCCESS;
714 BootOrder = NULL;
715 BootOrderSize = 0;
716
717 BootOrder = BdsLibGetVariableAndSize (
718 L"BootOrder",
719 &gEfiGlobalVariableGuid,
720 &BootOrderSize
721 );
722 if (NULL == BootOrder) {
723 return EFI_NOT_FOUND;
724 }
725
726 Index = 0;
727 while (Index < BootOrderSize / sizeof (UINT16)) {
728 UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
729 BootOptionVar = BdsLibGetVariableAndSize (
730 BootOption,
731 &gEfiGlobalVariableGuid,
732 &BootOptionSize
733 );
734 if (NULL == BootOptionVar) {
735 gBS->FreePool (BootOrder);
736 return EFI_OUT_OF_RESOURCES;
737 }
738
739 TempPtr = BootOptionVar;
740 TempPtr += sizeof (UINT32) + sizeof (UINT16);
741 TempPtr += StrSize ((CHAR16 *) TempPtr);
742 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
743
744 //
745 // Skip legacy boot option (BBS boot device)
746 //
747 if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
748 (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
749 gBS->FreePool (BootOptionVar);
750 Index++;
751 continue;
752 }
753
754 if (!BdsLibIsValidEFIBootOptDevicePath (OptionDevicePath, FALSE)) {
755 //
756 // Delete this invalid boot option "Boot####"
757 //
758 Status = gRT->SetVariable (
759 BootOption,
760 &gEfiGlobalVariableGuid,
761 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
762 0,
763 NULL
764 );
765 //
766 // Mark this boot option in boot order as deleted
767 //
768 BootOrder[Index] = 0xffff;
769 }
770
771 gBS->FreePool (BootOptionVar);
772 Index++;
773 }
774
775 //
776 // Adjust boot order array
777 //
778 Index2 = 0;
779 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
780 if (BootOrder[Index] != 0xffff) {
781 BootOrder[Index2] = BootOrder[Index];
782 Index2 ++;
783 }
784 }
785 Status = gRT->SetVariable (
786 L"BootOrder",
787 &gEfiGlobalVariableGuid,
788 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
789 Index2 * sizeof (UINT16),
790 BootOrder
791 );
792
793 gBS->FreePool (BootOrder);
794
795 return Status;
796 }
797
798
799 /**
800 This function will enumerate all possible boot device in the system,
801 it will only excute once of every boot.
802
803 @param BdsBootOptionList The header of the link list which indexed all
804 current boot options
805
806 @retval EFI_SUCCESS Finished all the boot device enumerate and create
807 the boot option base on that boot device
808
809 **/
810 EFI_STATUS
811 BdsLibEnumerateAllBootOption (
812 IN OUT LIST_ENTRY *BdsBootOptionList
813 )
814 {
815 EFI_STATUS Status;
816 UINT16 FloppyNumber;
817 UINT16 CdromNumber;
818 UINT16 UsbNumber;
819 UINT16 MiscNumber;
820 UINT16 NonBlockNumber;
821 UINTN NumberBlockIoHandles;
822 EFI_HANDLE *BlockIoHandles;
823 EFI_BLOCK_IO_PROTOCOL *BlkIo;
824 UINTN Index;
825 UINTN NumberSimpleNetworkHandles;
826 EFI_HANDLE *SimpleNetworkHandles;
827 UINTN FvHandleCount;
828 EFI_HANDLE *FvHandleBuffer;
829 EFI_FV_FILETYPE Type;
830 UINTN Size;
831 EFI_FV_FILE_ATTRIBUTES Attributes;
832 UINT32 AuthenticationStatus;
833 #if (PI_SPECIFICATION_VERSION < 0x00010000)
834 EFI_FIRMWARE_VOLUME_PROTOCOL *Fv;
835 #else
836 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
837 #endif
838 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
839 UINTN DevicePathType;
840 CHAR16 Buffer[40];
841 EFI_HANDLE *FileSystemHandles;
842 UINTN NumberFileSystemHandles;
843 BOOLEAN NeedDelete;
844 EFI_IMAGE_DOS_HEADER DosHeader;
845 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
846 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
847
848 FloppyNumber = 0;
849 CdromNumber = 0;
850 UsbNumber = 0;
851 MiscNumber = 0;
852 ZeroMem (Buffer, sizeof (Buffer));
853 //
854 // If the boot device enumerate happened, just get the boot
855 // device from the boot order variable
856 //
857 if (mEnumBootDevice) {
858 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
859 return EFI_SUCCESS;
860 }
861 //
862 // Notes: this dirty code is to get the legacy boot option from the
863 // BBS table and create to variable as the EFI boot option, it should
864 // be removed after the CSM can provide legacy boot option directly
865 //
866 REFRESH_LEGACY_BOOT_OPTIONS;
867
868 //
869 // Delete invalid boot option
870 //
871 BdsDeleteAllInvalidEfiBootOption ();
872 //
873 // Parse removable media
874 //
875 gBS->LocateHandleBuffer (
876 ByProtocol,
877 &gEfiBlockIoProtocolGuid,
878 NULL,
879 &NumberBlockIoHandles,
880 &BlockIoHandles
881 );
882 for (Index = 0; Index < NumberBlockIoHandles; Index++) {
883 Status = gBS->HandleProtocol (
884 BlockIoHandles[Index],
885 &gEfiBlockIoProtocolGuid,
886 (VOID **) &BlkIo
887 );
888 if (!EFI_ERROR (Status)) {
889 if (!BlkIo->Media->RemovableMedia) {
890 //
891 // skip the non-removable block devices
892 //
893 continue;
894 }
895 }
896 DevicePath = DevicePathFromHandle (BlockIoHandles[Index]);
897 DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);
898
899 switch (DevicePathType) {
900 case BDS_EFI_ACPI_FLOPPY_BOOT:
901 if (FloppyNumber == 0) {
902 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Floppy");
903 } else {
904 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Floppy %d", FloppyNumber);
905 }
906 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
907 FloppyNumber++;
908 break;
909
910 case BDS_EFI_MESSAGE_ATAPI_BOOT:
911 if (CdromNumber == 0) {
912 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI DVD/CDROM");
913 } else {
914 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI DVD/CDROM %d", CdromNumber);
915 }
916 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
917 CdromNumber++;
918 break;
919
920 case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
921 if (UsbNumber == 0) {
922 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI USB Device");
923 } else {
924 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI USB Device %d", UsbNumber);
925 }
926 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
927 UsbNumber++;
928 break;
929
930 case BDS_EFI_MESSAGE_SCSI_BOOT:
931 if (UsbNumber == 0) {
932 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI SCSI Device");
933 } else {
934 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI SCSI Device %d", UsbNumber);
935 }
936 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
937 UsbNumber++;
938 break;
939
940 case BDS_EFI_MESSAGE_MISC_BOOT:
941 if (MiscNumber == 0) {
942 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Misc Device");
943 } else {
944 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Misc Device %d", MiscNumber);
945 }
946 BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
947 MiscNumber++;
948 break;
949
950 default:
951 break;
952 }
953 }
954
955 if (NumberBlockIoHandles) {
956 gBS->FreePool (BlockIoHandles);
957 }
958
959 //
960 // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
961 //
962 NonBlockNumber = 0;
963 gBS->LocateHandleBuffer (
964 ByProtocol,
965 &gEfiSimpleFileSystemProtocolGuid,
966 NULL,
967 &NumberFileSystemHandles,
968 &FileSystemHandles
969 );
970 for (Index = 0; Index < NumberFileSystemHandles; Index++) {
971 Status = gBS->HandleProtocol (
972 FileSystemHandles[Index],
973 &gEfiBlockIoProtocolGuid,
974 (VOID **) &BlkIo
975 );
976 if (!EFI_ERROR (Status)) {
977 //
978 // Skip if the file system handle supports a BlkIo protocol,
979 //
980 continue;
981 }
982
983 //
984 // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
985 // machinename is ia32, ia64, x64, ...
986 //
987 Hdr.Union = &HdrData;
988 NeedDelete = TRUE;
989 Status = BdsLibGetImageHeader (
990 FileSystemHandles[Index],
991 DEFAULT_REMOVABLE_FILE_NAME,
992 &DosHeader,
993 Hdr
994 );
995 if (!EFI_ERROR (Status) &&
996 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
997 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
998 NeedDelete = FALSE;
999 }
1000
1001 if (NeedDelete) {
1002 //
1003 // No such file or the file is not a EFI application, delete this boot option
1004 //
1005 BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
1006 } else {
1007 if (NonBlockNumber == 0) {
1008 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device");
1009 } else {
1010 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Non-Block Boot Device %d", NonBlockNumber);
1011 }
1012 BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);
1013 NonBlockNumber++;
1014 }
1015 }
1016
1017 if (NumberFileSystemHandles) {
1018 gBS->FreePool (FileSystemHandles);
1019 }
1020
1021 //
1022 // Parse Network Boot Device
1023 //
1024 gBS->LocateHandleBuffer (
1025 ByProtocol,
1026 &gEfiSimpleNetworkProtocolGuid,
1027 NULL,
1028 &NumberSimpleNetworkHandles,
1029 &SimpleNetworkHandles
1030 );
1031 for (Index = 0; Index < NumberSimpleNetworkHandles; Index++) {
1032 if (Index == 0) {
1033 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Network");
1034 } else {
1035 UnicodeSPrint (Buffer, sizeof (Buffer), L"EFI Network %d", Index);
1036 }
1037 BdsLibBuildOptionFromHandle (SimpleNetworkHandles[Index], BdsBootOptionList, Buffer);
1038 }
1039
1040 if (NumberSimpleNetworkHandles) {
1041 gBS->FreePool (SimpleNetworkHandles);
1042 }
1043
1044 //
1045 // Check if we have on flash shell
1046 //
1047 gBS->LocateHandleBuffer (
1048 ByProtocol,
1049 #if (PI_SPECIFICATION_VERSION < 0x00010000)
1050 &gEfiFirmwareVolumeProtocolGuid,
1051 #else
1052 &gEfiFirmwareVolume2ProtocolGuid,
1053 #endif
1054 NULL,
1055 &FvHandleCount,
1056 &FvHandleBuffer
1057 );
1058 for (Index = 0; Index < FvHandleCount; Index++) {
1059 gBS->HandleProtocol (
1060 FvHandleBuffer[Index],
1061 #if (PI_SPECIFICATION_VERSION < 0x00010000)
1062 &gEfiFirmwareVolumeProtocolGuid,
1063 #else
1064 &gEfiFirmwareVolume2ProtocolGuid,
1065 #endif
1066 (VOID **) &Fv
1067 );
1068
1069 Status = Fv->ReadFile (
1070 Fv,
1071 &gEfiShellFileGuid,
1072 NULL,
1073 &Size,
1074 &Type,
1075 &Attributes,
1076 &AuthenticationStatus
1077 );
1078 if (EFI_ERROR (Status)) {
1079 //
1080 // Skip if no shell file in the FV
1081 //
1082 continue;
1083 }
1084 //
1085 // Build the shell boot option
1086 //
1087 BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
1088 }
1089
1090 if (FvHandleCount) {
1091 gBS->FreePool (FvHandleBuffer);
1092 }
1093 //
1094 // Make sure every boot only have one time
1095 // boot device enumerate
1096 //
1097 BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
1098 mEnumBootDevice = TRUE;
1099
1100 return EFI_SUCCESS;
1101 }
1102
1103
1104 /**
1105 Build the boot option with the handle parsed in
1106
1107 @param Handle The handle which present the device path to create
1108 boot option
1109 @param BdsBootOptionList The header of the link list which indexed all
1110 current boot options
1111
1112 @return VOID
1113
1114 **/
1115 VOID
1116 BdsLibBuildOptionFromHandle (
1117 IN EFI_HANDLE Handle,
1118 IN LIST_ENTRY *BdsBootOptionList,
1119 IN CHAR16 *String
1120 )
1121 {
1122 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1123
1124 DevicePath = DevicePathFromHandle (Handle);
1125
1126 //
1127 // Create and register new boot option
1128 //
1129 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");
1130 }
1131
1132
1133 /**
1134 Build the on flash shell boot option with the handle parsed in
1135
1136 @param Handle The handle which present the device path to create
1137 on flash shell boot option
1138 @param BdsBootOptionList The header of the link list which indexed all
1139 current boot options
1140
1141 @return None
1142
1143 **/
1144 VOID
1145 BdsLibBuildOptionFromShell (
1146 IN EFI_HANDLE Handle,
1147 IN OUT LIST_ENTRY *BdsBootOptionList
1148 )
1149 {
1150 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1151 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
1152
1153 DevicePath = DevicePathFromHandle (Handle);
1154
1155 //
1156 // Build the shell device path
1157 //
1158 EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);
1159 //
1160 //ShellNode.Header.Type = MEDIA_DEVICE_PATH;
1161 //ShellNode.Header.SubType = MEDIA_FV_FILEPATH_DP;
1162 //SetDevicePathNodeLength (&ShellNode.Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH));
1163 //CopyMem (&ShellNode.NameGuid, &gEfiShellFileGuid, sizeof (EFI_GUID));
1164 //
1165 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
1166
1167 //
1168 // Create and register the shell boot option
1169 //
1170 BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");
1171
1172 }
1173
1174
1175 /**
1176 Boot from the EFI1.1 spec defined "BootNext" variable
1177
1178 None
1179
1180 @return None
1181
1182 **/
1183 VOID
1184 BdsLibBootNext (
1185 VOID
1186 )
1187 {
1188 UINT16 *BootNext;
1189 UINTN BootNextSize;
1190 CHAR16 Buffer[20];
1191 BDS_COMMON_OPTION *BootOption;
1192 LIST_ENTRY TempList;
1193 UINTN ExitDataSize;
1194 CHAR16 *ExitData;
1195
1196 //
1197 // Init the boot option name buffer and temp link list
1198 //
1199 InitializeListHead (&TempList);
1200 ZeroMem (Buffer, sizeof (Buffer));
1201
1202 BootNext = BdsLibGetVariableAndSize (
1203 L"BootNext",
1204 &gEfiGlobalVariableGuid,
1205 &BootNextSize
1206 );
1207
1208 //
1209 // Clear the boot next variable first
1210 //
1211 if (BootNext != NULL) {
1212 gRT->SetVariable (
1213 L"BootNext",
1214 &gEfiGlobalVariableGuid,
1215 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1216 0,
1217 BootNext
1218 );
1219
1220 //
1221 // Start to build the boot option and try to boot
1222 //
1223 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
1224 BootOption = BdsLibVariableToOption (&TempList, Buffer);
1225 BdsLibConnectDevicePath (BootOption->DevicePath);
1226 BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
1227 }
1228
1229 }
1230
1231
1232
1233 /**
1234 Return the bootable media handle.
1235 First, check the device is connected
1236 Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
1237 Third, detect the the default boot file in the Media, and return the removable Media handle.
1238
1239 @param DevicePath Device Path to a bootable device
1240
1241 @retval NULL The device path points to an EFI bootable Media
1242 @retval NULL The media on the DevicePath is not bootable
1243
1244 **/
1245 EFI_HANDLE
1246 BdsLibGetBootableHandle (
1247 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1248 )
1249 {
1250 EFI_STATUS Status;
1251 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
1252 EFI_DEVICE_PATH_PROTOCOL *DupDevicePath;
1253 EFI_HANDLE Handle;
1254 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1255 VOID *Buffer;
1256 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1257 UINTN Size;
1258 UINTN TempSize;
1259 EFI_HANDLE ReturnHandle;
1260 EFI_HANDLE *SimpleFileSystemHandles;
1261
1262 UINTN NumberSimpleFileSystemHandles;
1263 UINTN Index;
1264 EFI_IMAGE_DOS_HEADER DosHeader;
1265 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
1266 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1267
1268 UpdatedDevicePath = DevicePath;
1269 //
1270 // Check whether the device is connected
1271 //
1272 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);
1273 if (EFI_ERROR (Status)) {
1274 //
1275 // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
1276 //
1277 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);
1278 if (EFI_ERROR (Status)) {
1279 //
1280 // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
1281 //
1282 UpdatedDevicePath = DevicePath;
1283 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
1284 gBS->ConnectController (Handle, NULL, NULL, TRUE);
1285 }
1286 } else {
1287 //
1288 // Get BlockIo protocal and check removable attribute
1289 //
1290 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
1291 //
1292 // Issue a dummy read to the device to check for media change.
1293 // When the removable media is changed, any Block IO read/write will
1294 // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
1295 // returned. After the Block IO protocol is reinstalled, subsequent
1296 // Block IO read/write will success.
1297 //
1298 Buffer = AllocatePool (BlockIo->Media->BlockSize);
1299 if (Buffer != NULL) {
1300 BlockIo->ReadBlocks (
1301 BlockIo,
1302 BlockIo->Media->MediaId,
1303 0,
1304 BlockIo->Media->BlockSize,
1305 Buffer
1306 );
1307 gBS->FreePool (Buffer);
1308 }
1309 }
1310
1311 //
1312 // Detect the the default boot file from removable Media
1313 //
1314
1315 //
1316 // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus
1317 // Try to locate the USB node device path first, if fail then use its previour PCI node to search
1318 //
1319 DupDevicePath = DuplicateDevicePath (DevicePath);
1320 UpdatedDevicePath = DupDevicePath;
1321 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
1322 //
1323 // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node
1324 // Acpi()/Pci()/Usb() --> Acpi()/Pci()
1325 //
1326 if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&
1327 (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {
1328 //
1329 // Remove the usb node, let the device path only point to PCI node
1330 //
1331 SetDevicePathEndNode (UpdatedDevicePath);
1332 UpdatedDevicePath = DupDevicePath;
1333 } else {
1334 UpdatedDevicePath = DevicePath;
1335 }
1336
1337 //
1338 // Get the device path size of boot option
1339 //
1340 Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
1341 ReturnHandle = NULL;
1342 gBS->LocateHandleBuffer (
1343 ByProtocol,
1344 &gEfiSimpleFileSystemProtocolGuid,
1345 NULL,
1346 &NumberSimpleFileSystemHandles,
1347 &SimpleFileSystemHandles
1348 );
1349 for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
1350 //
1351 // Get the device path size of SimpleFileSystem handle
1352 //
1353 TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
1354 TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
1355 //
1356 // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
1357 //
1358 if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {
1359 //
1360 // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
1361 // machinename is ia32, ia64, x64, ...
1362 //
1363 Hdr.Union = &HdrData;
1364 Status = BdsLibGetImageHeader (
1365 SimpleFileSystemHandles[Index],
1366 DEFAULT_REMOVABLE_FILE_NAME,
1367 &DosHeader,
1368 Hdr
1369 );
1370 if (!EFI_ERROR (Status) &&
1371 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
1372 Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
1373 ReturnHandle = SimpleFileSystemHandles[Index];
1374 break;
1375 }
1376 }
1377 }
1378
1379 if (DupDevicePath != NULL) {
1380 SafeFreePool(DupDevicePath);
1381 }
1382 if (SimpleFileSystemHandles !=NULL ) {
1383 gBS->FreePool (SimpleFileSystemHandles);
1384 }
1385
1386 return ReturnHandle;
1387 }
1388
1389
1390
1391
1392 /**
1393 Check to see if the network cable is plugged in. If the DevicePath is not
1394 connected it will be connected.
1395
1396 @param DevicePath Device Path to check
1397
1398 @retval TRUE DevicePath points to an Network that is connected
1399 @retval FALSE DevicePath does not point to a bootable network
1400
1401 **/
1402 BOOLEAN
1403 BdsLibNetworkBootWithMediaPresent (
1404 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1405 )
1406 {
1407 EFI_STATUS Status;
1408 EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
1409 EFI_HANDLE Handle;
1410 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
1411 BOOLEAN MediaPresent;
1412
1413 MediaPresent = FALSE;
1414
1415 UpdatedDevicePath = DevicePath;
1416 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
1417 if (EFI_ERROR (Status)) {
1418 //
1419 // Device not present so see if we need to connect it
1420 //
1421 Status = BdsLibConnectDevicePath (DevicePath);
1422 if (!EFI_ERROR (Status)) {
1423 //
1424 // This one should work after we did the connect
1425 //
1426 Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
1427 }
1428 }
1429
1430 if (!EFI_ERROR (Status)) {
1431 Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
1432 if (!EFI_ERROR (Status)) {
1433 if (Snp->Mode->MediaPresentSupported) {
1434 if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
1435 //
1436 // In case some one else is using the SNP check to see if it's connected
1437 //
1438 MediaPresent = Snp->Mode->MediaPresent;
1439 } else {
1440 //
1441 // No one is using SNP so we need to Start and Initialize so
1442 // MediaPresent will be valid.
1443 //
1444 Status = Snp->Start (Snp);
1445 if (!EFI_ERROR (Status)) {
1446 Status = Snp->Initialize (Snp, 0, 0);
1447 if (!EFI_ERROR (Status)) {
1448 MediaPresent = Snp->Mode->MediaPresent;
1449 Snp->Shutdown (Snp);
1450 }
1451 Snp->Stop (Snp);
1452 }
1453 }
1454 } else {
1455 MediaPresent = TRUE;
1456 }
1457 }
1458 }
1459
1460 return MediaPresent;
1461 }
1462
1463
1464
1465 /**
1466 For a bootable Device path, return its boot type
1467
1468 @param DevicePath The bootable device Path to check
1469
1470 @return UINT32 Boot type :
1471 @return //
1472 @return // If the device path contains any media deviec path node, it is media boot type
1473 @return // For the floppy node, handle it as media node
1474 @return //
1475 @return BDS_EFI_MEDIA_HD_BOOT
1476 @return BDS_EFI_MEDIA_CDROM_BOOT
1477 @return BDS_EFI_ACPI_FLOPPY_BOOT
1478 @return //
1479 @return // If the device path not contains any media deviec path node, and
1480 @return // its last device path node point to a message device path node, it is
1481 @return // a message boot type
1482 @return //
1483 @return BDS_EFI_MESSAGE_ATAPI_BOOT
1484 @return BDS_EFI_MESSAGE_SCSI_BOOT
1485 @return BDS_EFI_MESSAGE_USB_DEVICE_BOOT
1486 @return BDS_EFI_MESSAGE_MISC_BOOT
1487 @return //
1488 @return // Legacy boot type
1489 @return //
1490 @return BDS_LEGACY_BBS_BOOT
1491 @return //
1492 @return // If a EFI Removable BlockIO device path not point to a media and message devie,
1493 @return // it is unsupported
1494 @return //
1495 @return BDS_EFI_UNSUPPORT
1496
1497 **/
1498 UINT32
1499 BdsGetBootTypeFromDevicePath (
1500 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
1501 )
1502 {
1503 ACPI_HID_DEVICE_PATH *Acpi;
1504 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1505 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
1506
1507
1508 if (NULL == DevicePath) {
1509 return BDS_EFI_UNSUPPORT;
1510 }
1511
1512 TempDevicePath = DevicePath;
1513
1514 while (!IsDevicePathEndType (TempDevicePath)) {
1515 switch (DevicePathType (TempDevicePath)) {
1516 case BBS_DEVICE_PATH:
1517 return BDS_LEGACY_BBS_BOOT;
1518 case MEDIA_DEVICE_PATH:
1519 if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {
1520 return BDS_EFI_MEDIA_HD_BOOT;
1521 } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {
1522 return BDS_EFI_MEDIA_CDROM_BOOT;
1523 }
1524 break;
1525 case ACPI_DEVICE_PATH:
1526 Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;
1527 if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {
1528 return BDS_EFI_ACPI_FLOPPY_BOOT;
1529 }
1530 break;
1531 case MESSAGING_DEVICE_PATH:
1532 //
1533 // if the device path not only point to driver device, it is not a messaging device path.
1534 //
1535 LastDeviceNode = NextDevicePathNode (TempDevicePath);
1536 if (!IsDevicePathEndType (LastDeviceNode)) {
1537 break;
1538 }
1539
1540 if (DevicePathSubType(TempDevicePath) == MSG_ATAPI_DP) {
1541 return BDS_EFI_MESSAGE_ATAPI_BOOT;
1542 } else if (DevicePathSubType(TempDevicePath) == MSG_USB_DP) {
1543 return BDS_EFI_MESSAGE_USB_DEVICE_BOOT;
1544 } else if (DevicePathSubType(TempDevicePath) == MSG_SCSI_DP) {
1545 return BDS_EFI_MESSAGE_SCSI_BOOT;
1546 }
1547 return BDS_EFI_MESSAGE_MISC_BOOT;
1548 default:
1549 break;
1550 }
1551 TempDevicePath = NextDevicePathNode (TempDevicePath);
1552 }
1553
1554 return BDS_EFI_UNSUPPORT;
1555 }
1556
1557
1558 /**
1559 Check whether the Device path in a boot option point to a valide bootable device,
1560 And if CheckMedia is true, check the device is ready to boot now.
1561
1562 DevPath -- the Device path in a boot option
1563 CheckMedia -- if true, check the device is ready to boot now.
1564
1565 @return TRUE -- the Device path is valide
1566 @return FALSE -- the Device path is invalide .
1567
1568 **/
1569 BOOLEAN
1570 BdsLibIsValidEFIBootOptDevicePath (
1571 IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
1572 IN BOOLEAN CheckMedia
1573 )
1574 {
1575 EFI_STATUS Status;
1576 EFI_HANDLE Handle;
1577 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1578 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
1579 EFI_BLOCK_IO_PROTOCOL *BlockIo;
1580
1581 TempDevicePath = DevPath;
1582 LastDeviceNode = DevPath;
1583 //
1584 // Check if it's a valid boot option for network boot device
1585 // Only check if there is SimpleNetworkProtocol installed. If yes, that means
1586 // there is the network card there.
1587 //
1588 Status = gBS->LocateDevicePath (
1589 &gEfiSimpleNetworkProtocolGuid,
1590 &TempDevicePath,
1591 &Handle
1592 );
1593 if (EFI_ERROR (Status)) {
1594 //
1595 // Device not present so see if we need to connect it
1596 //
1597 TempDevicePath = DevPath;
1598 BdsLibConnectDevicePath (TempDevicePath);
1599 Status = gBS->LocateDevicePath (
1600 &gEfiSimpleNetworkProtocolGuid,
1601 &TempDevicePath,
1602 &Handle
1603 );
1604 }
1605 if (!EFI_ERROR (Status)) {
1606 if (CheckMedia) {
1607 //
1608 // Test if it is ready to boot now
1609 //
1610 if (BdsLibNetworkBootWithMediaPresent(DevPath)) {
1611 return TRUE;
1612 }
1613 } else {
1614 return TRUE;
1615 }
1616 }
1617
1618 //
1619 // If the boot option point to a file, it is a valid EFI boot option,
1620 // and assume it is ready to boot now
1621 //
1622 while (!EfiIsDevicePathEnd (TempDevicePath)) {
1623 LastDeviceNode = TempDevicePath;
1624 TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
1625 }
1626 if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
1627 (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {
1628 return TRUE;
1629 }
1630
1631 //
1632 // If the boot option point to a internal Shell, it is a valid EFI boot option,
1633 // and assume it is ready to boot now
1634 //
1635 if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {
1636 return TRUE;
1637 }
1638
1639 //
1640 // If the boot option point to a blockIO device, no matter whether or not it is a removeable device, it is a valid EFI boot option
1641 //
1642 TempDevicePath = DevPath;
1643 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
1644 if (EFI_ERROR (Status)) {
1645 //
1646 // Device not present so see if we need to connect it
1647 //
1648 Status = BdsLibConnectDevicePath (DevPath);
1649 if (!EFI_ERROR (Status)) {
1650 //
1651 // Try again to get the Block Io protocol after we did the connect
1652 //
1653 TempDevicePath = DevPath;
1654 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
1655 }
1656 }
1657 if (!EFI_ERROR (Status)) {
1658 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
1659 if (!EFI_ERROR (Status)) {
1660 if (CheckMedia) {
1661 //
1662 // Test if it is ready to boot now
1663 //
1664 if (BdsLibGetBootableHandle (DevPath) != NULL) {
1665 return TRUE;
1666 }
1667 } else {
1668 return TRUE;
1669 }
1670 }
1671 } else {
1672 //
1673 // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,
1674 //
1675 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
1676 if (!EFI_ERROR (Status)) {
1677 if (CheckMedia) {
1678 //
1679 // Test if it is ready to boot now
1680 //
1681 if (BdsLibGetBootableHandle (DevPath) != NULL) {
1682 return TRUE;
1683 }
1684 } else {
1685 return TRUE;
1686 }
1687 }
1688 }
1689
1690 return FALSE;
1691 }
1692
1693
1694 /**
1695 According to a file guild, check a Fv file device path is valid. If it is invalid,
1696 try to return the valid device path.
1697 FV address maybe changes for memory layout adjust from time to time, use this funciton
1698 could promise the Fv file device path is right.
1699
1700 @param DevicePath on input, the Fv file device path need to check on
1701 output, the updated valid Fv file device path
1702 @param FileGuid the Fv file guild
1703
1704 @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
1705 parameter
1706 @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
1707 guild at all
1708 @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
1709 valid
1710 @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
1711 and return the updated device path in DevicePath
1712
1713 **/
1714 EFI_STATUS
1715 EFIAPI
1716 BdsLibUpdateFvFileDevicePath (
1717 IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
1718 IN EFI_GUID *FileGuid
1719 )
1720 {
1721 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1722 EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
1723 EFI_STATUS Status;
1724 EFI_GUID *GuidPoint;
1725 UINTN Index;
1726 UINTN FvHandleCount;
1727 EFI_HANDLE *FvHandleBuffer;
1728 EFI_FV_FILETYPE Type;
1729 UINTN Size;
1730 EFI_FV_FILE_ATTRIBUTES Attributes;
1731 UINT32 AuthenticationStatus;
1732 BOOLEAN FindFvFile;
1733 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
1734 #if (PI_SPECIFICATION_VERSION < 0x00010000)
1735 EFI_FIRMWARE_VOLUME_PROTOCOL *Fv;
1736 #else
1737 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1738 #endif
1739 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
1740 EFI_HANDLE FoundFvHandle;
1741 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
1742
1743 if ((DevicePath == NULL) || (*DevicePath == NULL)) {
1744 return EFI_INVALID_PARAMETER;
1745 }
1746 if (FileGuid == NULL) {
1747 return EFI_INVALID_PARAMETER;
1748 }
1749 //
1750 // Check whether the device path point to the default the input Fv file
1751 //
1752 TempDevicePath = *DevicePath;
1753 LastDeviceNode = TempDevicePath;
1754 while (!EfiIsDevicePathEnd (TempDevicePath)) {
1755 LastDeviceNode = TempDevicePath;
1756 TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
1757 }
1758 GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
1759 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode
1760 );
1761 if (GuidPoint == NULL) {
1762 //
1763 // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
1764 //
1765 return EFI_UNSUPPORTED;
1766 }
1767 if (!CompareGuid (GuidPoint, FileGuid)) {
1768 //
1769 // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
1770 //
1771 return EFI_UNSUPPORTED;
1772 }
1773
1774 //
1775 // Check whether the input Fv file device path is valid
1776 //
1777 TempDevicePath = *DevicePath;
1778 FoundFvHandle = NULL;
1779 Status = gBS->LocateDevicePath (
1780 #if (PI_SPECIFICATION_VERSION < 0x00010000)
1781 &gEfiFirmwareVolumeProtocolGuid,
1782 #else
1783 &gEfiFirmwareVolume2ProtocolGuid,
1784 #endif
1785 &TempDevicePath,
1786 &FoundFvHandle
1787 );
1788 if (!EFI_ERROR (Status)) {
1789 Status = gBS->HandleProtocol (
1790 FoundFvHandle,
1791 #if (PI_SPECIFICATION_VERSION < 0x00010000)
1792 &gEfiFirmwareVolumeProtocolGuid,
1793 #else
1794 &gEfiFirmwareVolume2ProtocolGuid,
1795 #endif
1796 (VOID **) &Fv
1797 );
1798 if (!EFI_ERROR (Status)) {
1799 //
1800 // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
1801 //
1802 Status = Fv->ReadFile (
1803 Fv,
1804 FileGuid,
1805 NULL,
1806 &Size,
1807 &Type,
1808 &Attributes,
1809 &AuthenticationStatus
1810 );
1811 if (!EFI_ERROR (Status)) {
1812 return EFI_ALREADY_STARTED;
1813 }
1814 }
1815 }
1816
1817 //
1818 // Look for the input wanted FV file in current FV
1819 // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
1820 //
1821 FindFvFile = FALSE;
1822 FoundFvHandle = NULL;
1823 Status = gBS->HandleProtocol (
1824 mBdsImageHandle,
1825 &gEfiLoadedImageProtocolGuid,
1826 (VOID **) &LoadedImage
1827 );
1828 if (!EFI_ERROR (Status)) {
1829 Status = gBS->HandleProtocol (
1830 LoadedImage->DeviceHandle,
1831 #if (PI_SPECIFICATION_VERSION < 0x00010000)
1832 &gEfiFirmwareVolumeProtocolGuid,
1833 #else
1834 &gEfiFirmwareVolume2ProtocolGuid,
1835 #endif
1836 (VOID **) &Fv
1837 );
1838 if (!EFI_ERROR (Status)) {
1839 Status = Fv->ReadFile (
1840 Fv,
1841 FileGuid,
1842 NULL,
1843 &Size,
1844 &Type,
1845 &Attributes,
1846 &AuthenticationStatus
1847 );
1848 if (!EFI_ERROR (Status)) {
1849 FindFvFile = TRUE;
1850 FoundFvHandle = LoadedImage->DeviceHandle;
1851 }
1852 }
1853 }
1854 //
1855 // Second, if fail to find, try to enumerate all FV
1856 //
1857 if (!FindFvFile) {
1858 gBS->LocateHandleBuffer (
1859 ByProtocol,
1860 #if (PI_SPECIFICATION_VERSION < 0x00010000)
1861 &gEfiFirmwareVolumeProtocolGuid,
1862 #else
1863 &gEfiFirmwareVolume2ProtocolGuid,
1864 #endif
1865 NULL,
1866 &FvHandleCount,
1867 &FvHandleBuffer
1868 );
1869 for (Index = 0; Index < FvHandleCount; Index++) {
1870 gBS->HandleProtocol (
1871 FvHandleBuffer[Index],
1872 #if (PI_SPECIFICATION_VERSION < 0x00010000)
1873 &gEfiFirmwareVolumeProtocolGuid,
1874 #else
1875 &gEfiFirmwareVolume2ProtocolGuid,
1876 #endif
1877 (VOID **) &Fv
1878 );
1879
1880 Status = Fv->ReadFile (
1881 Fv,
1882 FileGuid,
1883 NULL,
1884 &Size,
1885 &Type,
1886 &Attributes,
1887 &AuthenticationStatus
1888 );
1889 if (EFI_ERROR (Status)) {
1890 //
1891 // Skip if input Fv file not in the FV
1892 //
1893 continue;
1894 }
1895 FindFvFile = TRUE;
1896 FoundFvHandle = FvHandleBuffer[Index];
1897 break;
1898 }
1899 }
1900
1901 if (FindFvFile) {
1902 //
1903 // Build the shell device path
1904 //
1905 NewDevicePath = DevicePathFromHandle (FoundFvHandle);
1906 EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
1907 NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
1908 *DevicePath = NewDevicePath;
1909 return EFI_SUCCESS;
1910 }
1911 return EFI_NOT_FOUND;
1912 }