]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c
MdeModulePkg UefiBootManagerLib: Support LoadFile Protocol based on FV
[mirror_edk2.git] / MdeModulePkg / Library / UefiBootManagerLib / BmBootDescription.c
CommitLineData
1f2e80af
RN
1/** @file\r
2 Library functions which relate with boot option description.\r
3\r
4Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>\r
5(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "InternalBm.h"\r
17\r
18#define VENDOR_IDENTIFICATION_OFFSET 3\r
19#define VENDOR_IDENTIFICATION_LENGTH 8\r
20#define PRODUCT_IDENTIFICATION_OFFSET 11\r
21#define PRODUCT_IDENTIFICATION_LENGTH 16\r
22\r
23CONST UINT16 mBmUsbLangId = 0x0409; // English\r
24CHAR16 mBmUefiPrefix[] = L"UEFI ";\r
25\r
26LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers);\r
27\r
28/**\r
29 For a bootable Device path, return its boot type.\r
30\r
e4c7cefe
RN
31 @param DevicePath The bootable device Path to check\r
32\r
33 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node\r
34 which HID is floppy device.\r
35 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
36 and its last device path node's subtype is MSG_ATAPI_DP.\r
37 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
38 and its last device path node's subtype is MSG_SATA_DP.\r
39 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
40 and its last device path node's subtype is MSG_SCSI_DP.\r
41 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node\r
42 and its last device path node's subtype is MSG_USB_DP.\r
43 @retval BmMiscBoot If tiven device path doesn't match the above condition.\r
1f2e80af
RN
44\r
45**/\r
46BM_BOOT_TYPE\r
47BmDevicePathType (\r
48 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
49 )\r
50{\r
51 EFI_DEVICE_PATH_PROTOCOL *Node;\r
52 EFI_DEVICE_PATH_PROTOCOL *NextNode;\r
53\r
54 ASSERT (DevicePath != NULL);\r
55\r
56 for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {\r
57 switch (DevicePathType (Node)) {\r
58\r
59 case ACPI_DEVICE_PATH:\r
60 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *) Node)->HID) == 0x0604) {\r
61 return BmAcpiFloppyBoot;\r
62 }\r
63 break;\r
64\r
65 case HARDWARE_DEVICE_PATH:\r
66 if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {\r
67 return BmHardwareDeviceBoot;\r
68 }\r
69 break;\r
70\r
71 case MESSAGING_DEVICE_PATH:\r
72 //\r
73 // Skip LUN device node\r
74 //\r
75 NextNode = Node;\r
76 do {\r
77 NextNode = NextDevicePathNode (NextNode);\r
78 } while (\r
79 (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&\r
80 (DevicePathSubType(NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)\r
81 );\r
82\r
83 //\r
84 // If the device path not only point to driver device, it is not a messaging device path,\r
85 //\r
86 if (!IsDevicePathEndType (NextNode)) {\r
87 continue;\r
88 }\r
89\r
90 switch (DevicePathSubType (Node)) {\r
91 case MSG_ATAPI_DP:\r
92 return BmMessageAtapiBoot;\r
93 break;\r
94\r
95 case MSG_SATA_DP:\r
96 return BmMessageSataBoot;\r
97 break;\r
98\r
99 case MSG_USB_DP:\r
100 return BmMessageUsbBoot;\r
101 break;\r
102\r
103 case MSG_SCSI_DP:\r
104 return BmMessageScsiBoot;\r
105 break;\r
1f2e80af
RN
106 }\r
107 }\r
108 }\r
109\r
110 return BmMiscBoot;\r
111}\r
112\r
113/**\r
114 Eliminate the extra spaces in the Str to one space.\r
115\r
116 @param Str Input string info.\r
117**/\r
118VOID\r
119BmEliminateExtraSpaces (\r
120 IN CHAR16 *Str\r
121 )\r
122{\r
123 UINTN Index;\r
124 UINTN ActualIndex;\r
125\r
126 for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {\r
127 if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {\r
128 Str[ActualIndex++] = Str[Index];\r
129 }\r
130 }\r
131 Str[ActualIndex] = L'\0';\r
132}\r
133\r
134/**\r
135 Try to get the controller's ATA/ATAPI description.\r
136\r
137 @param Handle Controller handle.\r
138\r
139 @return The description string.\r
140**/\r
141CHAR16 *\r
142BmGetDescriptionFromDiskInfo (\r
143 IN EFI_HANDLE Handle\r
144 )\r
145{\r
146 UINTN Index;\r
147 EFI_STATUS Status;\r
148 EFI_DISK_INFO_PROTOCOL *DiskInfo;\r
149 UINT32 BufferSize;\r
150 EFI_ATAPI_IDENTIFY_DATA IdentifyData;\r
151 EFI_SCSI_INQUIRY_DATA InquiryData;\r
152 CHAR16 *Description;\r
153 UINTN Length;\r
154 CONST UINTN ModelNameLength = 40;\r
155 CONST UINTN SerialNumberLength = 20;\r
156 CHAR8 *StrPtr;\r
157 UINT8 Temp;\r
158\r
159 Description = NULL;\r
160\r
161 Status = gBS->HandleProtocol (\r
162 Handle,\r
163 &gEfiDiskInfoProtocolGuid,\r
164 (VOID **) &DiskInfo\r
165 );\r
166 if (EFI_ERROR (Status)) {\r
167 return NULL;\r
168 }\r
169\r
170 if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) ||\r
171 CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {\r
172 BufferSize = sizeof (EFI_ATAPI_IDENTIFY_DATA);\r
173 Status = DiskInfo->Identify (\r
174 DiskInfo,\r
175 &IdentifyData,\r
176 &BufferSize\r
177 );\r
178 if (!EFI_ERROR (Status)) {\r
179 Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));\r
180 ASSERT (Description != NULL);\r
181 for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {\r
182 Description[Index] = (CHAR16) IdentifyData.ModelName[Index + 1];\r
183 Description[Index + 1] = (CHAR16) IdentifyData.ModelName[Index];\r
184 }\r
185\r
186 Length = Index;\r
187 Description[Length++] = L' ';\r
188\r
189 for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {\r
190 Description[Length + Index] = (CHAR16) IdentifyData.SerialNo[Index + 1];\r
191 Description[Length + Index + 1] = (CHAR16) IdentifyData.SerialNo[Index];\r
192 }\r
193 Length += Index;\r
194 Description[Length++] = L'\0';\r
195 ASSERT (Length == ModelNameLength + SerialNumberLength + 2);\r
196\r
197 BmEliminateExtraSpaces (Description);\r
198 }\r
199 } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {\r
200 BufferSize = sizeof (EFI_SCSI_INQUIRY_DATA);\r
201 Status = DiskInfo->Inquiry (\r
202 DiskInfo,\r
203 &InquiryData,\r
204 &BufferSize\r
205 );\r
206 if (!EFI_ERROR (Status)) {\r
207 Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));\r
208 ASSERT (Description != NULL);\r
209\r
210 //\r
211 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification\r
212 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,\r
213 // Here combine the vendor identification and product identification to the description.\r
214 //\r
215 StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);\r
216 Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];\r
217 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';\r
b68ccac1 218 AsciiStrToUnicodeStrS (StrPtr, Description, VENDOR_IDENTIFICATION_LENGTH + 1);\r
1f2e80af
RN
219 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;\r
220\r
221 //\r
222 // Add one space at the middle of vendor information and product information.\r
223 //\r
224 Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';\r
225\r
226 StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);\r
227 StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';\r
b68ccac1 228 AsciiStrToUnicodeStrS (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1, PRODUCT_IDENTIFICATION_LENGTH + 1);\r
1f2e80af
RN
229\r
230 BmEliminateExtraSpaces (Description);\r
231 }\r
232 }\r
233\r
234 return Description;\r
235}\r
236\r
237/**\r
238 Try to get the controller's USB description.\r
239\r
240 @param Handle Controller handle.\r
241\r
242 @return The description string.\r
243**/\r
244CHAR16 *\r
245BmGetUsbDescription (\r
246 IN EFI_HANDLE Handle\r
247 )\r
248{\r
249 EFI_STATUS Status;\r
250 EFI_USB_IO_PROTOCOL *UsbIo;\r
251 CHAR16 NullChar;\r
252 CHAR16 *Manufacturer;\r
253 CHAR16 *Product;\r
254 CHAR16 *SerialNumber;\r
255 CHAR16 *Description;\r
256 EFI_USB_DEVICE_DESCRIPTOR DevDesc;\r
257 UINTN DescMaxSize;\r
258\r
259 Status = gBS->HandleProtocol (\r
260 Handle,\r
261 &gEfiUsbIoProtocolGuid,\r
262 (VOID **) &UsbIo\r
263 );\r
264 if (EFI_ERROR (Status)) {\r
265 return NULL;\r
266 }\r
267\r
268 NullChar = L'\0';\r
269\r
270 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);\r
271 if (EFI_ERROR (Status)) {\r
272 return NULL;\r
273 }\r
274\r
275 Status = UsbIo->UsbGetStringDescriptor (\r
276 UsbIo,\r
277 mBmUsbLangId,\r
278 DevDesc.StrManufacturer,\r
279 &Manufacturer\r
280 );\r
281 if (EFI_ERROR (Status)) {\r
282 Manufacturer = &NullChar;\r
283 }\r
284\r
285 Status = UsbIo->UsbGetStringDescriptor (\r
286 UsbIo,\r
287 mBmUsbLangId,\r
288 DevDesc.StrProduct,\r
289 &Product\r
290 );\r
291 if (EFI_ERROR (Status)) {\r
292 Product = &NullChar;\r
293 }\r
294\r
295 Status = UsbIo->UsbGetStringDescriptor (\r
296 UsbIo,\r
297 mBmUsbLangId,\r
298 DevDesc.StrSerialNumber,\r
299 &SerialNumber\r
300 );\r
301 if (EFI_ERROR (Status)) {\r
302 SerialNumber = &NullChar;\r
303 }\r
304\r
305 if ((Manufacturer == &NullChar) &&\r
306 (Product == &NullChar) &&\r
307 (SerialNumber == &NullChar)\r
308 ) {\r
309 return NULL;\r
310 }\r
311\r
312 DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber);\r
313 Description = AllocateZeroPool (DescMaxSize);\r
314 ASSERT (Description != NULL);\r
315 StrCatS (Description, DescMaxSize/sizeof(CHAR16), Manufacturer);\r
316 StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");\r
317\r
318 StrCatS (Description, DescMaxSize/sizeof(CHAR16), Product);\r
319 StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");\r
320\r
321 StrCatS (Description, DescMaxSize/sizeof(CHAR16), SerialNumber);\r
322\r
323 if (Manufacturer != &NullChar) {\r
324 FreePool (Manufacturer);\r
325 }\r
326 if (Product != &NullChar) {\r
327 FreePool (Product);\r
328 }\r
329 if (SerialNumber != &NullChar) {\r
330 FreePool (SerialNumber);\r
331 }\r
332\r
333 BmEliminateExtraSpaces (Description);\r
334\r
335 return Description;\r
336}\r
337\r
e4c7cefe
RN
338/**\r
339 Return the description for network boot device.\r
340\r
341 @param Handle Controller handle.\r
342\r
343 @return The description string.\r
344**/\r
345CHAR16 *\r
346BmGetNetworkDescription (\r
347 IN EFI_HANDLE Handle\r
348 )\r
349{\r
350 EFI_STATUS Status;\r
351 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
352 MAC_ADDR_DEVICE_PATH *Mac;\r
353 VLAN_DEVICE_PATH *Vlan;\r
354 EFI_DEVICE_PATH_PROTOCOL *Ip;\r
355 EFI_DEVICE_PATH_PROTOCOL *Uri;\r
356 CHAR16 *Description;\r
357 UINTN DescriptionSize;\r
358\r
359 Status = gBS->OpenProtocol (\r
360 Handle,\r
361 &gEfiLoadFileProtocolGuid,\r
362 NULL,\r
363 gImageHandle,\r
364 Handle,\r
365 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
366 );\r
367 if (EFI_ERROR (Status)) {\r
368 return NULL;\r
369 }\r
370\r
371 Status = gBS->OpenProtocol (\r
372 Handle,\r
373 &gEfiDevicePathProtocolGuid,\r
374 (VOID **) &DevicePath,\r
375 gImageHandle,\r
376 Handle,\r
377 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
378 );\r
379 if (EFI_ERROR (Status) || (DevicePath == NULL)) {\r
380 return NULL;\r
381 }\r
382\r
383 //\r
384 // The PXE device path is like:\r
385 // ....../Mac(...)[/Vlan(...)]\r
386 // ....../Mac(...)[/Vlan(...)]/IPv4(...)\r
387 // ....../Mac(...)[/Vlan(...)]/IPv6(...)\r
388 //\r
389 // The HTTP device path is like:\r
390 // ....../Mac(...)[/Vlan(...)]/IPv4(...)/Uri(...)\r
391 // ....../Mac(...)[/Vlan(...)]/IPv6(...)/Uri(...)\r
392 //\r
393 while (!IsDevicePathEnd (DevicePath) &&\r
394 ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||\r
395 (DevicePathSubType (DevicePath) != MSG_MAC_ADDR_DP))\r
396 ) {\r
397 DevicePath = NextDevicePathNode (DevicePath);\r
398 }\r
399\r
400 if (IsDevicePathEnd (DevicePath)) {\r
401 return NULL;\r
402 }\r
403\r
404 Mac = (MAC_ADDR_DEVICE_PATH *) DevicePath;\r
405 DevicePath = NextDevicePathNode (DevicePath);\r
406\r
407 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
408 (DevicePathSubType (DevicePath) == MSG_VLAN_DP)\r
409 ) {\r
410 Vlan = (VLAN_DEVICE_PATH *) DevicePath;\r
411 DevicePath = NextDevicePathNode (DevicePath);\r
412 } else {\r
413 Vlan = NULL;\r
414 }\r
415\r
416 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
417 ((DevicePathSubType (DevicePath) == MSG_IPv4_DP) ||\r
418 (DevicePathSubType (DevicePath) == MSG_IPv6_DP))\r
419 ) {\r
420 Ip = DevicePath;\r
421 DevicePath = NextDevicePathNode (DevicePath);\r
422 } else {\r
423 Ip = NULL;\r
424 }\r
425\r
426 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&\r
427 (DevicePathSubType (DevicePath) == MSG_URI_DP)\r
428 ) {\r
429 Uri = DevicePath;\r
430 DevicePath = NextDevicePathNode (DevicePath);\r
431 } else {\r
432 Uri = NULL;\r
433 }\r
434\r
435 //\r
436 // Build description like below:\r
437 // "PXEv6 (MAC:112233445566 VLAN1)"\r
438 // "HTTPv4 (MAC:112233445566)"\r
439 //\r
440 DescriptionSize = sizeof (L"HTTPv6 (MAC:112233445566 VLAN65535)");\r
441 Description = AllocatePool (DescriptionSize);\r
442 ASSERT (Description != NULL);\r
443 UnicodeSPrint (\r
444 Description, DescriptionSize,\r
445 (Vlan == NULL) ?\r
446 L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :\r
447 L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",\r
448 (Uri == NULL) ? L"PXE" : L"HTTP",\r
449 ((Ip == NULL) || (DevicePathSubType (Ip) == MSG_IPv4_DP)) ? 4 : 6,\r
450 Mac->MacAddress.Addr[0], Mac->MacAddress.Addr[1], Mac->MacAddress.Addr[2],\r
451 Mac->MacAddress.Addr[3], Mac->MacAddress.Addr[4], Mac->MacAddress.Addr[5],\r
452 (Vlan == NULL) ? 0 : Vlan->VlanId\r
453 );\r
454 return Description;\r
455}\r
456\r
1f2e80af
RN
457/**\r
458 Return the boot description for the controller based on the type.\r
459\r
460 @param Handle Controller handle.\r
461\r
462 @return The description string.\r
463**/\r
464CHAR16 *\r
465BmGetMiscDescription (\r
466 IN EFI_HANDLE Handle\r
467 )\r
468{\r
469 EFI_STATUS Status;\r
470 CHAR16 *Description;\r
471 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
472 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
473\r
474 switch (BmDevicePathType (DevicePathFromHandle (Handle))) {\r
475 case BmAcpiFloppyBoot:\r
476 Description = L"Floppy";\r
477 break;\r
478\r
479 case BmMessageAtapiBoot:\r
480 case BmMessageSataBoot:\r
481 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
482 ASSERT_EFI_ERROR (Status);\r
483 //\r
484 // Assume a removable SATA device should be the DVD/CD device\r
485 //\r
486 Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";\r
487 break;\r
488\r
489 case BmMessageUsbBoot:\r
490 Description = L"USB Device";\r
491 break;\r
492\r
493 case BmMessageScsiBoot:\r
494 Description = L"SCSI Device";\r
495 break;\r
496\r
497 case BmHardwareDeviceBoot:\r
498 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);\r
499 if (!EFI_ERROR (Status)) {\r
500 Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";\r
501 } else {\r
502 Description = L"Misc Device";\r
503 }\r
504 break;\r
505\r
1f2e80af
RN
506 default:\r
507 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs);\r
508 if (!EFI_ERROR (Status)) {\r
509 Description = L"Non-Block Boot Device";\r
510 } else {\r
511 Description = L"Misc Device";\r
512 }\r
513 break;\r
514 }\r
515\r
516 return AllocateCopyPool (StrSize (Description), Description);\r
517}\r
518\r
519/**\r
520 Register the platform provided boot description handler.\r
521\r
522 @param Handler The platform provided boot description handler\r
523\r
524 @retval EFI_SUCCESS The handler was registered successfully.\r
525 @retval EFI_ALREADY_STARTED The handler was already registered.\r
526 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.\r
527**/\r
528EFI_STATUS\r
529EFIAPI\r
530EfiBootManagerRegisterBootDescriptionHandler (\r
531 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler\r
532 )\r
533{\r
534 LIST_ENTRY *Link;\r
535 BM_BOOT_DESCRIPTION_ENTRY *Entry;\r
536\r
537 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)\r
538 ; !IsNull (&mPlatformBootDescriptionHandlers, Link)\r
539 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)\r
540 ) {\r
541 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);\r
542 if (Entry->Handler == Handler) {\r
543 return EFI_ALREADY_STARTED;\r
544 }\r
545 }\r
546\r
547 Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY));\r
548 if (Entry == NULL) {\r
549 return EFI_OUT_OF_RESOURCES;\r
550 }\r
551\r
552 Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE;\r
553 Entry->Handler = Handler;\r
554 InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link);\r
555 return EFI_SUCCESS;\r
556}\r
557\r
558BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {\r
559 BmGetUsbDescription,\r
560 BmGetDescriptionFromDiskInfo,\r
e4c7cefe 561 BmGetNetworkDescription,\r
1f2e80af
RN
562 BmGetMiscDescription\r
563};\r
564\r
565/**\r
566 Return the boot description for the controller.\r
567\r
568 @param Handle Controller handle.\r
569\r
570 @return The description string.\r
571**/\r
572CHAR16 *\r
573BmGetBootDescription (\r
574 IN EFI_HANDLE Handle\r
575 )\r
576{\r
577 LIST_ENTRY *Link;\r
578 BM_BOOT_DESCRIPTION_ENTRY *Entry;\r
579 CHAR16 *Description;\r
580 CHAR16 *DefaultDescription;\r
581 CHAR16 *Temp;\r
582 UINTN Index;\r
583\r
584 //\r
585 // Firstly get the default boot description\r
586 //\r
587 DefaultDescription = NULL;\r
588 for (Index = 0; Index < sizeof (mBmBootDescriptionHandlers) / sizeof (mBmBootDescriptionHandlers[0]); Index++) {\r
589 DefaultDescription = mBmBootDescriptionHandlers[Index] (Handle);\r
590 if (DefaultDescription != NULL) {\r
591 //\r
592 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix\r
593 // ONLY for core provided boot description handler.\r
594 //\r
595 Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix));\r
596 ASSERT (Temp != NULL);\r
597 StrCpyS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), mBmUefiPrefix);\r
598 StrCatS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), DefaultDescription);\r
599 FreePool (DefaultDescription);\r
600 DefaultDescription = Temp;\r
601 break;\r
602 }\r
603 }\r
604 ASSERT (DefaultDescription != NULL);\r
605\r
606 //\r
607 // Secondly query platform for the better boot description\r
608 //\r
609 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)\r
610 ; !IsNull (&mPlatformBootDescriptionHandlers, Link)\r
611 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)\r
612 ) {\r
613 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);\r
614 Description = Entry->Handler (Handle, DefaultDescription);\r
615 if (Description != NULL) {\r
616 FreePool (DefaultDescription);\r
617 return Description;\r
618 }\r
619 }\r
620\r
621 return DefaultDescription;\r
622}\r
623\r
624/**\r
625 Enumerate all boot option descriptions and append " 2"/" 3"/... to make\r
626 unique description.\r
627\r
628 @param BootOptions Array of boot options.\r
629 @param BootOptionCount Count of boot options.\r
630**/\r
631VOID\r
632BmMakeBootOptionDescriptionUnique (\r
633 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,\r
634 UINTN BootOptionCount\r
635 )\r
636{\r
637 UINTN Base;\r
638 UINTN Index;\r
639 UINTN DescriptionSize;\r
640 UINTN MaxSuffixSize;\r
641 BOOLEAN *Visited;\r
642 UINTN MatchCount;\r
643\r
644 if (BootOptionCount == 0) {\r
645 return;\r
646 }\r
647\r
648 //\r
649 // Calculate the maximum buffer size for the number suffix.\r
650 // The initial sizeof (CHAR16) is for the blank space before the number.\r
651 //\r
652 MaxSuffixSize = sizeof (CHAR16);\r
653 for (Index = BootOptionCount; Index != 0; Index = Index / 10) {\r
654 MaxSuffixSize += sizeof (CHAR16);\r
655 }\r
656\r
657 Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);\r
658 ASSERT (Visited != NULL);\r
659\r
660 for (Base = 0; Base < BootOptionCount; Base++) {\r
661 if (!Visited[Base]) {\r
662 MatchCount = 1;\r
663 Visited[Base] = TRUE;\r
664 DescriptionSize = StrSize (BootOptions[Base].Description);\r
665 for (Index = Base + 1; Index < BootOptionCount; Index++) {\r
666 if (!Visited[Index] && StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0) {\r
667 Visited[Index] = TRUE;\r
668 MatchCount++;\r
669 FreePool (BootOptions[Index].Description);\r
670 BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);\r
671 UnicodeSPrint (\r
672 BootOptions[Index].Description, DescriptionSize + MaxSuffixSize,\r
673 L"%s %d",\r
674 BootOptions[Base].Description, MatchCount\r
675 );\r
676 }\r
677 }\r
678 }\r
679 }\r
680\r
681 FreePool (Visited);\r
682}\r