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