1 | /** @file
|
---|
2 | Library functions which relates with booting.
|
---|
3 |
|
---|
4 | Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
---|
5 | Copyright (c) 2011 - 2021, Intel Corporation. All rights reserved.<BR>
|
---|
6 | (C) Copyright 2015-2021 Hewlett Packard Enterprise Development LP<BR>
|
---|
7 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
8 |
|
---|
9 | **/
|
---|
10 |
|
---|
11 | #include "InternalBm.h"
|
---|
12 |
|
---|
13 | EFI_RAM_DISK_PROTOCOL *mRamDisk = NULL;
|
---|
14 |
|
---|
15 | EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION mBmRefreshLegacyBootOption = NULL;
|
---|
16 | EFI_BOOT_MANAGER_LEGACY_BOOT mBmLegacyBoot = NULL;
|
---|
17 |
|
---|
18 | ///
|
---|
19 | /// This GUID is used for an EFI Variable that stores the front device pathes
|
---|
20 | /// for a partial device path that starts with the HD node.
|
---|
21 | ///
|
---|
22 | EFI_GUID mBmHardDriveBootVariableGuid = {
|
---|
23 | 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x08, 0xe2, 0x0e, 0x90, 0x6c, 0xb6, 0xde }
|
---|
24 | };
|
---|
25 | EFI_GUID mBmAutoCreateBootOptionGuid = {
|
---|
26 | 0x8108ac4e, 0x9f11, 0x4d59, { 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2 }
|
---|
27 | };
|
---|
28 |
|
---|
29 | /**
|
---|
30 |
|
---|
31 | End Perf entry of BDS
|
---|
32 |
|
---|
33 | @param Event The triggered event.
|
---|
34 | @param Context Context for this event.
|
---|
35 |
|
---|
36 | **/
|
---|
37 | VOID
|
---|
38 | EFIAPI
|
---|
39 | BmEndOfBdsPerfCode (
|
---|
40 | IN EFI_EVENT Event,
|
---|
41 | IN VOID *Context
|
---|
42 | )
|
---|
43 | {
|
---|
44 | //
|
---|
45 | // Record the performance data for End of BDS
|
---|
46 | //
|
---|
47 | PERF_CROSSMODULE_END ("BDS");
|
---|
48 |
|
---|
49 | return;
|
---|
50 | }
|
---|
51 |
|
---|
52 | /**
|
---|
53 | The function registers the legacy boot support capabilities.
|
---|
54 |
|
---|
55 | @param RefreshLegacyBootOption The function pointer to create all the legacy boot options.
|
---|
56 | @param LegacyBoot The function pointer to boot the legacy boot option.
|
---|
57 | **/
|
---|
58 | VOID
|
---|
59 | EFIAPI
|
---|
60 | EfiBootManagerRegisterLegacyBootSupport (
|
---|
61 | EFI_BOOT_MANAGER_REFRESH_LEGACY_BOOT_OPTION RefreshLegacyBootOption,
|
---|
62 | EFI_BOOT_MANAGER_LEGACY_BOOT LegacyBoot
|
---|
63 | )
|
---|
64 | {
|
---|
65 | mBmRefreshLegacyBootOption = RefreshLegacyBootOption;
|
---|
66 | mBmLegacyBoot = LegacyBoot;
|
---|
67 | }
|
---|
68 |
|
---|
69 | /**
|
---|
70 | Return TRUE when the boot option is auto-created instead of manually added.
|
---|
71 |
|
---|
72 | @param BootOption Pointer to the boot option to check.
|
---|
73 |
|
---|
74 | @retval TRUE The boot option is auto-created.
|
---|
75 | @retval FALSE The boot option is manually added.
|
---|
76 | **/
|
---|
77 | BOOLEAN
|
---|
78 | BmIsAutoCreateBootOption (
|
---|
79 | EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
|
---|
80 | )
|
---|
81 | {
|
---|
82 | if ((BootOption->OptionalDataSize == sizeof (EFI_GUID)) &&
|
---|
83 | CompareGuid ((EFI_GUID *)BootOption->OptionalData, &mBmAutoCreateBootOptionGuid)
|
---|
84 | )
|
---|
85 | {
|
---|
86 | return TRUE;
|
---|
87 | } else {
|
---|
88 | return FALSE;
|
---|
89 | }
|
---|
90 | }
|
---|
91 |
|
---|
92 | /**
|
---|
93 | Find the boot option in the NV storage and return the option number.
|
---|
94 |
|
---|
95 | @param OptionToFind Boot option to be checked.
|
---|
96 |
|
---|
97 | @return The option number of the found boot option.
|
---|
98 |
|
---|
99 | **/
|
---|
100 | UINTN
|
---|
101 | BmFindBootOptionInVariable (
|
---|
102 | IN EFI_BOOT_MANAGER_LOAD_OPTION *OptionToFind
|
---|
103 | )
|
---|
104 | {
|
---|
105 | EFI_STATUS Status;
|
---|
106 | EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
|
---|
107 | UINTN OptionNumber;
|
---|
108 | CHAR16 OptionName[BM_OPTION_NAME_LEN];
|
---|
109 | EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
|
---|
110 | UINTN BootOptionCount;
|
---|
111 | UINTN Index;
|
---|
112 |
|
---|
113 | OptionNumber = LoadOptionNumberUnassigned;
|
---|
114 |
|
---|
115 | //
|
---|
116 | // Try to match the variable exactly if the option number is assigned
|
---|
117 | //
|
---|
118 | if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {
|
---|
119 | UnicodeSPrint (
|
---|
120 | OptionName,
|
---|
121 | sizeof (OptionName),
|
---|
122 | L"%s%04x",
|
---|
123 | mBmLoadOptionName[OptionToFind->OptionType],
|
---|
124 | OptionToFind->OptionNumber
|
---|
125 | );
|
---|
126 | Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
|
---|
127 |
|
---|
128 | if (!EFI_ERROR (Status)) {
|
---|
129 | ASSERT (OptionToFind->OptionNumber == BootOption.OptionNumber);
|
---|
130 | if ((OptionToFind->Attributes == BootOption.Attributes) &&
|
---|
131 | (StrCmp (OptionToFind->Description, BootOption.Description) == 0) &&
|
---|
132 | (CompareMem (OptionToFind->FilePath, BootOption.FilePath, GetDevicePathSize (OptionToFind->FilePath)) == 0) &&
|
---|
133 | (OptionToFind->OptionalDataSize == BootOption.OptionalDataSize) &&
|
---|
134 | (CompareMem (OptionToFind->OptionalData, BootOption.OptionalData, OptionToFind->OptionalDataSize) == 0)
|
---|
135 | )
|
---|
136 | {
|
---|
137 | OptionNumber = OptionToFind->OptionNumber;
|
---|
138 | }
|
---|
139 |
|
---|
140 | EfiBootManagerFreeLoadOption (&BootOption);
|
---|
141 | }
|
---|
142 | }
|
---|
143 |
|
---|
144 | //
|
---|
145 | // The option number assigned is either incorrect or unassigned.
|
---|
146 | //
|
---|
147 | if (OptionNumber == LoadOptionNumberUnassigned) {
|
---|
148 | BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
|
---|
149 |
|
---|
150 | Index = EfiBootManagerFindLoadOption (OptionToFind, BootOptions, BootOptionCount);
|
---|
151 | if (Index != -1) {
|
---|
152 | OptionNumber = BootOptions[Index].OptionNumber;
|
---|
153 | }
|
---|
154 |
|
---|
155 | EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
|
---|
156 | }
|
---|
157 |
|
---|
158 | return OptionNumber;
|
---|
159 | }
|
---|
160 |
|
---|
161 | /**
|
---|
162 | Return the correct FV file path.
|
---|
163 | FV address may change across reboot. This routine promises the FV file device path is right.
|
---|
164 |
|
---|
165 | @param FilePath The Memory Mapped Device Path to get the file buffer.
|
---|
166 |
|
---|
167 | @return The updated FV Device Path pointint to the file.
|
---|
168 | **/
|
---|
169 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
170 | BmAdjustFvFilePath (
|
---|
171 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath
|
---|
172 | )
|
---|
173 | {
|
---|
174 | EFI_STATUS Status;
|
---|
175 | UINTN Index;
|
---|
176 | EFI_DEVICE_PATH_PROTOCOL *FvFileNode;
|
---|
177 | EFI_HANDLE FvHandle;
|
---|
178 | EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
|
---|
179 | UINTN FvHandleCount;
|
---|
180 | EFI_HANDLE *FvHandles;
|
---|
181 | EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
|
---|
182 | EFI_DEVICE_PATH_PROTOCOL *FullPath;
|
---|
183 |
|
---|
184 | //
|
---|
185 | // Get the file buffer by using the exactly FilePath.
|
---|
186 | //
|
---|
187 | FvFileNode = FilePath;
|
---|
188 | Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
|
---|
189 | if (!EFI_ERROR (Status)) {
|
---|
190 | return DuplicateDevicePath (FilePath);
|
---|
191 | }
|
---|
192 |
|
---|
193 | //
|
---|
194 | // Only wide match other FVs if it's a memory mapped FV file path.
|
---|
195 | //
|
---|
196 | if ((DevicePathType (FilePath) != HARDWARE_DEVICE_PATH) || (DevicePathSubType (FilePath) != HW_MEMMAP_DP)) {
|
---|
197 | return NULL;
|
---|
198 | }
|
---|
199 |
|
---|
200 | FvFileNode = NextDevicePathNode (FilePath);
|
---|
201 |
|
---|
202 | //
|
---|
203 | // Firstly find the FV file in current FV
|
---|
204 | //
|
---|
205 | gBS->HandleProtocol (
|
---|
206 | gImageHandle,
|
---|
207 | &gEfiLoadedImageProtocolGuid,
|
---|
208 | (VOID **)&LoadedImage
|
---|
209 | );
|
---|
210 | NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
|
---|
211 | FullPath = BmAdjustFvFilePath (NewDevicePath);
|
---|
212 | FreePool (NewDevicePath);
|
---|
213 | if (FullPath != NULL) {
|
---|
214 | return FullPath;
|
---|
215 | }
|
---|
216 |
|
---|
217 | //
|
---|
218 | // Secondly find the FV file in all other FVs
|
---|
219 | //
|
---|
220 | gBS->LocateHandleBuffer (
|
---|
221 | ByProtocol,
|
---|
222 | &gEfiFirmwareVolume2ProtocolGuid,
|
---|
223 | NULL,
|
---|
224 | &FvHandleCount,
|
---|
225 | &FvHandles
|
---|
226 | );
|
---|
227 | for (Index = 0; Index < FvHandleCount; Index++) {
|
---|
228 | if (FvHandles[Index] == LoadedImage->DeviceHandle) {
|
---|
229 | //
|
---|
230 | // Skip current FV, it was handed in first step.
|
---|
231 | //
|
---|
232 | continue;
|
---|
233 | }
|
---|
234 |
|
---|
235 | NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
|
---|
236 | FullPath = BmAdjustFvFilePath (NewDevicePath);
|
---|
237 | FreePool (NewDevicePath);
|
---|
238 | if (FullPath != NULL) {
|
---|
239 | break;
|
---|
240 | }
|
---|
241 | }
|
---|
242 |
|
---|
243 | if (FvHandles != NULL) {
|
---|
244 | FreePool (FvHandles);
|
---|
245 | }
|
---|
246 |
|
---|
247 | return FullPath;
|
---|
248 | }
|
---|
249 |
|
---|
250 | /**
|
---|
251 | Check if it's a Device Path pointing to FV file.
|
---|
252 |
|
---|
253 | The function doesn't garentee the device path points to existing FV file.
|
---|
254 |
|
---|
255 | @param DevicePath Input device path.
|
---|
256 |
|
---|
257 | @retval TRUE The device path is a FV File Device Path.
|
---|
258 | @retval FALSE The device path is NOT a FV File Device Path.
|
---|
259 | **/
|
---|
260 | BOOLEAN
|
---|
261 | BmIsFvFilePath (
|
---|
262 | IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
---|
263 | )
|
---|
264 | {
|
---|
265 | EFI_STATUS Status;
|
---|
266 | EFI_HANDLE Handle;
|
---|
267 | EFI_DEVICE_PATH_PROTOCOL *Node;
|
---|
268 |
|
---|
269 | Node = DevicePath;
|
---|
270 | Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &Handle);
|
---|
271 | if (!EFI_ERROR (Status)) {
|
---|
272 | return TRUE;
|
---|
273 | }
|
---|
274 |
|
---|
275 | if ((DevicePathType (DevicePath) == HARDWARE_DEVICE_PATH) && (DevicePathSubType (DevicePath) == HW_MEMMAP_DP)) {
|
---|
276 | DevicePath = NextDevicePathNode (DevicePath);
|
---|
277 | if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MEDIA_PIWG_FW_FILE_DP)) {
|
---|
278 | return IsDevicePathEnd (NextDevicePathNode (DevicePath));
|
---|
279 | }
|
---|
280 | }
|
---|
281 |
|
---|
282 | return FALSE;
|
---|
283 | }
|
---|
284 |
|
---|
285 | /**
|
---|
286 | Check whether a USB device match the specified USB Class device path. This
|
---|
287 | function follows "Load Option Processing" behavior in UEFI specification.
|
---|
288 |
|
---|
289 | @param UsbIo USB I/O protocol associated with the USB device.
|
---|
290 | @param UsbClass The USB Class device path to match.
|
---|
291 |
|
---|
292 | @retval TRUE The USB device match the USB Class device path.
|
---|
293 | @retval FALSE The USB device does not match the USB Class device path.
|
---|
294 |
|
---|
295 | **/
|
---|
296 | BOOLEAN
|
---|
297 | BmMatchUsbClass (
|
---|
298 | IN EFI_USB_IO_PROTOCOL *UsbIo,
|
---|
299 | IN USB_CLASS_DEVICE_PATH *UsbClass
|
---|
300 | )
|
---|
301 | {
|
---|
302 | EFI_STATUS Status;
|
---|
303 | EFI_USB_DEVICE_DESCRIPTOR DevDesc;
|
---|
304 | EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
|
---|
305 | UINT8 DeviceClass;
|
---|
306 | UINT8 DeviceSubClass;
|
---|
307 | UINT8 DeviceProtocol;
|
---|
308 |
|
---|
309 | if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
|
---|
310 | (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP))
|
---|
311 | {
|
---|
312 | return FALSE;
|
---|
313 | }
|
---|
314 |
|
---|
315 | //
|
---|
316 | // Check Vendor Id and Product Id.
|
---|
317 | //
|
---|
318 | Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
|
---|
319 | if (EFI_ERROR (Status)) {
|
---|
320 | return FALSE;
|
---|
321 | }
|
---|
322 |
|
---|
323 | if ((UsbClass->VendorId != 0xffff) &&
|
---|
324 | (UsbClass->VendorId != DevDesc.IdVendor))
|
---|
325 | {
|
---|
326 | return FALSE;
|
---|
327 | }
|
---|
328 |
|
---|
329 | if ((UsbClass->ProductId != 0xffff) &&
|
---|
330 | (UsbClass->ProductId != DevDesc.IdProduct))
|
---|
331 | {
|
---|
332 | return FALSE;
|
---|
333 | }
|
---|
334 |
|
---|
335 | DeviceClass = DevDesc.DeviceClass;
|
---|
336 | DeviceSubClass = DevDesc.DeviceSubClass;
|
---|
337 | DeviceProtocol = DevDesc.DeviceProtocol;
|
---|
338 | if (DeviceClass == 0) {
|
---|
339 | //
|
---|
340 | // If Class in Device Descriptor is set to 0, use the Class, SubClass and
|
---|
341 | // Protocol in Interface Descriptor instead.
|
---|
342 | //
|
---|
343 | Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
|
---|
344 | if (EFI_ERROR (Status)) {
|
---|
345 | return FALSE;
|
---|
346 | }
|
---|
347 |
|
---|
348 | DeviceClass = IfDesc.InterfaceClass;
|
---|
349 | DeviceSubClass = IfDesc.InterfaceSubClass;
|
---|
350 | DeviceProtocol = IfDesc.InterfaceProtocol;
|
---|
351 | }
|
---|
352 |
|
---|
353 | //
|
---|
354 | // Check Class, SubClass and Protocol.
|
---|
355 | //
|
---|
356 | if ((UsbClass->DeviceClass != 0xff) &&
|
---|
357 | (UsbClass->DeviceClass != DeviceClass))
|
---|
358 | {
|
---|
359 | return FALSE;
|
---|
360 | }
|
---|
361 |
|
---|
362 | if ((UsbClass->DeviceSubClass != 0xff) &&
|
---|
363 | (UsbClass->DeviceSubClass != DeviceSubClass))
|
---|
364 | {
|
---|
365 | return FALSE;
|
---|
366 | }
|
---|
367 |
|
---|
368 | if ((UsbClass->DeviceProtocol != 0xff) &&
|
---|
369 | (UsbClass->DeviceProtocol != DeviceProtocol))
|
---|
370 | {
|
---|
371 | return FALSE;
|
---|
372 | }
|
---|
373 |
|
---|
374 | return TRUE;
|
---|
375 | }
|
---|
376 |
|
---|
377 | /**
|
---|
378 | Check whether a USB device match the specified USB WWID device path. This
|
---|
379 | function follows "Load Option Processing" behavior in UEFI specification.
|
---|
380 |
|
---|
381 | @param UsbIo USB I/O protocol associated with the USB device.
|
---|
382 | @param UsbWwid The USB WWID device path to match.
|
---|
383 |
|
---|
384 | @retval TRUE The USB device match the USB WWID device path.
|
---|
385 | @retval FALSE The USB device does not match the USB WWID device path.
|
---|
386 |
|
---|
387 | **/
|
---|
388 | BOOLEAN
|
---|
389 | BmMatchUsbWwid (
|
---|
390 | IN EFI_USB_IO_PROTOCOL *UsbIo,
|
---|
391 | IN USB_WWID_DEVICE_PATH *UsbWwid
|
---|
392 | )
|
---|
393 | {
|
---|
394 | EFI_STATUS Status;
|
---|
395 | EFI_USB_DEVICE_DESCRIPTOR DevDesc;
|
---|
396 | EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
|
---|
397 | UINT16 *LangIdTable;
|
---|
398 | UINT16 TableSize;
|
---|
399 | UINT16 Index;
|
---|
400 | CHAR16 *CompareStr;
|
---|
401 | UINTN CompareLen;
|
---|
402 | CHAR16 *SerialNumberStr;
|
---|
403 | UINTN Length;
|
---|
404 |
|
---|
405 | if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
|
---|
406 | (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP))
|
---|
407 | {
|
---|
408 | return FALSE;
|
---|
409 | }
|
---|
410 |
|
---|
411 | //
|
---|
412 | // Check Vendor Id and Product Id.
|
---|
413 | //
|
---|
414 | Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
|
---|
415 | if (EFI_ERROR (Status)) {
|
---|
416 | return FALSE;
|
---|
417 | }
|
---|
418 |
|
---|
419 | if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
|
---|
420 | (DevDesc.IdProduct != UsbWwid->ProductId))
|
---|
421 | {
|
---|
422 | return FALSE;
|
---|
423 | }
|
---|
424 |
|
---|
425 | //
|
---|
426 | // Check Interface Number.
|
---|
427 | //
|
---|
428 | Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
|
---|
429 | if (EFI_ERROR (Status)) {
|
---|
430 | return FALSE;
|
---|
431 | }
|
---|
432 |
|
---|
433 | if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
|
---|
434 | return FALSE;
|
---|
435 | }
|
---|
436 |
|
---|
437 | //
|
---|
438 | // Check Serial Number.
|
---|
439 | //
|
---|
440 | if (DevDesc.StrSerialNumber == 0) {
|
---|
441 | return FALSE;
|
---|
442 | }
|
---|
443 |
|
---|
444 | //
|
---|
445 | // Get all supported languages.
|
---|
446 | //
|
---|
447 | TableSize = 0;
|
---|
448 | LangIdTable = NULL;
|
---|
449 | Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
|
---|
450 | if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
|
---|
451 | return FALSE;
|
---|
452 | }
|
---|
453 |
|
---|
454 | //
|
---|
455 | // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
|
---|
456 | //
|
---|
457 | CompareStr = (CHAR16 *)(UINTN)(UsbWwid + 1);
|
---|
458 | CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
|
---|
459 | if (CompareStr[CompareLen - 1] == L'\0') {
|
---|
460 | CompareLen--;
|
---|
461 | }
|
---|
462 |
|
---|
463 | //
|
---|
464 | // Compare serial number in each supported language.
|
---|
465 | //
|
---|
466 | for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
|
---|
467 | SerialNumberStr = NULL;
|
---|
468 | Status = UsbIo->UsbGetStringDescriptor (
|
---|
469 | UsbIo,
|
---|
470 | LangIdTable[Index],
|
---|
471 | DevDesc.StrSerialNumber,
|
---|
472 | &SerialNumberStr
|
---|
473 | );
|
---|
474 | if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
|
---|
475 | continue;
|
---|
476 | }
|
---|
477 |
|
---|
478 | Length = StrLen (SerialNumberStr);
|
---|
479 | if ((Length >= CompareLen) &&
|
---|
480 | (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0))
|
---|
481 | {
|
---|
482 | FreePool (SerialNumberStr);
|
---|
483 | return TRUE;
|
---|
484 | }
|
---|
485 |
|
---|
486 | FreePool (SerialNumberStr);
|
---|
487 | }
|
---|
488 |
|
---|
489 | return FALSE;
|
---|
490 | }
|
---|
491 |
|
---|
492 | /**
|
---|
493 | Find a USB device which match the specified short-form device path start with
|
---|
494 | USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
|
---|
495 | will search in all USB devices of the platform. If ParentDevicePath is not NULL,
|
---|
496 | this function will only search in its child devices.
|
---|
497 |
|
---|
498 | @param DevicePath The device path that contains USB Class or USB WWID device path.
|
---|
499 | @param ParentDevicePathSize The length of the device path before the USB Class or
|
---|
500 | USB WWID device path.
|
---|
501 | @param UsbIoHandleCount A pointer to the count of the returned USB IO handles.
|
---|
502 |
|
---|
503 | @retval NULL The matched USB IO handles cannot be found.
|
---|
504 | @retval other The matched USB IO handles.
|
---|
505 |
|
---|
506 | **/
|
---|
507 | EFI_HANDLE *
|
---|
508 | BmFindUsbDevice (
|
---|
509 | IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
---|
510 | IN UINTN ParentDevicePathSize,
|
---|
511 | OUT UINTN *UsbIoHandleCount
|
---|
512 | )
|
---|
513 | {
|
---|
514 | EFI_STATUS Status;
|
---|
515 | EFI_HANDLE *UsbIoHandles;
|
---|
516 | EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
|
---|
517 | EFI_USB_IO_PROTOCOL *UsbIo;
|
---|
518 | UINTN Index;
|
---|
519 | BOOLEAN Matched;
|
---|
520 |
|
---|
521 | ASSERT (UsbIoHandleCount != NULL);
|
---|
522 |
|
---|
523 | //
|
---|
524 | // Get all UsbIo Handles.
|
---|
525 | //
|
---|
526 | Status = gBS->LocateHandleBuffer (
|
---|
527 | ByProtocol,
|
---|
528 | &gEfiUsbIoProtocolGuid,
|
---|
529 | NULL,
|
---|
530 | UsbIoHandleCount,
|
---|
531 | &UsbIoHandles
|
---|
532 | );
|
---|
533 | if (EFI_ERROR (Status)) {
|
---|
534 | *UsbIoHandleCount = 0;
|
---|
535 | UsbIoHandles = NULL;
|
---|
536 | }
|
---|
537 |
|
---|
538 | for (Index = 0; Index < *UsbIoHandleCount; ) {
|
---|
539 | //
|
---|
540 | // Get the Usb IO interface.
|
---|
541 | //
|
---|
542 | Status = gBS->HandleProtocol (
|
---|
543 | UsbIoHandles[Index],
|
---|
544 | &gEfiUsbIoProtocolGuid,
|
---|
545 | (VOID **)&UsbIo
|
---|
546 | );
|
---|
547 | UsbIoDevicePath = DevicePathFromHandle (UsbIoHandles[Index]);
|
---|
548 | Matched = FALSE;
|
---|
549 | if (!EFI_ERROR (Status) && (UsbIoDevicePath != NULL)) {
|
---|
550 | //
|
---|
551 | // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
|
---|
552 | //
|
---|
553 | if (CompareMem (UsbIoDevicePath, DevicePath, ParentDevicePathSize) == 0) {
|
---|
554 | if (BmMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *)((UINTN)DevicePath + ParentDevicePathSize)) ||
|
---|
555 | BmMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *)((UINTN)DevicePath + ParentDevicePathSize)))
|
---|
556 | {
|
---|
557 | Matched = TRUE;
|
---|
558 | }
|
---|
559 | }
|
---|
560 | }
|
---|
561 |
|
---|
562 | if (!Matched) {
|
---|
563 | (*UsbIoHandleCount)--;
|
---|
564 | CopyMem (&UsbIoHandles[Index], &UsbIoHandles[Index + 1], (*UsbIoHandleCount - Index) * sizeof (EFI_HANDLE));
|
---|
565 | } else {
|
---|
566 | Index++;
|
---|
567 | }
|
---|
568 | }
|
---|
569 |
|
---|
570 | return UsbIoHandles;
|
---|
571 | }
|
---|
572 |
|
---|
573 | /**
|
---|
574 | Expand USB Class or USB WWID device path node to be full device path of a USB
|
---|
575 | device in platform.
|
---|
576 |
|
---|
577 | This function support following 4 cases:
|
---|
578 | 1) Boot Option device path starts with a USB Class or USB WWID device path,
|
---|
579 | and there is no Media FilePath device path in the end.
|
---|
580 | In this case, it will follow Removable Media Boot Behavior.
|
---|
581 | 2) Boot Option device path starts with a USB Class or USB WWID device path,
|
---|
582 | and ended with Media FilePath device path.
|
---|
583 | 3) Boot Option device path starts with a full device path to a USB Host Controller,
|
---|
584 | contains a USB Class or USB WWID device path node, while not ended with Media
|
---|
585 | FilePath device path. In this case, it will follow Removable Media Boot Behavior.
|
---|
586 | 4) Boot Option device path starts with a full device path to a USB Host Controller,
|
---|
587 | contains a USB Class or USB WWID device path node, and ended with Media
|
---|
588 | FilePath device path.
|
---|
589 |
|
---|
590 | @param FilePath The device path pointing to a load option.
|
---|
591 | It could be a short-form device path.
|
---|
592 | @param FullPath The full path returned by the routine in last call.
|
---|
593 | Set to NULL in first call.
|
---|
594 | @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
|
---|
595 |
|
---|
596 | @return The next possible full path pointing to the load option.
|
---|
597 | Caller is responsible to free the memory.
|
---|
598 | **/
|
---|
599 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
600 | BmExpandUsbDevicePath (
|
---|
601 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
---|
602 | IN EFI_DEVICE_PATH_PROTOCOL *FullPath,
|
---|
603 | IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
|
---|
604 | )
|
---|
605 | {
|
---|
606 | UINTN ParentDevicePathSize;
|
---|
607 | EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
|
---|
608 | EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
|
---|
609 | EFI_HANDLE *Handles;
|
---|
610 | UINTN HandleCount;
|
---|
611 | UINTN Index;
|
---|
612 | BOOLEAN GetNext;
|
---|
613 |
|
---|
614 | NextFullPath = NULL;
|
---|
615 | GetNext = (BOOLEAN)(FullPath == NULL);
|
---|
616 | ParentDevicePathSize = (UINTN)ShortformNode - (UINTN)FilePath;
|
---|
617 | RemainingDevicePath = NextDevicePathNode (ShortformNode);
|
---|
618 | Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
|
---|
619 |
|
---|
620 | for (Index = 0; Index < HandleCount; Index++) {
|
---|
621 | FilePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
|
---|
622 | if (FilePath == NULL) {
|
---|
623 | //
|
---|
624 | // Out of memory.
|
---|
625 | //
|
---|
626 | continue;
|
---|
627 | }
|
---|
628 |
|
---|
629 | NextFullPath = BmGetNextLoadOptionDevicePath (FilePath, NULL);
|
---|
630 | FreePool (FilePath);
|
---|
631 | if (NextFullPath == NULL) {
|
---|
632 | //
|
---|
633 | // No BlockIo or SimpleFileSystem under FilePath.
|
---|
634 | //
|
---|
635 | continue;
|
---|
636 | }
|
---|
637 |
|
---|
638 | if (GetNext) {
|
---|
639 | break;
|
---|
640 | } else {
|
---|
641 | GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
|
---|
642 | FreePool (NextFullPath);
|
---|
643 | NextFullPath = NULL;
|
---|
644 | }
|
---|
645 | }
|
---|
646 |
|
---|
647 | if (Handles != NULL) {
|
---|
648 | FreePool (Handles);
|
---|
649 | }
|
---|
650 |
|
---|
651 | return NextFullPath;
|
---|
652 | }
|
---|
653 |
|
---|
654 | /**
|
---|
655 | Expand File-path device path node to be full device path in platform.
|
---|
656 |
|
---|
657 | @param FilePath The device path pointing to a load option.
|
---|
658 | It could be a short-form device path.
|
---|
659 | @param FullPath The full path returned by the routine in last call.
|
---|
660 | Set to NULL in first call.
|
---|
661 |
|
---|
662 | @return The next possible full path pointing to the load option.
|
---|
663 | Caller is responsible to free the memory.
|
---|
664 | **/
|
---|
665 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
666 | BmExpandFileDevicePath (
|
---|
667 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
---|
668 | IN EFI_DEVICE_PATH_PROTOCOL *FullPath
|
---|
669 | )
|
---|
670 | {
|
---|
671 | EFI_STATUS Status;
|
---|
672 | UINTN Index;
|
---|
673 | UINTN HandleCount;
|
---|
674 | EFI_HANDLE *Handles;
|
---|
675 | EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
---|
676 | UINTN MediaType;
|
---|
677 | EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
|
---|
678 | BOOLEAN GetNext;
|
---|
679 |
|
---|
680 | EfiBootManagerConnectAll ();
|
---|
681 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);
|
---|
682 | if (EFI_ERROR (Status)) {
|
---|
683 | HandleCount = 0;
|
---|
684 | Handles = NULL;
|
---|
685 | }
|
---|
686 |
|
---|
687 | GetNext = (BOOLEAN)(FullPath == NULL);
|
---|
688 | NextFullPath = NULL;
|
---|
689 | //
|
---|
690 | // Enumerate all removable media devices followed by all fixed media devices,
|
---|
691 | // followed by media devices which don't layer on block io.
|
---|
692 | //
|
---|
693 | for (MediaType = 0; MediaType < 3; MediaType++) {
|
---|
694 | for (Index = 0; Index < HandleCount; Index++) {
|
---|
695 | Status = gBS->HandleProtocol (Handles[Index], &gEfiBlockIoProtocolGuid, (VOID *)&BlockIo);
|
---|
696 | if (EFI_ERROR (Status)) {
|
---|
697 | BlockIo = NULL;
|
---|
698 | }
|
---|
699 |
|
---|
700 | if (((MediaType == 0) && (BlockIo != NULL) && BlockIo->Media->RemovableMedia) ||
|
---|
701 | ((MediaType == 1) && (BlockIo != NULL) && !BlockIo->Media->RemovableMedia) ||
|
---|
702 | ((MediaType == 2) && (BlockIo == NULL))
|
---|
703 | )
|
---|
704 | {
|
---|
705 | NextFullPath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);
|
---|
706 | if (GetNext) {
|
---|
707 | break;
|
---|
708 | } else {
|
---|
709 | GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
|
---|
710 | FreePool (NextFullPath);
|
---|
711 | NextFullPath = NULL;
|
---|
712 | }
|
---|
713 | }
|
---|
714 | }
|
---|
715 |
|
---|
716 | if (NextFullPath != NULL) {
|
---|
717 | break;
|
---|
718 | }
|
---|
719 | }
|
---|
720 |
|
---|
721 | if (Handles != NULL) {
|
---|
722 | FreePool (Handles);
|
---|
723 | }
|
---|
724 |
|
---|
725 | return NextFullPath;
|
---|
726 | }
|
---|
727 |
|
---|
728 | /**
|
---|
729 | Expand URI device path node to be full device path in platform.
|
---|
730 |
|
---|
731 | @param FilePath The device path pointing to a load option.
|
---|
732 | It could be a short-form device path.
|
---|
733 | @param FullPath The full path returned by the routine in last call.
|
---|
734 | Set to NULL in first call.
|
---|
735 |
|
---|
736 | @return The next possible full path pointing to the load option.
|
---|
737 | Caller is responsible to free the memory.
|
---|
738 | **/
|
---|
739 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
740 | BmExpandUriDevicePath (
|
---|
741 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
---|
742 | IN EFI_DEVICE_PATH_PROTOCOL *FullPath
|
---|
743 | )
|
---|
744 | {
|
---|
745 | EFI_STATUS Status;
|
---|
746 | UINTN Index;
|
---|
747 | UINTN HandleCount;
|
---|
748 | EFI_HANDLE *Handles;
|
---|
749 | EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
|
---|
750 | EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
|
---|
751 | BOOLEAN GetNext;
|
---|
752 |
|
---|
753 | EfiBootManagerConnectAll ();
|
---|
754 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiLoadFileProtocolGuid, NULL, &HandleCount, &Handles);
|
---|
755 | if (EFI_ERROR (Status)) {
|
---|
756 | HandleCount = 0;
|
---|
757 | Handles = NULL;
|
---|
758 | }
|
---|
759 |
|
---|
760 | NextFullPath = NULL;
|
---|
761 | GetNext = (BOOLEAN)(FullPath == NULL);
|
---|
762 | for (Index = 0; Index < HandleCount; Index++) {
|
---|
763 | NextFullPath = BmExpandLoadFile (Handles[Index], FilePath);
|
---|
764 |
|
---|
765 | if (NextFullPath == NULL) {
|
---|
766 | continue;
|
---|
767 | }
|
---|
768 |
|
---|
769 | if (GetNext) {
|
---|
770 | break;
|
---|
771 | } else {
|
---|
772 | GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
|
---|
773 | //
|
---|
774 | // Free the resource occupied by the RAM disk.
|
---|
775 | //
|
---|
776 | RamDiskDevicePath = BmGetRamDiskDevicePath (NextFullPath);
|
---|
777 | if (RamDiskDevicePath != NULL) {
|
---|
778 | BmDestroyRamDisk (RamDiskDevicePath);
|
---|
779 | FreePool (RamDiskDevicePath);
|
---|
780 | }
|
---|
781 |
|
---|
782 | FreePool (NextFullPath);
|
---|
783 | NextFullPath = NULL;
|
---|
784 | }
|
---|
785 | }
|
---|
786 |
|
---|
787 | if (Handles != NULL) {
|
---|
788 | FreePool (Handles);
|
---|
789 | }
|
---|
790 |
|
---|
791 | return NextFullPath;
|
---|
792 | }
|
---|
793 |
|
---|
794 | /**
|
---|
795 | Save the partition DevicePath to the CachedDevicePath as the first instance.
|
---|
796 |
|
---|
797 | @param CachedDevicePath The device path cache.
|
---|
798 | @param DevicePath The partition device path to be cached.
|
---|
799 | **/
|
---|
800 | VOID
|
---|
801 | BmCachePartitionDevicePath (
|
---|
802 | IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
|
---|
803 | IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
---|
804 | )
|
---|
805 | {
|
---|
806 | EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
---|
807 | UINTN Count;
|
---|
808 |
|
---|
809 | if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
|
---|
810 | TempDevicePath = *CachedDevicePath;
|
---|
811 | *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
|
---|
812 | FreePool (TempDevicePath);
|
---|
813 | }
|
---|
814 |
|
---|
815 | if (*CachedDevicePath == NULL) {
|
---|
816 | *CachedDevicePath = DuplicateDevicePath (DevicePath);
|
---|
817 | return;
|
---|
818 | }
|
---|
819 |
|
---|
820 | TempDevicePath = *CachedDevicePath;
|
---|
821 | *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
|
---|
822 | if (TempDevicePath != NULL) {
|
---|
823 | FreePool (TempDevicePath);
|
---|
824 | }
|
---|
825 |
|
---|
826 | //
|
---|
827 | // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
|
---|
828 | // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
|
---|
829 | //
|
---|
830 | Count = 0;
|
---|
831 | TempDevicePath = *CachedDevicePath;
|
---|
832 | while (!IsDevicePathEnd (TempDevicePath)) {
|
---|
833 | TempDevicePath = NextDevicePathNode (TempDevicePath);
|
---|
834 | //
|
---|
835 | // Parse one instance
|
---|
836 | //
|
---|
837 | while (!IsDevicePathEndType (TempDevicePath)) {
|
---|
838 | TempDevicePath = NextDevicePathNode (TempDevicePath);
|
---|
839 | }
|
---|
840 |
|
---|
841 | Count++;
|
---|
842 | //
|
---|
843 | // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
|
---|
844 | //
|
---|
845 | if (Count == 12) {
|
---|
846 | SetDevicePathEndNode (TempDevicePath);
|
---|
847 | break;
|
---|
848 | }
|
---|
849 | }
|
---|
850 | }
|
---|
851 |
|
---|
852 | /**
|
---|
853 | Expand a device path that starts with a hard drive media device path node to be a
|
---|
854 | full device path that includes the full hardware path to the device. We need
|
---|
855 | to do this so it can be booted. As an optimization the front match (the part point
|
---|
856 | to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
|
---|
857 | so a connect all is not required on every boot. All successful history device path
|
---|
858 | which point to partition node (the front part) will be saved.
|
---|
859 |
|
---|
860 | @param FilePath The device path pointing to a load option.
|
---|
861 | It could be a short-form device path.
|
---|
862 |
|
---|
863 | @return The full device path pointing to the load option.
|
---|
864 | **/
|
---|
865 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
866 | BmExpandPartitionDevicePath (
|
---|
867 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath
|
---|
868 | )
|
---|
869 | {
|
---|
870 | EFI_STATUS Status;
|
---|
871 | UINTN BlockIoHandleCount;
|
---|
872 | EFI_HANDLE *BlockIoBuffer;
|
---|
873 | EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
|
---|
874 | UINTN Index;
|
---|
875 | EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
|
---|
876 | EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
|
---|
877 | EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
---|
878 | EFI_DEVICE_PATH_PROTOCOL *FullPath;
|
---|
879 | UINTN CachedDevicePathSize;
|
---|
880 | BOOLEAN NeedAdjust;
|
---|
881 | EFI_DEVICE_PATH_PROTOCOL *Instance;
|
---|
882 | UINTN Size;
|
---|
883 | BOOLEAN MatchFound;
|
---|
884 | BOOLEAN ConnectAllAttempted;
|
---|
885 |
|
---|
886 | //
|
---|
887 | // Check if there is prestore 'HDDP' variable.
|
---|
888 | // If exist, search the front path which point to partition node in the variable instants.
|
---|
889 | // If fail to find or 'HDDP' not exist, reconnect all and search in all system
|
---|
890 | //
|
---|
891 | GetVariable2 (L"HDDP", &mBmHardDriveBootVariableGuid, (VOID **)&CachedDevicePath, &CachedDevicePathSize);
|
---|
892 |
|
---|
893 | //
|
---|
894 | // Delete the invalid 'HDDP' variable.
|
---|
895 | //
|
---|
896 | if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
|
---|
897 | FreePool (CachedDevicePath);
|
---|
898 | CachedDevicePath = NULL;
|
---|
899 | Status = gRT->SetVariable (
|
---|
900 | L"HDDP",
|
---|
901 | &mBmHardDriveBootVariableGuid,
|
---|
902 | 0,
|
---|
903 | 0,
|
---|
904 | NULL
|
---|
905 | );
|
---|
906 | ASSERT_EFI_ERROR (Status);
|
---|
907 | }
|
---|
908 |
|
---|
909 | FullPath = NULL;
|
---|
910 | if (CachedDevicePath != NULL) {
|
---|
911 | TempNewDevicePath = CachedDevicePath;
|
---|
912 | NeedAdjust = FALSE;
|
---|
913 | do {
|
---|
914 | //
|
---|
915 | // Check every instance of the variable
|
---|
916 | // First, check whether the instance contain the partition node, which is needed for distinguishing multi
|
---|
917 | // partial partition boot option. Second, check whether the instance could be connected.
|
---|
918 | //
|
---|
919 | Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
|
---|
920 | if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *)FilePath)) {
|
---|
921 | //
|
---|
922 | // Connect the device path instance, the device path point to hard drive media device path node
|
---|
923 | // e.g. ACPI() /PCI()/ATA()/Partition()
|
---|
924 | //
|
---|
925 | Status = EfiBootManagerConnectDevicePath (Instance, NULL);
|
---|
926 | if (!EFI_ERROR (Status)) {
|
---|
927 | TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
|
---|
928 | //
|
---|
929 | // TempDevicePath = ACPI()/PCI()/ATA()/Partition()
|
---|
930 | // or = ACPI()/PCI()/ATA()/Partition()/.../A.EFI
|
---|
931 | //
|
---|
932 | // When TempDevicePath = ACPI()/PCI()/ATA()/Partition(),
|
---|
933 | // it may expand to two potienal full paths (nested partition, rarely happen):
|
---|
934 | // 1. ACPI()/PCI()/ATA()/Partition()/Partition(A1)/EFI/BootX64.EFI
|
---|
935 | // 2. ACPI()/PCI()/ATA()/Partition()/Partition(A2)/EFI/BootX64.EFI
|
---|
936 | // For simplicity, only #1 is returned.
|
---|
937 | //
|
---|
938 | FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);
|
---|
939 | FreePool (TempDevicePath);
|
---|
940 |
|
---|
941 | if (FullPath != NULL) {
|
---|
942 | //
|
---|
943 | // Adjust the 'HDDP' instances sequence if the matched one is not first one.
|
---|
944 | //
|
---|
945 | if (NeedAdjust) {
|
---|
946 | BmCachePartitionDevicePath (&CachedDevicePath, Instance);
|
---|
947 | //
|
---|
948 | // Save the matching Device Path so we don't need to do a connect all next time
|
---|
949 | // Failing to save only impacts performance next time expanding the short-form device path
|
---|
950 | //
|
---|
951 | Status = gRT->SetVariable (
|
---|
952 | L"HDDP",
|
---|
953 | &mBmHardDriveBootVariableGuid,
|
---|
954 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
---|
955 | GetDevicePathSize (CachedDevicePath),
|
---|
956 | CachedDevicePath
|
---|
957 | );
|
---|
958 | }
|
---|
959 |
|
---|
960 | FreePool (Instance);
|
---|
961 | FreePool (CachedDevicePath);
|
---|
962 | return FullPath;
|
---|
963 | }
|
---|
964 | }
|
---|
965 | }
|
---|
966 |
|
---|
967 | //
|
---|
968 | // Come here means the first instance is not matched
|
---|
969 | //
|
---|
970 | NeedAdjust = TRUE;
|
---|
971 | FreePool (Instance);
|
---|
972 | } while (TempNewDevicePath != NULL);
|
---|
973 | }
|
---|
974 |
|
---|
975 | //
|
---|
976 | // If we get here we fail to find or 'HDDP' not exist, and now we need
|
---|
977 | // to search all devices in the system for a matched partition
|
---|
978 | //
|
---|
979 | BlockIoBuffer = NULL;
|
---|
980 | MatchFound = FALSE;
|
---|
981 | ConnectAllAttempted = FALSE;
|
---|
982 | do {
|
---|
983 | if (BlockIoBuffer != NULL) {
|
---|
984 | FreePool (BlockIoBuffer);
|
---|
985 | }
|
---|
986 |
|
---|
987 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
|
---|
988 | if (EFI_ERROR (Status)) {
|
---|
989 | BlockIoHandleCount = 0;
|
---|
990 | BlockIoBuffer = NULL;
|
---|
991 | }
|
---|
992 |
|
---|
993 | //
|
---|
994 | // Loop through all the device handles that support the BLOCK_IO Protocol
|
---|
995 | //
|
---|
996 | for (Index = 0; Index < BlockIoHandleCount; Index++) {
|
---|
997 | BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
|
---|
998 | if (BlockIoDevicePath == NULL) {
|
---|
999 | continue;
|
---|
1000 | }
|
---|
1001 |
|
---|
1002 | if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *)FilePath)) {
|
---|
1003 | //
|
---|
1004 | // Find the matched partition device path
|
---|
1005 | //
|
---|
1006 | TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
|
---|
1007 | FullPath = BmGetNextLoadOptionDevicePath (TempDevicePath, NULL);
|
---|
1008 | FreePool (TempDevicePath);
|
---|
1009 |
|
---|
1010 | if (FullPath != NULL) {
|
---|
1011 | BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
|
---|
1012 |
|
---|
1013 | //
|
---|
1014 | // Save the matching Device Path so we don't need to do a connect all next time
|
---|
1015 | // Failing to save only impacts performance next time expanding the short-form device path
|
---|
1016 | //
|
---|
1017 | Status = gRT->SetVariable (
|
---|
1018 | L"HDDP",
|
---|
1019 | &mBmHardDriveBootVariableGuid,
|
---|
1020 | EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
---|
1021 | EFI_VARIABLE_NON_VOLATILE,
|
---|
1022 | GetDevicePathSize (CachedDevicePath),
|
---|
1023 | CachedDevicePath
|
---|
1024 | );
|
---|
1025 | MatchFound = TRUE;
|
---|
1026 | break;
|
---|
1027 | }
|
---|
1028 | }
|
---|
1029 | }
|
---|
1030 |
|
---|
1031 | //
|
---|
1032 | // If we found a matching BLOCK_IO handle or we've already
|
---|
1033 | // tried a ConnectAll, we are done searching.
|
---|
1034 | //
|
---|
1035 | if (MatchFound || ConnectAllAttempted) {
|
---|
1036 | break;
|
---|
1037 | }
|
---|
1038 |
|
---|
1039 | EfiBootManagerConnectAll ();
|
---|
1040 | ConnectAllAttempted = TRUE;
|
---|
1041 | } while (1);
|
---|
1042 |
|
---|
1043 | if (CachedDevicePath != NULL) {
|
---|
1044 | FreePool (CachedDevicePath);
|
---|
1045 | }
|
---|
1046 |
|
---|
1047 | if (BlockIoBuffer != NULL) {
|
---|
1048 | FreePool (BlockIoBuffer);
|
---|
1049 | }
|
---|
1050 |
|
---|
1051 | return FullPath;
|
---|
1052 | }
|
---|
1053 |
|
---|
1054 | #ifdef VBOX
|
---|
1055 | /**
|
---|
1056 | * Checks which filename to try loading by inspecting what is existing on the provided
|
---|
1057 | * simple filesystem protocol provider.
|
---|
1058 | *
|
---|
1059 | * This is required to support booting macOS as it stores the efi OS loader in a non standard location
|
---|
1060 | * and we have to support both styles without rewriting half of the boot manager library.
|
---|
1061 | */
|
---|
1062 | EFI_STATUS VBoxBmQueryMediaFileNameForSFs(EFI_HANDLE hSFs, CHAR16 **ppwszFileName)
|
---|
1063 | {
|
---|
1064 | EFI_STATUS Status = EFI_SUCCESS;
|
---|
1065 | EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *pSFs = NULL;
|
---|
1066 | EFI_FILE_PROTOCOL *pRoot = NULL;
|
---|
1067 |
|
---|
1068 | *ppwszFileName = EFI_REMOVABLE_MEDIA_FILE_NAME;
|
---|
1069 |
|
---|
1070 | Status = gBS->HandleProtocol(hSFs, &gEfiSimpleFileSystemProtocolGuid, (void **)&pSFs);
|
---|
1071 | if (!EFI_ERROR(Status))
|
---|
1072 | {
|
---|
1073 | Status = pSFs->OpenVolume(pSFs, &pRoot);
|
---|
1074 | if (!EFI_ERROR(Status))
|
---|
1075 | {
|
---|
1076 | #if 0
|
---|
1077 | # define VBOX_EFI_APPLE_MEDIA_FILE_NAME L"\\System\\Library\\CoreServices\\boot.efi"
|
---|
1078 | EFI_FILE_PROTOCOL *pFile = NULL;
|
---|
1079 |
|
---|
1080 | Status = pRoot->Open(pRoot, &pFile, VBOX_EFI_APPLE_MEDIA_FILE_NAME, EFI_FILE_MODE_READ,
|
---|
1081 | EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM);
|
---|
1082 | if (!EFI_ERROR(Status))
|
---|
1083 | {
|
---|
1084 | *ppwszFileName = VBOX_EFI_APPLE_MEDIA_FILE_NAME;
|
---|
1085 | pFile->Close(pFile);
|
---|
1086 | }
|
---|
1087 | #else /* Doesn't quite work yet. */
|
---|
1088 | VBOX_FS_BLESSED_FILE *Buffer = NULL;
|
---|
1089 | UINTN BufferSize = 0;
|
---|
1090 |
|
---|
1091 | Status = pRoot->GetInfo(pRoot, &gVBoxFsBlessedFileInfoGuid, &BufferSize, Buffer);
|
---|
1092 | if (Status == EFI_BUFFER_TOO_SMALL) {
|
---|
1093 | Buffer = AllocatePool (BufferSize);
|
---|
1094 | ASSERT (Buffer != NULL);
|
---|
1095 |
|
---|
1096 | /** @todo We might leak this allocation but it doesn't really matter as it
|
---|
1097 | * is of type BootServicesData and will be reclaimed by the OS when it boots.
|
---|
1098 | */
|
---|
1099 | Status = pRoot->GetInfo(pRoot, &gVBoxFsBlessedFileInfoGuid, &BufferSize, Buffer);
|
---|
1100 | if (!EFI_ERROR(Status))
|
---|
1101 | {
|
---|
1102 | DEBUG ((EFI_D_INFO, "[Bds] VBoxBmQueryMediaFileNameForSFs: Got blessed file info %s\n", &Buffer->BlessedFile[0]));
|
---|
1103 | *ppwszFileName = &Buffer->BlessedFile[0];
|
---|
1104 | }
|
---|
1105 | }
|
---|
1106 | #endif
|
---|
1107 |
|
---|
1108 | pRoot->Close(pRoot);
|
---|
1109 | }
|
---|
1110 | }
|
---|
1111 |
|
---|
1112 | return EFI_SUCCESS;
|
---|
1113 | }
|
---|
1114 | #endif
|
---|
1115 |
|
---|
1116 | /**
|
---|
1117 | Expand the media device path which points to a BlockIo or SimpleFileSystem instance
|
---|
1118 | by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
|
---|
1119 |
|
---|
1120 | @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
|
---|
1121 | @param FullPath The full path returned by the routine in last call.
|
---|
1122 | Set to NULL in first call.
|
---|
1123 |
|
---|
1124 | @return The next possible full path pointing to the load option.
|
---|
1125 | Caller is responsible to free the memory.
|
---|
1126 | **/
|
---|
1127 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
1128 | BmExpandMediaDevicePath (
|
---|
1129 | IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
---|
1130 | IN EFI_DEVICE_PATH_PROTOCOL *FullPath
|
---|
1131 | )
|
---|
1132 | {
|
---|
1133 | EFI_STATUS Status;
|
---|
1134 | EFI_HANDLE Handle;
|
---|
1135 | EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
---|
1136 | VOID *Buffer;
|
---|
1137 | EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
|
---|
1138 | EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
|
---|
1139 | UINTN Size;
|
---|
1140 | UINTN TempSize;
|
---|
1141 | EFI_HANDLE *SimpleFileSystemHandles;
|
---|
1142 | UINTN NumberSimpleFileSystemHandles;
|
---|
1143 | UINTN Index;
|
---|
1144 | BOOLEAN GetNext;
|
---|
1145 | #ifdef VBOX
|
---|
1146 | CHAR16 *pwszFilename = NULL;
|
---|
1147 | #endif
|
---|
1148 |
|
---|
1149 | GetNext = (BOOLEAN)(FullPath == NULL);
|
---|
1150 |
|
---|
1151 | //
|
---|
1152 | // Check whether the device is connected
|
---|
1153 | //
|
---|
1154 | TempDevicePath = DevicePath;
|
---|
1155 | Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
|
---|
1156 | if (!EFI_ERROR (Status)) {
|
---|
1157 | ASSERT (IsDevicePathEnd (TempDevicePath));
|
---|
1158 |
|
---|
1159 | #ifndef VBOX
|
---|
1160 | NextFullPath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
|
---|
1161 | #else
|
---|
1162 | Status = VBoxBmQueryMediaFileNameForSFs(Handle, &pwszFilename);
|
---|
1163 | if (!EFI_ERROR(Status))
|
---|
1164 | NextFullPath = FileDevicePath (Handle, pwszFilename);
|
---|
1165 | else
|
---|
1166 | return NULL;
|
---|
1167 | #endif
|
---|
1168 | //
|
---|
1169 | // For device path pointing to simple file system, it only expands to one full path.
|
---|
1170 | //
|
---|
1171 | if (GetNext) {
|
---|
1172 | return NextFullPath;
|
---|
1173 | } else {
|
---|
1174 | FreePool (NextFullPath);
|
---|
1175 | return NULL;
|
---|
1176 | }
|
---|
1177 | }
|
---|
1178 |
|
---|
1179 | Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
|
---|
1180 | ASSERT_EFI_ERROR (Status);
|
---|
1181 |
|
---|
1182 | //
|
---|
1183 | // For device boot option only pointing to the removable device handle,
|
---|
1184 | // should make sure all its children handles (its child partion or media handles)
|
---|
1185 | // are created and connected.
|
---|
1186 | //
|
---|
1187 | gBS->ConnectController (Handle, NULL, NULL, TRUE);
|
---|
1188 |
|
---|
1189 | //
|
---|
1190 | // Issue a dummy read to the device to check for media change.
|
---|
1191 | // When the removable media is changed, any Block IO read/write will
|
---|
1192 | // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
|
---|
1193 | // returned. After the Block IO protocol is reinstalled, subsequent
|
---|
1194 | // Block IO read/write will success.
|
---|
1195 | //
|
---|
1196 | Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
|
---|
1197 | ASSERT_EFI_ERROR (Status);
|
---|
1198 | if (EFI_ERROR (Status)) {
|
---|
1199 | return NULL;
|
---|
1200 | }
|
---|
1201 |
|
---|
1202 | Buffer = AllocatePool (BlockIo->Media->BlockSize);
|
---|
1203 | if (Buffer != NULL) {
|
---|
1204 | BlockIo->ReadBlocks (
|
---|
1205 | BlockIo,
|
---|
1206 | BlockIo->Media->MediaId,
|
---|
1207 | 0,
|
---|
1208 | BlockIo->Media->BlockSize,
|
---|
1209 | Buffer
|
---|
1210 | );
|
---|
1211 | FreePool (Buffer);
|
---|
1212 | }
|
---|
1213 |
|
---|
1214 | //
|
---|
1215 | // Detect the the default boot file from removable Media
|
---|
1216 | //
|
---|
1217 | NextFullPath = NULL;
|
---|
1218 | Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
|
---|
1219 | gBS->LocateHandleBuffer (
|
---|
1220 | ByProtocol,
|
---|
1221 | &gEfiSimpleFileSystemProtocolGuid,
|
---|
1222 | NULL,
|
---|
1223 | &NumberSimpleFileSystemHandles,
|
---|
1224 | &SimpleFileSystemHandles
|
---|
1225 | );
|
---|
1226 | for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
|
---|
1227 | //
|
---|
1228 | // Get the device path size of SimpleFileSystem handle
|
---|
1229 | //
|
---|
1230 | TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
|
---|
1231 | TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
|
---|
1232 | //
|
---|
1233 | // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
|
---|
1234 | //
|
---|
1235 | if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
|
---|
1236 | #ifndef VBOX
|
---|
1237 | NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
|
---|
1238 | #else
|
---|
1239 | Status = VBoxBmQueryMediaFileNameForSFs(SimpleFileSystemHandles[Index], &pwszFilename);
|
---|
1240 | if (!EFI_ERROR(Status))
|
---|
1241 | NextFullPath = FileDevicePath (SimpleFileSystemHandles[Index], pwszFilename);
|
---|
1242 | else
|
---|
1243 | return NULL;
|
---|
1244 | #endif
|
---|
1245 | if (GetNext) {
|
---|
1246 | break;
|
---|
1247 | } else {
|
---|
1248 | GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
|
---|
1249 | FreePool (NextFullPath);
|
---|
1250 | NextFullPath = NULL;
|
---|
1251 | }
|
---|
1252 | }
|
---|
1253 | }
|
---|
1254 |
|
---|
1255 | if (SimpleFileSystemHandles != NULL) {
|
---|
1256 | FreePool (SimpleFileSystemHandles);
|
---|
1257 | }
|
---|
1258 |
|
---|
1259 | return NextFullPath;
|
---|
1260 | }
|
---|
1261 |
|
---|
1262 | /**
|
---|
1263 | Check whether Left and Right are the same without matching the specific
|
---|
1264 | device path data in IP device path and URI device path node.
|
---|
1265 |
|
---|
1266 | @retval TRUE Left and Right are the same.
|
---|
1267 | @retval FALSE Left and Right are the different.
|
---|
1268 | **/
|
---|
1269 | BOOLEAN
|
---|
1270 | BmMatchHttpBootDevicePath (
|
---|
1271 | IN EFI_DEVICE_PATH_PROTOCOL *Left,
|
---|
1272 | IN EFI_DEVICE_PATH_PROTOCOL *Right
|
---|
1273 | )
|
---|
1274 | {
|
---|
1275 | for ( ; !IsDevicePathEnd (Left) && !IsDevicePathEnd (Right)
|
---|
1276 | ; Left = NextDevicePathNode (Left), Right = NextDevicePathNode (Right)
|
---|
1277 | )
|
---|
1278 | {
|
---|
1279 | if (CompareMem (Left, Right, DevicePathNodeLength (Left)) != 0) {
|
---|
1280 | if ((DevicePathType (Left) != MESSAGING_DEVICE_PATH) || (DevicePathType (Right) != MESSAGING_DEVICE_PATH)) {
|
---|
1281 | return FALSE;
|
---|
1282 | }
|
---|
1283 |
|
---|
1284 | if (DevicePathSubType (Left) == MSG_DNS_DP) {
|
---|
1285 | Left = NextDevicePathNode (Left);
|
---|
1286 | }
|
---|
1287 |
|
---|
1288 | if (DevicePathSubType (Right) == MSG_DNS_DP) {
|
---|
1289 | Right = NextDevicePathNode (Right);
|
---|
1290 | }
|
---|
1291 |
|
---|
1292 | if (((DevicePathSubType (Left) != MSG_IPv4_DP) || (DevicePathSubType (Right) != MSG_IPv4_DP)) &&
|
---|
1293 | ((DevicePathSubType (Left) != MSG_IPv6_DP) || (DevicePathSubType (Right) != MSG_IPv6_DP)) &&
|
---|
1294 | ((DevicePathSubType (Left) != MSG_URI_DP) || (DevicePathSubType (Right) != MSG_URI_DP))
|
---|
1295 | )
|
---|
1296 | {
|
---|
1297 | return FALSE;
|
---|
1298 | }
|
---|
1299 | }
|
---|
1300 | }
|
---|
1301 |
|
---|
1302 | return (BOOLEAN)(IsDevicePathEnd (Left) && IsDevicePathEnd (Right));
|
---|
1303 | }
|
---|
1304 |
|
---|
1305 | /**
|
---|
1306 | Get the file buffer from the file system produced by Load File instance.
|
---|
1307 |
|
---|
1308 | @param LoadFileHandle The handle of LoadFile instance.
|
---|
1309 | @param RamDiskHandle Return the RAM Disk handle.
|
---|
1310 |
|
---|
1311 | @return The next possible full path pointing to the load option.
|
---|
1312 | Caller is responsible to free the memory.
|
---|
1313 | **/
|
---|
1314 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
1315 | BmExpandNetworkFileSystem (
|
---|
1316 | IN EFI_HANDLE LoadFileHandle,
|
---|
1317 | OUT EFI_HANDLE *RamDiskHandle
|
---|
1318 | )
|
---|
1319 | {
|
---|
1320 | EFI_STATUS Status;
|
---|
1321 | EFI_HANDLE Handle;
|
---|
1322 | EFI_HANDLE *Handles;
|
---|
1323 | UINTN HandleCount;
|
---|
1324 | UINTN Index;
|
---|
1325 | EFI_DEVICE_PATH_PROTOCOL *Node;
|
---|
1326 |
|
---|
1327 | Status = gBS->LocateHandleBuffer (
|
---|
1328 | ByProtocol,
|
---|
1329 | &gEfiBlockIoProtocolGuid,
|
---|
1330 | NULL,
|
---|
1331 | &HandleCount,
|
---|
1332 | &Handles
|
---|
1333 | );
|
---|
1334 | if (EFI_ERROR (Status)) {
|
---|
1335 | Handles = NULL;
|
---|
1336 | HandleCount = 0;
|
---|
1337 | }
|
---|
1338 |
|
---|
1339 | Handle = NULL;
|
---|
1340 | for (Index = 0; Index < HandleCount; Index++) {
|
---|
1341 | Node = DevicePathFromHandle (Handles[Index]);
|
---|
1342 | Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
|
---|
1343 | if (!EFI_ERROR (Status) &&
|
---|
1344 | (Handle == LoadFileHandle) &&
|
---|
1345 | (DevicePathType (Node) == MEDIA_DEVICE_PATH) && (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP))
|
---|
1346 | {
|
---|
1347 | //
|
---|
1348 | // Find the BlockIo instance populated from the LoadFile.
|
---|
1349 | //
|
---|
1350 | Handle = Handles[Index];
|
---|
1351 | break;
|
---|
1352 | }
|
---|
1353 | }
|
---|
1354 |
|
---|
1355 | if (Handles != NULL) {
|
---|
1356 | FreePool (Handles);
|
---|
1357 | }
|
---|
1358 |
|
---|
1359 | if (Index == HandleCount) {
|
---|
1360 | Handle = NULL;
|
---|
1361 | }
|
---|
1362 |
|
---|
1363 | *RamDiskHandle = Handle;
|
---|
1364 |
|
---|
1365 | if (Handle != NULL) {
|
---|
1366 | //
|
---|
1367 | // Re-use BmExpandMediaDevicePath() to get the full device path of load option.
|
---|
1368 | // But assume only one SimpleFileSystem can be found under the BlockIo.
|
---|
1369 | //
|
---|
1370 | return BmExpandMediaDevicePath (DevicePathFromHandle (Handle), NULL);
|
---|
1371 | } else {
|
---|
1372 | return NULL;
|
---|
1373 | }
|
---|
1374 | }
|
---|
1375 |
|
---|
1376 | /**
|
---|
1377 | Return the RAM Disk device path created by LoadFile.
|
---|
1378 |
|
---|
1379 | @param FilePath The source file path.
|
---|
1380 |
|
---|
1381 | @return Callee-to-free RAM Disk device path
|
---|
1382 | **/
|
---|
1383 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
1384 | BmGetRamDiskDevicePath (
|
---|
1385 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath
|
---|
1386 | )
|
---|
1387 | {
|
---|
1388 | EFI_STATUS Status;
|
---|
1389 | EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
|
---|
1390 | EFI_DEVICE_PATH_PROTOCOL *Node;
|
---|
1391 | EFI_HANDLE Handle;
|
---|
1392 |
|
---|
1393 | Node = FilePath;
|
---|
1394 | Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
|
---|
1395 | if (!EFI_ERROR (Status) &&
|
---|
1396 | (DevicePathType (Node) == MEDIA_DEVICE_PATH) &&
|
---|
1397 | (DevicePathSubType (Node) == MEDIA_RAM_DISK_DP)
|
---|
1398 | )
|
---|
1399 | {
|
---|
1400 | //
|
---|
1401 | // Construct the device path pointing to RAM Disk
|
---|
1402 | //
|
---|
1403 | Node = NextDevicePathNode (Node);
|
---|
1404 | RamDiskDevicePath = DuplicateDevicePath (FilePath);
|
---|
1405 | ASSERT (RamDiskDevicePath != NULL);
|
---|
1406 | SetDevicePathEndNode ((VOID *)((UINTN)RamDiskDevicePath + ((UINTN)Node - (UINTN)FilePath)));
|
---|
1407 | return RamDiskDevicePath;
|
---|
1408 | }
|
---|
1409 |
|
---|
1410 | return NULL;
|
---|
1411 | }
|
---|
1412 |
|
---|
1413 | /**
|
---|
1414 | Return the buffer and buffer size occupied by the RAM Disk.
|
---|
1415 |
|
---|
1416 | @param RamDiskDevicePath RAM Disk device path.
|
---|
1417 | @param RamDiskSizeInPages Return RAM Disk size in pages.
|
---|
1418 |
|
---|
1419 | @retval RAM Disk buffer.
|
---|
1420 | **/
|
---|
1421 | VOID *
|
---|
1422 | BmGetRamDiskMemoryInfo (
|
---|
1423 | IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath,
|
---|
1424 | OUT UINTN *RamDiskSizeInPages
|
---|
1425 | )
|
---|
1426 | {
|
---|
1427 | EFI_STATUS Status;
|
---|
1428 | EFI_HANDLE Handle;
|
---|
1429 | UINT64 StartingAddr;
|
---|
1430 | UINT64 EndingAddr;
|
---|
1431 |
|
---|
1432 | ASSERT (RamDiskDevicePath != NULL);
|
---|
1433 |
|
---|
1434 | *RamDiskSizeInPages = 0;
|
---|
1435 |
|
---|
1436 | //
|
---|
1437 | // Get the buffer occupied by RAM Disk.
|
---|
1438 | //
|
---|
1439 | Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &RamDiskDevicePath, &Handle);
|
---|
1440 | ASSERT_EFI_ERROR (Status);
|
---|
1441 | ASSERT (
|
---|
1442 | (DevicePathType (RamDiskDevicePath) == MEDIA_DEVICE_PATH) &&
|
---|
1443 | (DevicePathSubType (RamDiskDevicePath) == MEDIA_RAM_DISK_DP)
|
---|
1444 | );
|
---|
1445 | StartingAddr = ReadUnaligned64 ((UINT64 *)((MEDIA_RAM_DISK_DEVICE_PATH *)RamDiskDevicePath)->StartingAddr);
|
---|
1446 | EndingAddr = ReadUnaligned64 ((UINT64 *)((MEDIA_RAM_DISK_DEVICE_PATH *)RamDiskDevicePath)->EndingAddr);
|
---|
1447 | *RamDiskSizeInPages = EFI_SIZE_TO_PAGES ((UINTN)(EndingAddr - StartingAddr + 1));
|
---|
1448 | return (VOID *)(UINTN)StartingAddr;
|
---|
1449 | }
|
---|
1450 |
|
---|
1451 | /**
|
---|
1452 | Destroy the RAM Disk.
|
---|
1453 |
|
---|
1454 | The destroy operation includes to call RamDisk.Unregister to
|
---|
1455 | unregister the RAM DISK from RAM DISK driver, free the memory
|
---|
1456 | allocated for the RAM Disk.
|
---|
1457 |
|
---|
1458 | @param RamDiskDevicePath RAM Disk device path.
|
---|
1459 | **/
|
---|
1460 | VOID
|
---|
1461 | BmDestroyRamDisk (
|
---|
1462 | IN EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath
|
---|
1463 | )
|
---|
1464 | {
|
---|
1465 | EFI_STATUS Status;
|
---|
1466 | VOID *RamDiskBuffer;
|
---|
1467 | UINTN RamDiskSizeInPages;
|
---|
1468 |
|
---|
1469 | ASSERT (RamDiskDevicePath != NULL);
|
---|
1470 |
|
---|
1471 | RamDiskBuffer = BmGetRamDiskMemoryInfo (RamDiskDevicePath, &RamDiskSizeInPages);
|
---|
1472 |
|
---|
1473 | //
|
---|
1474 | // Destroy RAM Disk.
|
---|
1475 | //
|
---|
1476 | if (mRamDisk == NULL) {
|
---|
1477 | Status = gBS->LocateProtocol (&gEfiRamDiskProtocolGuid, NULL, (VOID *)&mRamDisk);
|
---|
1478 | ASSERT_EFI_ERROR (Status);
|
---|
1479 | }
|
---|
1480 |
|
---|
1481 | Status = mRamDisk->Unregister (RamDiskDevicePath);
|
---|
1482 | ASSERT_EFI_ERROR (Status);
|
---|
1483 | FreePages (RamDiskBuffer, RamDiskSizeInPages);
|
---|
1484 | }
|
---|
1485 |
|
---|
1486 | /**
|
---|
1487 | Get the file buffer from the specified Load File instance.
|
---|
1488 |
|
---|
1489 | @param LoadFileHandle The specified Load File instance.
|
---|
1490 | @param FilePath The file path which will pass to LoadFile().
|
---|
1491 |
|
---|
1492 | @return The full device path pointing to the load option buffer.
|
---|
1493 | **/
|
---|
1494 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
1495 | BmExpandLoadFile (
|
---|
1496 | IN EFI_HANDLE LoadFileHandle,
|
---|
1497 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath
|
---|
1498 | )
|
---|
1499 | {
|
---|
1500 | EFI_STATUS Status;
|
---|
1501 | EFI_LOAD_FILE_PROTOCOL *LoadFile;
|
---|
1502 | VOID *FileBuffer;
|
---|
1503 | EFI_HANDLE RamDiskHandle;
|
---|
1504 | UINTN BufferSize;
|
---|
1505 | EFI_DEVICE_PATH_PROTOCOL *FullPath;
|
---|
1506 |
|
---|
1507 | Status = gBS->OpenProtocol (
|
---|
1508 | LoadFileHandle,
|
---|
1509 | &gEfiLoadFileProtocolGuid,
|
---|
1510 | (VOID **)&LoadFile,
|
---|
1511 | gImageHandle,
|
---|
1512 | NULL,
|
---|
1513 | EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
---|
1514 | );
|
---|
1515 | ASSERT_EFI_ERROR (Status);
|
---|
1516 |
|
---|
1517 | FileBuffer = NULL;
|
---|
1518 | BufferSize = 0;
|
---|
1519 | Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
|
---|
1520 | if ((Status != EFI_WARN_FILE_SYSTEM) && (Status != EFI_BUFFER_TOO_SMALL)) {
|
---|
1521 | return NULL;
|
---|
1522 | }
|
---|
1523 |
|
---|
1524 | if (Status == EFI_BUFFER_TOO_SMALL) {
|
---|
1525 | //
|
---|
1526 | // The load option buffer is directly returned by LoadFile.
|
---|
1527 | //
|
---|
1528 | return DuplicateDevicePath (DevicePathFromHandle (LoadFileHandle));
|
---|
1529 | }
|
---|
1530 |
|
---|
1531 | //
|
---|
1532 | // The load option resides in a RAM disk.
|
---|
1533 | //
|
---|
1534 | FileBuffer = AllocateReservedPages (EFI_SIZE_TO_PAGES (BufferSize));
|
---|
1535 | if (FileBuffer == NULL) {
|
---|
1536 | DEBUG_CODE_BEGIN ();
|
---|
1537 | EFI_DEVICE_PATH *LoadFilePath;
|
---|
1538 | CHAR16 *LoadFileText;
|
---|
1539 | CHAR16 *FileText;
|
---|
1540 |
|
---|
1541 | LoadFilePath = DevicePathFromHandle (LoadFileHandle);
|
---|
1542 | if (LoadFilePath == NULL) {
|
---|
1543 | LoadFileText = NULL;
|
---|
1544 | } else {
|
---|
1545 | LoadFileText = ConvertDevicePathToText (LoadFilePath, FALSE, FALSE);
|
---|
1546 | }
|
---|
1547 |
|
---|
1548 | FileText = ConvertDevicePathToText (FilePath, FALSE, FALSE);
|
---|
1549 |
|
---|
1550 | DEBUG ((
|
---|
1551 | DEBUG_ERROR,
|
---|
1552 | "%a:%a: failed to allocate reserved pages: "
|
---|
1553 | "BufferSize=%Lu LoadFile=\"%s\" FilePath=\"%s\"\n",
|
---|
1554 | gEfiCallerBaseName,
|
---|
1555 | __func__,
|
---|
1556 | (UINT64)BufferSize,
|
---|
1557 | LoadFileText,
|
---|
1558 | FileText
|
---|
1559 | ));
|
---|
1560 |
|
---|
1561 | if (FileText != NULL) {
|
---|
1562 | FreePool (FileText);
|
---|
1563 | }
|
---|
1564 |
|
---|
1565 | if (LoadFileText != NULL) {
|
---|
1566 | FreePool (LoadFileText);
|
---|
1567 | }
|
---|
1568 |
|
---|
1569 | DEBUG_CODE_END ();
|
---|
1570 | return NULL;
|
---|
1571 | }
|
---|
1572 |
|
---|
1573 | Status = LoadFile->LoadFile (LoadFile, FilePath, TRUE, &BufferSize, FileBuffer);
|
---|
1574 | if (EFI_ERROR (Status)) {
|
---|
1575 | FreePages (FileBuffer, EFI_SIZE_TO_PAGES (BufferSize));
|
---|
1576 | return NULL;
|
---|
1577 | }
|
---|
1578 |
|
---|
1579 | FullPath = BmExpandNetworkFileSystem (LoadFileHandle, &RamDiskHandle);
|
---|
1580 | if (FullPath == NULL) {
|
---|
1581 | //
|
---|
1582 | // Free the memory occupied by the RAM disk if there is no BlockIo or SimpleFileSystem instance.
|
---|
1583 | //
|
---|
1584 | BmDestroyRamDisk (DevicePathFromHandle (RamDiskHandle));
|
---|
1585 | }
|
---|
1586 |
|
---|
1587 | return FullPath;
|
---|
1588 | }
|
---|
1589 |
|
---|
1590 | /**
|
---|
1591 | Return the full device path pointing to the load option.
|
---|
1592 |
|
---|
1593 | FilePath may:
|
---|
1594 | 1. Exactly matches to a LoadFile instance.
|
---|
1595 | 2. Cannot match to any LoadFile instance. Wide match is required.
|
---|
1596 | In either case, the routine may return:
|
---|
1597 | 1. A copy of FilePath when FilePath matches to a LoadFile instance and
|
---|
1598 | the LoadFile returns a load option buffer.
|
---|
1599 | 2. A new device path with IP and URI information updated when wide match
|
---|
1600 | happens.
|
---|
1601 | 3. A new device path pointing to a load option in RAM disk.
|
---|
1602 | In either case, only one full device path is returned for a specified
|
---|
1603 | FilePath.
|
---|
1604 |
|
---|
1605 | @param FilePath The media device path pointing to a LoadFile instance.
|
---|
1606 |
|
---|
1607 | @return The load option buffer.
|
---|
1608 | **/
|
---|
1609 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
1610 | BmExpandLoadFiles (
|
---|
1611 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath
|
---|
1612 | )
|
---|
1613 | {
|
---|
1614 | EFI_STATUS Status;
|
---|
1615 | EFI_HANDLE Handle;
|
---|
1616 | EFI_HANDLE *Handles;
|
---|
1617 | UINTN HandleCount;
|
---|
1618 | UINTN Index;
|
---|
1619 | EFI_DEVICE_PATH_PROTOCOL *Node;
|
---|
1620 |
|
---|
1621 | //
|
---|
1622 | // Get file buffer from load file instance.
|
---|
1623 | //
|
---|
1624 | Node = FilePath;
|
---|
1625 | Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);
|
---|
1626 | if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
|
---|
1627 | //
|
---|
1628 | // When wide match happens, pass full device path to LoadFile (),
|
---|
1629 | // otherwise, pass remaining device path to LoadFile ().
|
---|
1630 | //
|
---|
1631 | FilePath = Node;
|
---|
1632 | } else {
|
---|
1633 | Handle = NULL;
|
---|
1634 | //
|
---|
1635 | // Use wide match algorithm to find one when
|
---|
1636 | // cannot find a LoadFile instance to exactly match the FilePath
|
---|
1637 | //
|
---|
1638 | Status = gBS->LocateHandleBuffer (
|
---|
1639 | ByProtocol,
|
---|
1640 | &gEfiLoadFileProtocolGuid,
|
---|
1641 | NULL,
|
---|
1642 | &HandleCount,
|
---|
1643 | &Handles
|
---|
1644 | );
|
---|
1645 | if (EFI_ERROR (Status)) {
|
---|
1646 | Handles = NULL;
|
---|
1647 | HandleCount = 0;
|
---|
1648 | }
|
---|
1649 |
|
---|
1650 | for (Index = 0; Index < HandleCount; Index++) {
|
---|
1651 | if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) {
|
---|
1652 | Handle = Handles[Index];
|
---|
1653 | break;
|
---|
1654 | }
|
---|
1655 | }
|
---|
1656 |
|
---|
1657 | if (Handles != NULL) {
|
---|
1658 | FreePool (Handles);
|
---|
1659 | }
|
---|
1660 | }
|
---|
1661 |
|
---|
1662 | if (Handle == NULL) {
|
---|
1663 | return NULL;
|
---|
1664 | }
|
---|
1665 |
|
---|
1666 | return BmExpandLoadFile (Handle, FilePath);
|
---|
1667 | }
|
---|
1668 |
|
---|
1669 | /**
|
---|
1670 | Get the load option by its device path.
|
---|
1671 |
|
---|
1672 | @param FilePath The device path pointing to a load option.
|
---|
1673 | It could be a short-form device path.
|
---|
1674 | @param FullPath Return the full device path of the load option after
|
---|
1675 | short-form device path expanding.
|
---|
1676 | Caller is responsible to free it.
|
---|
1677 | @param FileSize Return the load option size.
|
---|
1678 |
|
---|
1679 | @return The load option buffer. Caller is responsible to free the memory.
|
---|
1680 | **/
|
---|
1681 | VOID *
|
---|
1682 | EFIAPI
|
---|
1683 | EfiBootManagerGetLoadOptionBuffer (
|
---|
1684 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
---|
1685 | OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
|
---|
1686 | OUT UINTN *FileSize
|
---|
1687 | )
|
---|
1688 | {
|
---|
1689 | *FullPath = NULL;
|
---|
1690 |
|
---|
1691 | EfiBootManagerConnectDevicePath (FilePath, NULL);
|
---|
1692 | return BmGetNextLoadOptionBuffer (LoadOptionTypeMax, FilePath, FullPath, FileSize);
|
---|
1693 | }
|
---|
1694 |
|
---|
1695 | /**
|
---|
1696 | Get the next possible full path pointing to the load option.
|
---|
1697 | The routine doesn't guarantee the returned full path points to an existing
|
---|
1698 | file, and it also doesn't guarantee the existing file is a valid load option.
|
---|
1699 | BmGetNextLoadOptionBuffer() guarantees.
|
---|
1700 |
|
---|
1701 | @param FilePath The device path pointing to a load option.
|
---|
1702 | It could be a short-form device path.
|
---|
1703 | @param FullPath The full path returned by the routine in last call.
|
---|
1704 | Set to NULL in first call.
|
---|
1705 |
|
---|
1706 | @return The next possible full path pointing to the load option.
|
---|
1707 | Caller is responsible to free the memory.
|
---|
1708 | **/
|
---|
1709 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
1710 | BmGetNextLoadOptionDevicePath (
|
---|
1711 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
---|
1712 | IN EFI_DEVICE_PATH_PROTOCOL *FullPath
|
---|
1713 | )
|
---|
1714 | {
|
---|
1715 | EFI_HANDLE Handle;
|
---|
1716 | EFI_DEVICE_PATH_PROTOCOL *Node;
|
---|
1717 | EFI_STATUS Status;
|
---|
1718 |
|
---|
1719 | ASSERT (FilePath != NULL);
|
---|
1720 |
|
---|
1721 | //
|
---|
1722 | // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
|
---|
1723 | //
|
---|
1724 | Node = FilePath;
|
---|
1725 | Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
|
---|
1726 | if (EFI_ERROR (Status)) {
|
---|
1727 | Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
|
---|
1728 | }
|
---|
1729 |
|
---|
1730 | if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
|
---|
1731 | return BmExpandMediaDevicePath (FilePath, FullPath);
|
---|
1732 | }
|
---|
1733 |
|
---|
1734 | //
|
---|
1735 | // Expand the short-form device path to full device path
|
---|
1736 | //
|
---|
1737 | if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
|
---|
1738 | (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP))
|
---|
1739 | {
|
---|
1740 | //
|
---|
1741 | // Expand the Harddrive device path
|
---|
1742 | //
|
---|
1743 | if (FullPath == NULL) {
|
---|
1744 | return BmExpandPartitionDevicePath (FilePath);
|
---|
1745 | } else {
|
---|
1746 | return NULL;
|
---|
1747 | }
|
---|
1748 | } else if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
|
---|
1749 | (DevicePathSubType (FilePath) == MEDIA_FILEPATH_DP))
|
---|
1750 | {
|
---|
1751 | //
|
---|
1752 | // Expand the File-path device path
|
---|
1753 | //
|
---|
1754 | return BmExpandFileDevicePath (FilePath, FullPath);
|
---|
1755 | } else if ((DevicePathType (FilePath) == MESSAGING_DEVICE_PATH) &&
|
---|
1756 | (DevicePathSubType (FilePath) == MSG_URI_DP))
|
---|
1757 | {
|
---|
1758 | //
|
---|
1759 | // Expand the URI device path
|
---|
1760 | //
|
---|
1761 | return BmExpandUriDevicePath (FilePath, FullPath);
|
---|
1762 | } else {
|
---|
1763 | Node = FilePath;
|
---|
1764 | Status = gBS->LocateDevicePath (&gEfiUsbIoProtocolGuid, &Node, &Handle);
|
---|
1765 | if (EFI_ERROR (Status)) {
|
---|
1766 | //
|
---|
1767 | // Only expand the USB WWID/Class device path
|
---|
1768 | // when FilePath doesn't point to a physical UsbIo controller.
|
---|
1769 | // Otherwise, infinite recursion will happen.
|
---|
1770 | //
|
---|
1771 | for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
|
---|
1772 | if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
|
---|
1773 | ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP)))
|
---|
1774 | {
|
---|
1775 | break;
|
---|
1776 | }
|
---|
1777 | }
|
---|
1778 |
|
---|
1779 | //
|
---|
1780 | // Expand the USB WWID/Class device path
|
---|
1781 | //
|
---|
1782 | if (!IsDevicePathEnd (Node)) {
|
---|
1783 | if (FilePath == Node) {
|
---|
1784 | //
|
---|
1785 | // Boot Option device path starts with USB Class or USB WWID device path.
|
---|
1786 | // For Boot Option device path which doesn't begin with the USB Class or
|
---|
1787 | // USB WWID device path, it's not needed to connect again here.
|
---|
1788 | //
|
---|
1789 | BmConnectUsbShortFormDevicePath (FilePath);
|
---|
1790 | }
|
---|
1791 |
|
---|
1792 | return BmExpandUsbDevicePath (FilePath, FullPath, Node);
|
---|
1793 | }
|
---|
1794 | }
|
---|
1795 | }
|
---|
1796 |
|
---|
1797 | //
|
---|
1798 | // For the below cases, FilePath only expands to one Full path.
|
---|
1799 | // So just handle the case when FullPath == NULL.
|
---|
1800 | //
|
---|
1801 | if (FullPath != NULL) {
|
---|
1802 | return NULL;
|
---|
1803 | }
|
---|
1804 |
|
---|
1805 | //
|
---|
1806 | // Load option resides in FV.
|
---|
1807 | //
|
---|
1808 | if (BmIsFvFilePath (FilePath)) {
|
---|
1809 | return BmAdjustFvFilePath (FilePath);
|
---|
1810 | }
|
---|
1811 |
|
---|
1812 | //
|
---|
1813 | // Load option resides in Simple File System.
|
---|
1814 | //
|
---|
1815 | Node = FilePath;
|
---|
1816 | Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
|
---|
1817 | if (!EFI_ERROR (Status)) {
|
---|
1818 | return DuplicateDevicePath (FilePath);
|
---|
1819 | }
|
---|
1820 |
|
---|
1821 | //
|
---|
1822 | // Last chance to try: Load option may be loaded through LoadFile.
|
---|
1823 | //
|
---|
1824 | return BmExpandLoadFiles (FilePath);
|
---|
1825 | }
|
---|
1826 |
|
---|
1827 | /**
|
---|
1828 | Check if it's a Device Path pointing to BootManagerMenu.
|
---|
1829 |
|
---|
1830 | @param DevicePath Input device path.
|
---|
1831 |
|
---|
1832 | @retval TRUE The device path is BootManagerMenu File Device Path.
|
---|
1833 | @retval FALSE The device path is NOT BootManagerMenu File Device Path.
|
---|
1834 | **/
|
---|
1835 | BOOLEAN
|
---|
1836 | BmIsBootManagerMenuFilePath (
|
---|
1837 | EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
---|
1838 | )
|
---|
1839 | {
|
---|
1840 | EFI_HANDLE FvHandle;
|
---|
1841 | VOID *NameGuid;
|
---|
1842 | EFI_STATUS Status;
|
---|
1843 |
|
---|
1844 | Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle);
|
---|
1845 | if (!EFI_ERROR (Status)) {
|
---|
1846 | NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)DevicePath);
|
---|
1847 | if (NameGuid != NULL) {
|
---|
1848 | return CompareGuid (NameGuid, PcdGetPtr (PcdBootManagerMenuFile));
|
---|
1849 | }
|
---|
1850 | }
|
---|
1851 |
|
---|
1852 | return FALSE;
|
---|
1853 | }
|
---|
1854 |
|
---|
1855 | /**
|
---|
1856 | Report status code with EFI_RETURN_STATUS_EXTENDED_DATA about LoadImage() or
|
---|
1857 | StartImage() failure.
|
---|
1858 |
|
---|
1859 | @param[in] ErrorCode An Error Code in the Software Class, DXE Boot
|
---|
1860 | Service Driver Subclass. ErrorCode will be used to
|
---|
1861 | compose the Value parameter for status code
|
---|
1862 | reporting. Must be one of
|
---|
1863 | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR and
|
---|
1864 | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED.
|
---|
1865 |
|
---|
1866 | @param[in] FailureStatus The failure status returned by the boot service
|
---|
1867 | that should be reported.
|
---|
1868 | **/
|
---|
1869 | VOID
|
---|
1870 | BmReportLoadFailure (
|
---|
1871 | IN UINT32 ErrorCode,
|
---|
1872 | IN EFI_STATUS FailureStatus
|
---|
1873 | )
|
---|
1874 | {
|
---|
1875 | EFI_RETURN_STATUS_EXTENDED_DATA ExtendedData;
|
---|
1876 |
|
---|
1877 | if (!ReportErrorCodeEnabled ()) {
|
---|
1878 | return;
|
---|
1879 | }
|
---|
1880 |
|
---|
1881 | ASSERT (
|
---|
1882 | (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR) ||
|
---|
1883 | (ErrorCode == EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
|
---|
1884 | );
|
---|
1885 |
|
---|
1886 | ZeroMem (&ExtendedData, sizeof (ExtendedData));
|
---|
1887 | ExtendedData.ReturnStatus = FailureStatus;
|
---|
1888 |
|
---|
1889 | REPORT_STATUS_CODE_EX (
|
---|
1890 | (EFI_ERROR_CODE | EFI_ERROR_MINOR),
|
---|
1891 | (EFI_SOFTWARE_DXE_BS_DRIVER | ErrorCode),
|
---|
1892 | 0,
|
---|
1893 | NULL,
|
---|
1894 | NULL,
|
---|
1895 | &ExtendedData.DataHeader + 1,
|
---|
1896 | sizeof (ExtendedData) - sizeof (ExtendedData.DataHeader)
|
---|
1897 | );
|
---|
1898 | }
|
---|
1899 |
|
---|
1900 | /**
|
---|
1901 | Attempt to boot the EFI boot option. This routine sets L"BootCurent" and
|
---|
1902 | also signals the EFI ready to boot event. If the device path for the option
|
---|
1903 | starts with a BBS device path a legacy boot is attempted via the registered
|
---|
1904 | gLegacyBoot function. Short form device paths are also supported via this
|
---|
1905 | rountine. A device path starting with MEDIA_HARDDRIVE_DP, MSG_USB_WWID_DP,
|
---|
1906 | MSG_USB_CLASS_DP gets expaned out to find the first device that matches.
|
---|
1907 | If the BootOption Device Path fails the removable media boot algorithm
|
---|
1908 | is attempted (\EFI\BOOTIA32.EFI, \EFI\BOOTX64.EFI,... only one file type
|
---|
1909 | is tried per processor type)
|
---|
1910 |
|
---|
1911 | @param BootOption Boot Option to try and boot.
|
---|
1912 | On return, BootOption->Status contains the boot status.
|
---|
1913 | EFI_SUCCESS BootOption was booted
|
---|
1914 | EFI_UNSUPPORTED A BBS device path was found with no valid callback
|
---|
1915 | registered via EfiBootManagerInitialize().
|
---|
1916 | EFI_NOT_FOUND The BootOption was not found on the system
|
---|
1917 | !EFI_SUCCESS BootOption failed with this error status
|
---|
1918 |
|
---|
1919 | **/
|
---|
1920 | VOID
|
---|
1921 | EFIAPI
|
---|
1922 | EfiBootManagerBoot (
|
---|
1923 | IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
|
---|
1924 | )
|
---|
1925 | {
|
---|
1926 | EFI_STATUS Status;
|
---|
1927 | EFI_HANDLE ImageHandle;
|
---|
1928 | EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
|
---|
1929 | UINT16 Uint16;
|
---|
1930 | UINTN OptionNumber;
|
---|
1931 | UINTN OriginalOptionNumber;
|
---|
1932 | EFI_DEVICE_PATH_PROTOCOL *FilePath;
|
---|
1933 | EFI_DEVICE_PATH_PROTOCOL *RamDiskDevicePath;
|
---|
1934 | VOID *FileBuffer;
|
---|
1935 | UINTN FileSize;
|
---|
1936 | EFI_BOOT_LOGO_PROTOCOL *BootLogo;
|
---|
1937 | EFI_EVENT LegacyBootEvent;
|
---|
1938 |
|
---|
1939 | if (BootOption == NULL) {
|
---|
1940 | return;
|
---|
1941 | }
|
---|
1942 |
|
---|
1943 | if ((BootOption->FilePath == NULL) || (BootOption->OptionType != LoadOptionTypeBoot)) {
|
---|
1944 | BootOption->Status = EFI_INVALID_PARAMETER;
|
---|
1945 | return;
|
---|
1946 | }
|
---|
1947 |
|
---|
1948 | //
|
---|
1949 | // 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")
|
---|
1950 | //
|
---|
1951 | OptionNumber = BmFindBootOptionInVariable (BootOption);
|
---|
1952 | if (OptionNumber == LoadOptionNumberUnassigned) {
|
---|
1953 | Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
|
---|
1954 | if (!EFI_ERROR (Status)) {
|
---|
1955 | //
|
---|
1956 | // Save the BootOption->OptionNumber to restore later
|
---|
1957 | //
|
---|
1958 | OptionNumber = Uint16;
|
---|
1959 | OriginalOptionNumber = BootOption->OptionNumber;
|
---|
1960 | BootOption->OptionNumber = OptionNumber;
|
---|
1961 | Status = EfiBootManagerLoadOptionToVariable (BootOption);
|
---|
1962 | BootOption->OptionNumber = OriginalOptionNumber;
|
---|
1963 | }
|
---|
1964 |
|
---|
1965 | if (EFI_ERROR (Status)) {
|
---|
1966 | DEBUG ((DEBUG_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));
|
---|
1967 | BootOption->Status = Status;
|
---|
1968 | return;
|
---|
1969 | }
|
---|
1970 | }
|
---|
1971 |
|
---|
1972 | //
|
---|
1973 | // 2. Set BootCurrent
|
---|
1974 | //
|
---|
1975 | Uint16 = (UINT16)OptionNumber;
|
---|
1976 | BmSetVariableAndReportStatusCodeOnError (
|
---|
1977 | L"BootCurrent",
|
---|
1978 | &gEfiGlobalVariableGuid,
|
---|
1979 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
---|
1980 | sizeof (UINT16),
|
---|
1981 | &Uint16
|
---|
1982 | );
|
---|
1983 |
|
---|
1984 | //
|
---|
1985 | // 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute
|
---|
1986 | // the boot option.
|
---|
1987 | //
|
---|
1988 | if (BmIsBootManagerMenuFilePath (BootOption->FilePath)) {
|
---|
1989 | DEBUG ((DEBUG_INFO, "[Bds] Booting Boot Manager Menu.\n"));
|
---|
1990 | BmStopHotkeyService (NULL, NULL);
|
---|
1991 | } else {
|
---|
1992 | EfiSignalEventReadyToBoot ();
|
---|
1993 | //
|
---|
1994 | // Report Status Code to indicate ReadyToBoot was signalled
|
---|
1995 | //
|
---|
1996 | REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
|
---|
1997 | //
|
---|
1998 | // 4. Repair system through DriverHealth protocol
|
---|
1999 | //
|
---|
2000 | BmRepairAllControllers (0);
|
---|
2001 | }
|
---|
2002 |
|
---|
2003 | PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32)OptionNumber);
|
---|
2004 |
|
---|
2005 | //
|
---|
2006 | // 5. Adjust the different type memory page number just before booting
|
---|
2007 | // and save the updated info into the variable for next boot to use
|
---|
2008 | //
|
---|
2009 | BmSetMemoryTypeInformationVariable (
|
---|
2010 | (BOOLEAN)((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT)
|
---|
2011 | );
|
---|
2012 |
|
---|
2013 | //
|
---|
2014 | // 6. Load EFI boot option to ImageHandle
|
---|
2015 | //
|
---|
2016 | DEBUG_CODE_BEGIN ();
|
---|
2017 | if (BootOption->Description == NULL) {
|
---|
2018 | DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));
|
---|
2019 | } else {
|
---|
2020 | DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));
|
---|
2021 | }
|
---|
2022 |
|
---|
2023 | DEBUG_CODE_END ();
|
---|
2024 |
|
---|
2025 | ImageHandle = NULL;
|
---|
2026 | RamDiskDevicePath = NULL;
|
---|
2027 | if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
|
---|
2028 | Status = EFI_NOT_FOUND;
|
---|
2029 | FilePath = NULL;
|
---|
2030 | EfiBootManagerConnectDevicePath (BootOption->FilePath, NULL);
|
---|
2031 | FileBuffer = BmGetNextLoadOptionBuffer (LoadOptionTypeBoot, BootOption->FilePath, &FilePath, &FileSize);
|
---|
2032 | if (FileBuffer != NULL) {
|
---|
2033 | RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);
|
---|
2034 |
|
---|
2035 | REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
|
---|
2036 | Status = gBS->LoadImage (
|
---|
2037 | TRUE,
|
---|
2038 | gImageHandle,
|
---|
2039 | FilePath,
|
---|
2040 | FileBuffer,
|
---|
2041 | FileSize,
|
---|
2042 | &ImageHandle
|
---|
2043 | );
|
---|
2044 | }
|
---|
2045 |
|
---|
2046 | if (FileBuffer != NULL) {
|
---|
2047 | FreePool (FileBuffer);
|
---|
2048 | }
|
---|
2049 |
|
---|
2050 | if (FilePath != NULL) {
|
---|
2051 | FreePool (FilePath);
|
---|
2052 | }
|
---|
2053 |
|
---|
2054 | if (EFI_ERROR (Status)) {
|
---|
2055 | //
|
---|
2056 | // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
|
---|
2057 | // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
|
---|
2058 | // If the caller doesn't have the option to defer the execution of an image, we should
|
---|
2059 | // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
|
---|
2060 | //
|
---|
2061 | if (Status == EFI_SECURITY_VIOLATION) {
|
---|
2062 | gBS->UnloadImage (ImageHandle);
|
---|
2063 | }
|
---|
2064 |
|
---|
2065 | //
|
---|
2066 | // Destroy the RAM disk
|
---|
2067 | //
|
---|
2068 | if (RamDiskDevicePath != NULL) {
|
---|
2069 | BmDestroyRamDisk (RamDiskDevicePath);
|
---|
2070 | FreePool (RamDiskDevicePath);
|
---|
2071 | }
|
---|
2072 |
|
---|
2073 | //
|
---|
2074 | // Report Status Code with the failure status to indicate that the failure to load boot option
|
---|
2075 | //
|
---|
2076 | BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR, Status);
|
---|
2077 | BootOption->Status = Status;
|
---|
2078 | return;
|
---|
2079 | }
|
---|
2080 | }
|
---|
2081 |
|
---|
2082 | //
|
---|
2083 | // Check to see if we should legacy BOOT. If yes then do the legacy boot
|
---|
2084 | // Write boot to OS performance data for Legacy boot
|
---|
2085 | //
|
---|
2086 | if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
|
---|
2087 | if (mBmLegacyBoot != NULL) {
|
---|
2088 | //
|
---|
2089 | // Write boot to OS performance data for legacy boot.
|
---|
2090 | //
|
---|
2091 | PERF_CODE (
|
---|
2092 | //
|
---|
2093 | // Create an event to be signalled when Legacy Boot occurs to write performance data.
|
---|
2094 | //
|
---|
2095 | Status = EfiCreateEventLegacyBootEx (
|
---|
2096 | TPL_NOTIFY,
|
---|
2097 | BmEndOfBdsPerfCode,
|
---|
2098 | NULL,
|
---|
2099 | &LegacyBootEvent
|
---|
2100 | );
|
---|
2101 | ASSERT_EFI_ERROR (Status);
|
---|
2102 | );
|
---|
2103 |
|
---|
2104 | mBmLegacyBoot (BootOption);
|
---|
2105 | } else {
|
---|
2106 | BootOption->Status = EFI_UNSUPPORTED;
|
---|
2107 | }
|
---|
2108 |
|
---|
2109 | PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32)OptionNumber);
|
---|
2110 | return;
|
---|
2111 | }
|
---|
2112 |
|
---|
2113 | //
|
---|
2114 | // Provide the image with its load options
|
---|
2115 | //
|
---|
2116 | Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);
|
---|
2117 | ASSERT_EFI_ERROR (Status);
|
---|
2118 |
|
---|
2119 | if (!BmIsAutoCreateBootOption (BootOption)) {
|
---|
2120 | ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;
|
---|
2121 | ImageInfo->LoadOptions = BootOption->OptionalData;
|
---|
2122 | }
|
---|
2123 |
|
---|
2124 | //
|
---|
2125 | // Clean to NULL because the image is loaded directly from the firmwares boot manager.
|
---|
2126 | //
|
---|
2127 | ImageInfo->ParentHandle = NULL;
|
---|
2128 |
|
---|
2129 | //
|
---|
2130 | // Before calling the image, enable the Watchdog Timer for 5 minutes period
|
---|
2131 | //
|
---|
2132 | gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
|
---|
2133 |
|
---|
2134 | //
|
---|
2135 | // Write boot to OS performance data for UEFI boot
|
---|
2136 | //
|
---|
2137 | PERF_CODE (
|
---|
2138 | BmEndOfBdsPerfCode (NULL, NULL);
|
---|
2139 | );
|
---|
2140 |
|
---|
2141 | REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
|
---|
2142 |
|
---|
2143 | Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);
|
---|
2144 | DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
|
---|
2145 | BootOption->Status = Status;
|
---|
2146 |
|
---|
2147 | //
|
---|
2148 | // Destroy the RAM disk
|
---|
2149 | //
|
---|
2150 | if (RamDiskDevicePath != NULL) {
|
---|
2151 | BmDestroyRamDisk (RamDiskDevicePath);
|
---|
2152 | FreePool (RamDiskDevicePath);
|
---|
2153 | }
|
---|
2154 |
|
---|
2155 | if (EFI_ERROR (Status)) {
|
---|
2156 | //
|
---|
2157 | // Report Status Code with the failure status to indicate that boot failure
|
---|
2158 | //
|
---|
2159 | BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED, Status);
|
---|
2160 | }
|
---|
2161 |
|
---|
2162 | PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32)OptionNumber);
|
---|
2163 |
|
---|
2164 | //
|
---|
2165 | // Clear the Watchdog Timer after the image returns
|
---|
2166 | //
|
---|
2167 | gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
|
---|
2168 |
|
---|
2169 | //
|
---|
2170 | // Set Logo status invalid after trying one boot option
|
---|
2171 | //
|
---|
2172 | BootLogo = NULL;
|
---|
2173 | Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **)&BootLogo);
|
---|
2174 | if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
|
---|
2175 | Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
|
---|
2176 | ASSERT_EFI_ERROR (Status);
|
---|
2177 | }
|
---|
2178 |
|
---|
2179 | //
|
---|
2180 | // Clear Boot Current
|
---|
2181 | //
|
---|
2182 | Status = gRT->SetVariable (
|
---|
2183 | L"BootCurrent",
|
---|
2184 | &gEfiGlobalVariableGuid,
|
---|
2185 | 0,
|
---|
2186 | 0,
|
---|
2187 | NULL
|
---|
2188 | );
|
---|
2189 | //
|
---|
2190 | // Deleting variable with current variable implementation shouldn't fail.
|
---|
2191 | // When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,
|
---|
2192 | // exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.
|
---|
2193 | //
|
---|
2194 | ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
|
---|
2195 | }
|
---|
2196 |
|
---|
2197 | /**
|
---|
2198 | Check whether there is a instance in BlockIoDevicePath, which contain multi device path
|
---|
2199 | instances, has the same partition node with HardDriveDevicePath device path
|
---|
2200 |
|
---|
2201 | @param BlockIoDevicePath Multi device path instances which need to check
|
---|
2202 | @param HardDriveDevicePath A device path which starts with a hard drive media
|
---|
2203 | device path.
|
---|
2204 |
|
---|
2205 | @retval TRUE There is a matched device path instance.
|
---|
2206 | @retval FALSE There is no matched device path instance.
|
---|
2207 |
|
---|
2208 | **/
|
---|
2209 | BOOLEAN
|
---|
2210 | BmMatchPartitionDevicePathNode (
|
---|
2211 | IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
|
---|
2212 | IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
|
---|
2213 | )
|
---|
2214 | {
|
---|
2215 | HARDDRIVE_DEVICE_PATH *Node;
|
---|
2216 |
|
---|
2217 | if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
|
---|
2218 | return FALSE;
|
---|
2219 | }
|
---|
2220 |
|
---|
2221 | //
|
---|
2222 | // Match all the partition device path nodes including the nested partition nodes
|
---|
2223 | //
|
---|
2224 | while (!IsDevicePathEnd (BlockIoDevicePath)) {
|
---|
2225 | if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
|
---|
2226 | (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
|
---|
2227 | )
|
---|
2228 | {
|
---|
2229 | //
|
---|
2230 | // See if the harddrive device path in blockio matches the orig Hard Drive Node
|
---|
2231 | //
|
---|
2232 | Node = (HARDDRIVE_DEVICE_PATH *)BlockIoDevicePath;
|
---|
2233 |
|
---|
2234 | //
|
---|
2235 | // Match Signature and PartitionNumber.
|
---|
2236 | // Unused bytes in Signature are initiaized with zeros.
|
---|
2237 | //
|
---|
2238 | if ((Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
|
---|
2239 | (Node->MBRType == HardDriveDevicePath->MBRType) &&
|
---|
2240 | (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
|
---|
2241 | (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0))
|
---|
2242 | {
|
---|
2243 | return TRUE;
|
---|
2244 | }
|
---|
2245 | }
|
---|
2246 |
|
---|
2247 | BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
|
---|
2248 | }
|
---|
2249 |
|
---|
2250 | return FALSE;
|
---|
2251 | }
|
---|
2252 |
|
---|
2253 | /**
|
---|
2254 | Emuerate all possible bootable medias in the following order:
|
---|
2255 | 1. Removable BlockIo - The boot option only points to the removable media
|
---|
2256 | device, like USB key, DVD, Floppy etc.
|
---|
2257 | 2. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
|
---|
2258 | like HardDisk.
|
---|
2259 | 3. Non-BlockIo SimpleFileSystem - The boot option points to a device supporting
|
---|
2260 | SimpleFileSystem Protocol, but not supporting BlockIo
|
---|
2261 | protocol.
|
---|
2262 | 4. LoadFile - The boot option points to the media supporting
|
---|
2263 | LoadFile protocol.
|
---|
2264 | Reference: UEFI Spec chapter 3.3 Boot Option Variables Default Boot Behavior
|
---|
2265 |
|
---|
2266 | @param BootOptionCount Return the boot option count which has been found.
|
---|
2267 |
|
---|
2268 | @retval Pointer to the boot option array.
|
---|
2269 | **/
|
---|
2270 | EFI_BOOT_MANAGER_LOAD_OPTION *
|
---|
2271 | BmEnumerateBootOptions (
|
---|
2272 | UINTN *BootOptionCount
|
---|
2273 | )
|
---|
2274 | {
|
---|
2275 | EFI_STATUS Status;
|
---|
2276 | EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
|
---|
2277 | UINTN HandleCount;
|
---|
2278 | EFI_HANDLE *Handles;
|
---|
2279 | EFI_BLOCK_IO_PROTOCOL *BlkIo;
|
---|
2280 | UINTN Removable;
|
---|
2281 | UINTN Index;
|
---|
2282 | CHAR16 *Description;
|
---|
2283 |
|
---|
2284 | ASSERT (BootOptionCount != NULL);
|
---|
2285 |
|
---|
2286 | *BootOptionCount = 0;
|
---|
2287 | BootOptions = NULL;
|
---|
2288 |
|
---|
2289 | //
|
---|
2290 | // Parse removable block io followed by fixed block io
|
---|
2291 | //
|
---|
2292 | gBS->LocateHandleBuffer (
|
---|
2293 | ByProtocol,
|
---|
2294 | &gEfiBlockIoProtocolGuid,
|
---|
2295 | NULL,
|
---|
2296 | &HandleCount,
|
---|
2297 | &Handles
|
---|
2298 | );
|
---|
2299 |
|
---|
2300 | for (Removable = 0; Removable < 2; Removable++) {
|
---|
2301 | for (Index = 0; Index < HandleCount; Index++) {
|
---|
2302 | Status = gBS->HandleProtocol (
|
---|
2303 | Handles[Index],
|
---|
2304 | &gEfiBlockIoProtocolGuid,
|
---|
2305 | (VOID **)&BlkIo
|
---|
2306 | );
|
---|
2307 | if (EFI_ERROR (Status)) {
|
---|
2308 | continue;
|
---|
2309 | }
|
---|
2310 |
|
---|
2311 | //
|
---|
2312 | // Skip the logical partitions
|
---|
2313 | //
|
---|
2314 | if (BlkIo->Media->LogicalPartition) {
|
---|
2315 | continue;
|
---|
2316 | }
|
---|
2317 |
|
---|
2318 | //
|
---|
2319 | // Skip the fixed block io then the removable block io
|
---|
2320 | //
|
---|
2321 | if (BlkIo->Media->RemovableMedia == ((Removable == 0) ? FALSE : TRUE)) {
|
---|
2322 | continue;
|
---|
2323 | }
|
---|
2324 |
|
---|
2325 | //
|
---|
2326 | // Skip removable media if not present
|
---|
2327 | //
|
---|
2328 | if ((BlkIo->Media->RemovableMedia == TRUE) &&
|
---|
2329 | (BlkIo->Media->MediaPresent == FALSE))
|
---|
2330 | {
|
---|
2331 | continue;
|
---|
2332 | }
|
---|
2333 |
|
---|
2334 | Description = BmGetBootDescription (Handles[Index]);
|
---|
2335 | BootOptions = ReallocatePool (
|
---|
2336 | sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
|
---|
2337 | sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
|
---|
2338 | BootOptions
|
---|
2339 | );
|
---|
2340 | ASSERT (BootOptions != NULL);
|
---|
2341 |
|
---|
2342 | Status = EfiBootManagerInitializeLoadOption (
|
---|
2343 | &BootOptions[(*BootOptionCount)++],
|
---|
2344 | LoadOptionNumberUnassigned,
|
---|
2345 | LoadOptionTypeBoot,
|
---|
2346 | LOAD_OPTION_ACTIVE,
|
---|
2347 | Description,
|
---|
2348 | DevicePathFromHandle (Handles[Index]),
|
---|
2349 | NULL,
|
---|
2350 | 0
|
---|
2351 | );
|
---|
2352 | ASSERT_EFI_ERROR (Status);
|
---|
2353 |
|
---|
2354 | FreePool (Description);
|
---|
2355 | }
|
---|
2356 | }
|
---|
2357 |
|
---|
2358 | if (HandleCount != 0) {
|
---|
2359 | FreePool (Handles);
|
---|
2360 | }
|
---|
2361 |
|
---|
2362 | //
|
---|
2363 | // Parse simple file system not based on block io
|
---|
2364 | //
|
---|
2365 | gBS->LocateHandleBuffer (
|
---|
2366 | ByProtocol,
|
---|
2367 | &gEfiSimpleFileSystemProtocolGuid,
|
---|
2368 | NULL,
|
---|
2369 | &HandleCount,
|
---|
2370 | &Handles
|
---|
2371 | );
|
---|
2372 | for (Index = 0; Index < HandleCount; Index++) {
|
---|
2373 | Status = gBS->HandleProtocol (
|
---|
2374 | Handles[Index],
|
---|
2375 | &gEfiBlockIoProtocolGuid,
|
---|
2376 | (VOID **)&BlkIo
|
---|
2377 | );
|
---|
2378 | if (!EFI_ERROR (Status)) {
|
---|
2379 | //
|
---|
2380 | // Skip if the file system handle supports a BlkIo protocol, which we've handled in above
|
---|
2381 | //
|
---|
2382 | continue;
|
---|
2383 | }
|
---|
2384 |
|
---|
2385 | Description = BmGetBootDescription (Handles[Index]);
|
---|
2386 | BootOptions = ReallocatePool (
|
---|
2387 | sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
|
---|
2388 | sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
|
---|
2389 | BootOptions
|
---|
2390 | );
|
---|
2391 | ASSERT (BootOptions != NULL);
|
---|
2392 |
|
---|
2393 | Status = EfiBootManagerInitializeLoadOption (
|
---|
2394 | &BootOptions[(*BootOptionCount)++],
|
---|
2395 | LoadOptionNumberUnassigned,
|
---|
2396 | LoadOptionTypeBoot,
|
---|
2397 | LOAD_OPTION_ACTIVE,
|
---|
2398 | Description,
|
---|
2399 | DevicePathFromHandle (Handles[Index]),
|
---|
2400 | NULL,
|
---|
2401 | 0
|
---|
2402 | );
|
---|
2403 | ASSERT_EFI_ERROR (Status);
|
---|
2404 | FreePool (Description);
|
---|
2405 | }
|
---|
2406 |
|
---|
2407 | if (HandleCount != 0) {
|
---|
2408 | FreePool (Handles);
|
---|
2409 | }
|
---|
2410 |
|
---|
2411 | //
|
---|
2412 | // Parse load file protocol
|
---|
2413 | //
|
---|
2414 | gBS->LocateHandleBuffer (
|
---|
2415 | ByProtocol,
|
---|
2416 | &gEfiLoadFileProtocolGuid,
|
---|
2417 | NULL,
|
---|
2418 | &HandleCount,
|
---|
2419 | &Handles
|
---|
2420 | );
|
---|
2421 | for (Index = 0; Index < HandleCount; Index++) {
|
---|
2422 | //
|
---|
2423 | // Ignore BootManagerMenu. its boot option will be created by EfiBootManagerGetBootManagerMenu().
|
---|
2424 | //
|
---|
2425 | if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {
|
---|
2426 | continue;
|
---|
2427 | }
|
---|
2428 |
|
---|
2429 | Description = BmGetBootDescription (Handles[Index]);
|
---|
2430 | BootOptions = ReallocatePool (
|
---|
2431 | sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
|
---|
2432 | sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
|
---|
2433 | BootOptions
|
---|
2434 | );
|
---|
2435 | ASSERT (BootOptions != NULL);
|
---|
2436 |
|
---|
2437 | Status = EfiBootManagerInitializeLoadOption (
|
---|
2438 | &BootOptions[(*BootOptionCount)++],
|
---|
2439 | LoadOptionNumberUnassigned,
|
---|
2440 | LoadOptionTypeBoot,
|
---|
2441 | LOAD_OPTION_ACTIVE,
|
---|
2442 | Description,
|
---|
2443 | DevicePathFromHandle (Handles[Index]),
|
---|
2444 | NULL,
|
---|
2445 | 0
|
---|
2446 | );
|
---|
2447 | ASSERT_EFI_ERROR (Status);
|
---|
2448 | FreePool (Description);
|
---|
2449 | }
|
---|
2450 |
|
---|
2451 | if (HandleCount != 0) {
|
---|
2452 | FreePool (Handles);
|
---|
2453 | }
|
---|
2454 |
|
---|
2455 | BmMakeBootOptionDescriptionUnique (BootOptions, *BootOptionCount);
|
---|
2456 | return BootOptions;
|
---|
2457 | }
|
---|
2458 |
|
---|
2459 | /**
|
---|
2460 | The function enumerates all boot options, creates them and registers them in the BootOrder variable.
|
---|
2461 | **/
|
---|
2462 | VOID
|
---|
2463 | EFIAPI
|
---|
2464 | EfiBootManagerRefreshAllBootOption (
|
---|
2465 | VOID
|
---|
2466 | )
|
---|
2467 | {
|
---|
2468 | EFI_STATUS Status;
|
---|
2469 | EFI_BOOT_MANAGER_LOAD_OPTION *NvBootOptions;
|
---|
2470 | UINTN NvBootOptionCount;
|
---|
2471 | EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
|
---|
2472 | UINTN BootOptionCount;
|
---|
2473 | EFI_BOOT_MANAGER_LOAD_OPTION *UpdatedBootOptions;
|
---|
2474 | UINTN UpdatedBootOptionCount;
|
---|
2475 | UINTN Index;
|
---|
2476 | EDKII_PLATFORM_BOOT_MANAGER_PROTOCOL *PlatformBootManager;
|
---|
2477 |
|
---|
2478 | //
|
---|
2479 | // Optionally refresh the legacy boot option
|
---|
2480 | //
|
---|
2481 | if (mBmRefreshLegacyBootOption != NULL) {
|
---|
2482 | mBmRefreshLegacyBootOption ();
|
---|
2483 | }
|
---|
2484 |
|
---|
2485 | BootOptions = BmEnumerateBootOptions (&BootOptionCount);
|
---|
2486 |
|
---|
2487 | //
|
---|
2488 | // Mark the boot option as added by BDS by setting OptionalData to a special GUID
|
---|
2489 | //
|
---|
2490 | for (Index = 0; Index < BootOptionCount; Index++) {
|
---|
2491 | BootOptions[Index].OptionalData = AllocateCopyPool (sizeof (EFI_GUID), &mBmAutoCreateBootOptionGuid);
|
---|
2492 | BootOptions[Index].OptionalDataSize = sizeof (EFI_GUID);
|
---|
2493 | }
|
---|
2494 |
|
---|
2495 | //
|
---|
2496 | // Locate Platform Boot Options Protocol
|
---|
2497 | //
|
---|
2498 | Status = gBS->LocateProtocol (
|
---|
2499 | &gEdkiiPlatformBootManagerProtocolGuid,
|
---|
2500 | NULL,
|
---|
2501 | (VOID **)&PlatformBootManager
|
---|
2502 | );
|
---|
2503 | if (!EFI_ERROR (Status)) {
|
---|
2504 | //
|
---|
2505 | // If found, call platform specific refresh to all auto enumerated and NV
|
---|
2506 | // boot options.
|
---|
2507 | //
|
---|
2508 | Status = PlatformBootManager->RefreshAllBootOptions (
|
---|
2509 | (CONST EFI_BOOT_MANAGER_LOAD_OPTION *)BootOptions,
|
---|
2510 | (CONST UINTN)BootOptionCount,
|
---|
2511 | &UpdatedBootOptions,
|
---|
2512 | &UpdatedBootOptionCount
|
---|
2513 | );
|
---|
2514 | if (!EFI_ERROR (Status)) {
|
---|
2515 | EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
|
---|
2516 | BootOptions = UpdatedBootOptions;
|
---|
2517 | BootOptionCount = UpdatedBootOptionCount;
|
---|
2518 | }
|
---|
2519 | }
|
---|
2520 |
|
---|
2521 | NvBootOptions = EfiBootManagerGetLoadOptions (&NvBootOptionCount, LoadOptionTypeBoot);
|
---|
2522 |
|
---|
2523 | //
|
---|
2524 | // Remove invalid EFI boot options from NV
|
---|
2525 | //
|
---|
2526 | for (Index = 0; Index < NvBootOptionCount; Index++) {
|
---|
2527 | if (((DevicePathType (NvBootOptions[Index].FilePath) != BBS_DEVICE_PATH) ||
|
---|
2528 | (DevicePathSubType (NvBootOptions[Index].FilePath) != BBS_BBS_DP)
|
---|
2529 | ) && BmIsAutoCreateBootOption (&NvBootOptions[Index])
|
---|
2530 | )
|
---|
2531 | {
|
---|
2532 | //
|
---|
2533 | // Only check those added by BDS
|
---|
2534 | // so that the boot options added by end-user or OS installer won't be deleted
|
---|
2535 | //
|
---|
2536 | if (EfiBootManagerFindLoadOption (&NvBootOptions[Index], BootOptions, BootOptionCount) == -1) {
|
---|
2537 | Status = EfiBootManagerDeleteLoadOptionVariable (NvBootOptions[Index].OptionNumber, LoadOptionTypeBoot);
|
---|
2538 | //
|
---|
2539 | // Deleting variable with current variable implementation shouldn't fail.
|
---|
2540 | //
|
---|
2541 | ASSERT_EFI_ERROR (Status);
|
---|
2542 | }
|
---|
2543 | }
|
---|
2544 | }
|
---|
2545 |
|
---|
2546 | //
|
---|
2547 | // Add new EFI boot options to NV
|
---|
2548 | //
|
---|
2549 | for (Index = 0; Index < BootOptionCount; Index++) {
|
---|
2550 | if (EfiBootManagerFindLoadOption (&BootOptions[Index], NvBootOptions, NvBootOptionCount) == -1) {
|
---|
2551 | EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN)-1);
|
---|
2552 | //
|
---|
2553 | // Try best to add the boot options so continue upon failure.
|
---|
2554 | //
|
---|
2555 | }
|
---|
2556 | }
|
---|
2557 |
|
---|
2558 | EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
|
---|
2559 | EfiBootManagerFreeLoadOptions (NvBootOptions, NvBootOptionCount);
|
---|
2560 | }
|
---|
2561 |
|
---|
2562 | /**
|
---|
2563 | This function is called to get or create the boot option for the Boot Manager Menu.
|
---|
2564 |
|
---|
2565 | The Boot Manager Menu is shown after successfully booting a boot option.
|
---|
2566 | This function will first try to search the BootManagerMenuFile is in the same FV as
|
---|
2567 | the module links to this library. If fails, it will search in all FVs.
|
---|
2568 |
|
---|
2569 | @param BootOption Return the boot option of the Boot Manager Menu
|
---|
2570 |
|
---|
2571 | @retval EFI_SUCCESS Successfully register the Boot Manager Menu.
|
---|
2572 | @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
|
---|
2573 | @retval others Return status of gRT->SetVariable (). BootOption still points
|
---|
2574 | to the Boot Manager Menu even the Status is not EFI_SUCCESS
|
---|
2575 | and EFI_NOT_FOUND.
|
---|
2576 | **/
|
---|
2577 | EFI_STATUS
|
---|
2578 | BmRegisterBootManagerMenu (
|
---|
2579 | OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
|
---|
2580 | )
|
---|
2581 | {
|
---|
2582 | EFI_STATUS Status;
|
---|
2583 | CHAR16 *Description;
|
---|
2584 | UINTN DescriptionLength;
|
---|
2585 | EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
---|
2586 | UINTN HandleCount;
|
---|
2587 | EFI_HANDLE *Handles;
|
---|
2588 | UINTN Index;
|
---|
2589 |
|
---|
2590 | DevicePath = NULL;
|
---|
2591 | Description = NULL;
|
---|
2592 | //
|
---|
2593 | // Try to find BootManagerMenu from LoadFile protocol
|
---|
2594 | //
|
---|
2595 | gBS->LocateHandleBuffer (
|
---|
2596 | ByProtocol,
|
---|
2597 | &gEfiLoadFileProtocolGuid,
|
---|
2598 | NULL,
|
---|
2599 | &HandleCount,
|
---|
2600 | &Handles
|
---|
2601 | );
|
---|
2602 | for (Index = 0; Index < HandleCount; Index++) {
|
---|
2603 | if (BmIsBootManagerMenuFilePath (DevicePathFromHandle (Handles[Index]))) {
|
---|
2604 | DevicePath = DuplicateDevicePath (DevicePathFromHandle (Handles[Index]));
|
---|
2605 | Description = BmGetBootDescription (Handles[Index]);
|
---|
2606 | break;
|
---|
2607 | }
|
---|
2608 | }
|
---|
2609 |
|
---|
2610 | if (HandleCount != 0) {
|
---|
2611 | FreePool (Handles);
|
---|
2612 | }
|
---|
2613 |
|
---|
2614 | if (DevicePath == NULL) {
|
---|
2615 | Status = GetFileDevicePathFromAnyFv (
|
---|
2616 | PcdGetPtr (PcdBootManagerMenuFile),
|
---|
2617 | EFI_SECTION_PE32,
|
---|
2618 | 0,
|
---|
2619 | &DevicePath
|
---|
2620 | );
|
---|
2621 | if (EFI_ERROR (Status)) {
|
---|
2622 | DEBUG ((DEBUG_WARN, "[Bds]BootManagerMenu FFS section can not be found, skip its boot option registration\n"));
|
---|
2623 | return EFI_NOT_FOUND;
|
---|
2624 | }
|
---|
2625 |
|
---|
2626 | ASSERT (DevicePath != NULL);
|
---|
2627 | //
|
---|
2628 | // Get BootManagerMenu application's description from EFI User Interface Section.
|
---|
2629 | //
|
---|
2630 | Status = GetSectionFromAnyFv (
|
---|
2631 | PcdGetPtr (PcdBootManagerMenuFile),
|
---|
2632 | EFI_SECTION_USER_INTERFACE,
|
---|
2633 | 0,
|
---|
2634 | (VOID **)&Description,
|
---|
2635 | &DescriptionLength
|
---|
2636 | );
|
---|
2637 | if (EFI_ERROR (Status)) {
|
---|
2638 | Description = NULL;
|
---|
2639 | }
|
---|
2640 | }
|
---|
2641 |
|
---|
2642 | Status = EfiBootManagerInitializeLoadOption (
|
---|
2643 | BootOption,
|
---|
2644 | LoadOptionNumberUnassigned,
|
---|
2645 | LoadOptionTypeBoot,
|
---|
2646 | LOAD_OPTION_CATEGORY_APP | LOAD_OPTION_ACTIVE | LOAD_OPTION_HIDDEN,
|
---|
2647 | (Description != NULL) ? Description : L"Boot Manager Menu",
|
---|
2648 | DevicePath,
|
---|
2649 | NULL,
|
---|
2650 | 0
|
---|
2651 | );
|
---|
2652 | ASSERT_EFI_ERROR (Status);
|
---|
2653 | FreePool (DevicePath);
|
---|
2654 | if (Description != NULL) {
|
---|
2655 | FreePool (Description);
|
---|
2656 | }
|
---|
2657 |
|
---|
2658 | DEBUG_CODE (
|
---|
2659 | EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
|
---|
2660 | UINTN BootOptionCount;
|
---|
2661 |
|
---|
2662 | BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
|
---|
2663 | ASSERT (EfiBootManagerFindLoadOption (BootOption, BootOptions, BootOptionCount) == -1);
|
---|
2664 | EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
|
---|
2665 | );
|
---|
2666 |
|
---|
2667 | return EfiBootManagerAddLoadOptionVariable (BootOption, (UINTN)-1);
|
---|
2668 | }
|
---|
2669 |
|
---|
2670 | /**
|
---|
2671 | Return the boot option corresponding to the Boot Manager Menu.
|
---|
2672 | It may automatically create one if the boot option hasn't been created yet.
|
---|
2673 |
|
---|
2674 | @param BootOption Return the Boot Manager Menu.
|
---|
2675 |
|
---|
2676 | @retval EFI_SUCCESS The Boot Manager Menu is successfully returned.
|
---|
2677 | @retval EFI_NOT_FOUND The Boot Manager Menu cannot be found.
|
---|
2678 | @retval others Return status of gRT->SetVariable (). BootOption still points
|
---|
2679 | to the Boot Manager Menu even the Status is not EFI_SUCCESS
|
---|
2680 | and EFI_NOT_FOUND.
|
---|
2681 | **/
|
---|
2682 | EFI_STATUS
|
---|
2683 | EFIAPI
|
---|
2684 | EfiBootManagerGetBootManagerMenu (
|
---|
2685 | EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
|
---|
2686 | )
|
---|
2687 | {
|
---|
2688 | EFI_STATUS Status;
|
---|
2689 | UINTN BootOptionCount;
|
---|
2690 | EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
|
---|
2691 | UINTN Index;
|
---|
2692 |
|
---|
2693 | BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
|
---|
2694 |
|
---|
2695 | for (Index = 0; Index < BootOptionCount; Index++) {
|
---|
2696 | if (BmIsBootManagerMenuFilePath (BootOptions[Index].FilePath)) {
|
---|
2697 | Status = EfiBootManagerInitializeLoadOption (
|
---|
2698 | BootOption,
|
---|
2699 | BootOptions[Index].OptionNumber,
|
---|
2700 | BootOptions[Index].OptionType,
|
---|
2701 | BootOptions[Index].Attributes,
|
---|
2702 | BootOptions[Index].Description,
|
---|
2703 | BootOptions[Index].FilePath,
|
---|
2704 | BootOptions[Index].OptionalData,
|
---|
2705 | BootOptions[Index].OptionalDataSize
|
---|
2706 | );
|
---|
2707 | ASSERT_EFI_ERROR (Status);
|
---|
2708 | break;
|
---|
2709 | }
|
---|
2710 | }
|
---|
2711 |
|
---|
2712 | EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
|
---|
2713 |
|
---|
2714 | //
|
---|
2715 | // Automatically create the Boot#### for Boot Manager Menu when not found.
|
---|
2716 | //
|
---|
2717 | if (Index == BootOptionCount) {
|
---|
2718 | return BmRegisterBootManagerMenu (BootOption);
|
---|
2719 | } else {
|
---|
2720 | return EFI_SUCCESS;
|
---|
2721 | }
|
---|
2722 | }
|
---|
2723 |
|
---|
2724 | /**
|
---|
2725 | Get the next possible full path pointing to the load option.
|
---|
2726 | The routine doesn't guarantee the returned full path points to an existing
|
---|
2727 | file, and it also doesn't guarantee the existing file is a valid load option.
|
---|
2728 | BmGetNextLoadOptionBuffer() guarantees.
|
---|
2729 |
|
---|
2730 | @param FilePath The device path pointing to a load option.
|
---|
2731 | It could be a short-form device path.
|
---|
2732 | @param FullPath The full path returned by the routine in last call.
|
---|
2733 | Set to NULL in first call.
|
---|
2734 |
|
---|
2735 | @return The next possible full path pointing to the load option.
|
---|
2736 | Caller is responsible to free the memory.
|
---|
2737 | **/
|
---|
2738 | EFI_DEVICE_PATH_PROTOCOL *
|
---|
2739 | EFIAPI
|
---|
2740 | EfiBootManagerGetNextLoadOptionDevicePath (
|
---|
2741 | IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
|
---|
2742 | IN EFI_DEVICE_PATH_PROTOCOL *FullPath
|
---|
2743 | )
|
---|
2744 | {
|
---|
2745 | return BmGetNextLoadOptionDevicePath (FilePath, FullPath);
|
---|
2746 | }
|
---|