VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c@ 109019

Last change on this file since 109019 was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 33.1 KB
Line 
1/** @file
2 Library functions which relate with boot option description.
3
4Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "InternalBm.h"
11
12#define VENDOR_IDENTIFICATION_OFFSET 3
13#define VENDOR_IDENTIFICATION_LENGTH 8
14#define PRODUCT_IDENTIFICATION_OFFSET 11
15#define PRODUCT_IDENTIFICATION_LENGTH 16
16
17CONST UINT16 mBmUsbLangId = 0x0409; // English
18CHAR16 mBmUefiPrefix[] = L"UEFI ";
19
20CHAR16 mBootDescGenericManufacturer[] = L"Generic";
21CHAR16 mBootDescSd[] = L"SD Device";
22CHAR16 mBootDescEmmc[] = L"eMMC Device";
23CHAR16 mBootDescEmmcUserData[] = L"eMMC User Data";
24CHAR16 mBootDescEmmcBoot1[] = L"eMMC Boot 1";
25CHAR16 mBootDescEmmcBoot2[] = L"eMMC Boot 2";
26CHAR16 mBootDescEmmcGp1[] = L"eMMC GP 1";
27CHAR16 mBootDescEmmcGp2[] = L"eMMC GP 2";
28CHAR16 mBootDescEmmcGp3[] = L"eMMC GP 3";
29CHAR16 mBootDescEmmcGp4[] = L"eMMC GP 4";
30
31typedef struct {
32 UINT8 Id;
33 CHAR16 *Name;
34} BM_SDMMC_MANUFACTURER;
35
36BM_SDMMC_MANUFACTURER mSdManufacturers[] = {
37 { 0x01, L"Panasonic" },
38 { 0x02, L"Toshiba/Kingston/Viking" },
39 { 0x03, L"SanDisk" },
40 { 0x08, L"Silicon Power" },
41 { 0x18, L"Infineon" },
42 { 0x1b, L"Transcend/Samsung" },
43 { 0x1c, L"Transcend" },
44 { 0x1d, L"Corsair/AData" },
45 { 0x1e, L"Transcend" },
46 { 0x1f, L"Kingston" },
47 { 0x27, L"Delkin/Phison" },
48 { 0x28, L"Lexar" },
49 { 0x30, L"SanDisk" },
50 { 0x31, L"Silicon Power" },
51 { 0x33, L"STMicroelectronics" },
52 { 0x41, L"Kingston" },
53 { 0x6f, L"STMicroelectronics" },
54 { 0x74, L"Transcend" },
55 { 0x76, L"Patriot" },
56 { 0x82, L"Gobe/Sony" },
57 { 0x9c, L"Angelbird/Hoodman" },
58};
59
60BM_SDMMC_MANUFACTURER mMmcManufacturers[] = {
61 { 0x00, L"SanDisk" },
62 { 0x02, L"Kingston/SanDisk" },
63 { 0x03, L"Toshiba" },
64 { 0x11, L"Toshiba" },
65 { 0x13, L"Micron" },
66 { 0x15, L"Samsung" },
67 { 0x37, L"KingMax" },
68 { 0x44, L"ATP" },
69 { 0x45, L"SanDisk" },
70 { 0x2c, L"Kingston" },
71 { 0x70, L"Kingston" },
72 { 0x88, L"Foresee" },
73 { 0x9b, L"YMTC" },
74 { 0xd6, L"Foresee" },
75 { 0xfe, L"Micron" },
76};
77
78LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers);
79
80/**
81 For a bootable Device path, return its boot type.
82
83 @param DevicePath The bootable device Path to check
84
85 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
86 which HID is floppy device.
87 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
88 and its last device path node's subtype is MSG_ATAPI_DP.
89 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
90 and its last device path node's subtype is MSG_SATA_DP.
91 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
92 and its last device path node's subtype is MSG_SCSI_DP.
93 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
94 and its last device path node's subtype is MSG_USB_DP.
95 @retval BmMiscBoot If tiven device path doesn't match the above condition.
96
97**/
98BM_BOOT_TYPE
99BmDevicePathType (
100 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
101 )
102{
103 EFI_DEVICE_PATH_PROTOCOL *Node;
104 EFI_DEVICE_PATH_PROTOCOL *NextNode;
105
106 ASSERT (DevicePath != NULL);
107
108 for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
109 switch (DevicePathType (Node)) {
110 case ACPI_DEVICE_PATH:
111 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *)Node)->HID) == 0x0604) {
112 return BmAcpiFloppyBoot;
113 }
114
115 break;
116
117 case HARDWARE_DEVICE_PATH:
118 if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {
119 return BmHardwareDeviceBoot;
120 }
121
122 break;
123
124 case MESSAGING_DEVICE_PATH:
125 //
126 // Skip LUN device node
127 //
128 NextNode = Node;
129 do {
130 NextNode = NextDevicePathNode (NextNode);
131 } while (
132 (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&
133 (DevicePathSubType (NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)
134 );
135
136 //
137 // If the device path not only point to driver device, it is not a messaging device path,
138 //
139 if (!IsDevicePathEndType (NextNode)) {
140 continue;
141 }
142
143 switch (DevicePathSubType (Node)) {
144 case MSG_ATAPI_DP:
145 return BmMessageAtapiBoot;
146 break;
147
148 case MSG_SATA_DP:
149 return BmMessageSataBoot;
150 break;
151
152 case MSG_USB_DP:
153 return BmMessageUsbBoot;
154 break;
155
156 case MSG_SCSI_DP:
157 return BmMessageScsiBoot;
158 break;
159 }
160 }
161 }
162
163 return BmMiscBoot;
164}
165
166/**
167 Eliminate the extra spaces in the Str to one space.
168
169 @param Str Input string info.
170**/
171VOID
172BmEliminateExtraSpaces (
173 IN CHAR16 *Str
174 )
175{
176 UINTN Index;
177 UINTN ActualIndex;
178
179 for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {
180 if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {
181 Str[ActualIndex++] = Str[Index];
182 }
183 }
184
185 Str[ActualIndex] = L'\0';
186}
187
188/**
189 Swap a byte array.
190
191 @param Source Input byte array.
192 @param Length The size of Source in bytes.
193**/
194VOID
195BmSwapBytes (
196 IN UINT8 *Source,
197 IN UINTN Length
198 )
199{
200 UINTN Index;
201 UINT8 Temp;
202 UINTN Count;
203
204 Count = Length / 2;
205 for (Index = 0; Index < Count; ++Index) {
206 Temp = Source[Index];
207 Source[Index] = Source[Length - 1 - Index];
208 Source[Length - 1 - Index] = Temp;
209 }
210}
211
212/**
213 Get the SD/MMC manufacturer name from an ID.
214
215 @param Id Manufacturer ID.
216 @param IsMmc Boolean indicating whether the ID is for SD or eMMC.
217
218 @return The manufacturer string.
219**/
220CHAR16 *
221BmGetSdMmcManufacturerName (
222 IN UINT8 Id,
223 IN BOOLEAN IsMmc
224 )
225{
226 BM_SDMMC_MANUFACTURER *List;
227 UINT8 Count;
228 UINTN Index;
229
230 List = IsMmc ? mMmcManufacturers : mSdManufacturers;
231 Count = IsMmc ? ARRAY_SIZE (mMmcManufacturers)
232 : ARRAY_SIZE (mSdManufacturers);
233
234 for (Index = 0; Index < Count; ++Index) {
235 if (List[Index].Id == Id) {
236 return List[Index].Name;
237 }
238 }
239
240 return mBootDescGenericManufacturer;
241}
242
243/**
244 Get the eMMC partition type from a controller path.
245
246 @param DevicePath Pointer to a CONTROLLER_DEVICE_PATH.
247
248 @return The description string.
249**/
250CHAR16 *
251BmGetEmmcTypeDescription (
252 CONTROLLER_DEVICE_PATH *DevicePath
253 )
254{
255 switch (DevicePath->ControllerNumber) {
256 case EmmcPartitionUserData:
257 return mBootDescEmmcUserData;
258 case EmmcPartitionBoot1:
259 return mBootDescEmmcBoot1;
260 case EmmcPartitionBoot2:
261 return mBootDescEmmcBoot2;
262 case EmmcPartitionGP1:
263 return mBootDescEmmcGp1;
264 case EmmcPartitionGP2:
265 return mBootDescEmmcGp2;
266 case EmmcPartitionGP3:
267 return mBootDescEmmcGp3;
268 case EmmcPartitionGP4:
269 return mBootDescEmmcGp4;
270 default:
271 break;
272 }
273
274 return mBootDescEmmc;
275}
276
277/**
278 Get an SD/MMC boot description.
279
280 @param ManufacturerName Manufacturer name string.
281 @param ProductName Product name from CID.
282 @param ProductNameLength Length of ProductName.
283 @param SerialNumber Serial number from CID.
284 @param DeviceType Device type string (e.g. SD or an eMMC partition).
285
286 @return The description string.
287**/
288CHAR16 *
289BmGetSdMmcDescription (
290 IN CHAR16 *ManufacturerName,
291 IN UINT8 *ProductName,
292 IN UINT8 ProductNameLength,
293 IN UINT8 SerialNumber[4],
294 IN CHAR16 *DeviceType
295 )
296{
297 CHAR16 *Desc;
298 UINTN DescSize;
299
300 DescSize = StrSize (ManufacturerName) - sizeof (CHAR16) // "Samsung"
301 + sizeof (CHAR16) // " "
302 + ProductNameLength * sizeof (CHAR16) // "BJTD4R"
303 + sizeof (CHAR16) // " "
304 + sizeof (UINT32) * 2 * sizeof (CHAR16) // "00000000"
305 + sizeof (CHAR16) // " "
306 + StrSize (DeviceType); // "eMMC User Data\0"
307
308 Desc = AllocateZeroPool (DescSize);
309 if (Desc == NULL) {
310 return NULL;
311 }
312
313 BmSwapBytes (ProductName, ProductNameLength);
314
315 UnicodeSPrint (
316 Desc,
317 DescSize,
318 L"%s %.*a %02x%02x%02x%02x %s",
319 ManufacturerName,
320 ProductNameLength,
321 ProductName,
322 SerialNumber[0],
323 SerialNumber[1],
324 SerialNumber[2],
325 SerialNumber[3],
326 DeviceType
327 );
328
329 return Desc;
330}
331
332/**
333 Try to get the controller's ATA/ATAPI description.
334
335 @param Handle Controller handle.
336
337 @return The description string.
338**/
339CHAR16 *
340BmGetDescriptionFromDiskInfo (
341 IN EFI_HANDLE Handle
342 )
343{
344 UINTN Index;
345 EFI_STATUS Status;
346 EFI_DISK_INFO_PROTOCOL *DiskInfo;
347 UINT32 BufferSize;
348 EFI_ATAPI_IDENTIFY_DATA IdentifyData;
349 EFI_SCSI_INQUIRY_DATA InquiryData;
350 SD_CID SdCid;
351 EMMC_CID EmmcCid;
352 CHAR16 *Description;
353 UINTN Length;
354 CONST UINTN ModelNameLength = 40;
355 CONST UINTN SerialNumberLength = 20;
356 CHAR8 *StrPtr;
357 UINT8 Temp;
358 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
359
360 Description = NULL;
361
362 Status = gBS->HandleProtocol (
363 Handle,
364 &gEfiDiskInfoProtocolGuid,
365 (VOID **)&DiskInfo
366 );
367 if (EFI_ERROR (Status)) {
368 return NULL;
369 }
370
371 if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) ||
372 CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid))
373 {
374 BufferSize = sizeof (EFI_ATAPI_IDENTIFY_DATA);
375 Status = DiskInfo->Identify (
376 DiskInfo,
377 &IdentifyData,
378 &BufferSize
379 );
380 if (!EFI_ERROR (Status)) {
381 Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));
382 ASSERT (Description != NULL);
383 for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {
384 Description[Index] = (CHAR16)IdentifyData.ModelName[Index + 1];
385 Description[Index + 1] = (CHAR16)IdentifyData.ModelName[Index];
386 }
387
388 Length = Index;
389 Description[Length++] = L' ';
390
391 for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {
392 Description[Length + Index] = (CHAR16)IdentifyData.SerialNo[Index + 1];
393 Description[Length + Index + 1] = (CHAR16)IdentifyData.SerialNo[Index];
394 }
395
396 Length += Index;
397 Description[Length++] = L'\0';
398 ASSERT (Length == ModelNameLength + SerialNumberLength + 2);
399
400 BmEliminateExtraSpaces (Description);
401 }
402 } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid) ||
403 CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoUfsInterfaceGuid))
404 {
405 BufferSize = sizeof (EFI_SCSI_INQUIRY_DATA);
406 Status = DiskInfo->Inquiry (
407 DiskInfo,
408 &InquiryData,
409 &BufferSize
410 );
411 if (!EFI_ERROR (Status)) {
412 Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));
413 ASSERT (Description != NULL);
414
415 //
416 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
417 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
418 // Here combine the vendor identification and product identification to the description.
419 //
420 StrPtr = (CHAR8 *)(&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);
421 Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];
422 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';
423 AsciiStrToUnicodeStrS (StrPtr, Description, VENDOR_IDENTIFICATION_LENGTH + 1);
424 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;
425
426 //
427 // Add one space at the middle of vendor information and product information.
428 //
429 Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';
430
431 StrPtr = (CHAR8 *)(&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);
432 StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';
433 AsciiStrToUnicodeStrS (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1, PRODUCT_IDENTIFICATION_LENGTH + 1);
434
435 BmEliminateExtraSpaces (Description);
436 }
437 } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoSdMmcInterfaceGuid)) {
438 DevicePath = DevicePathFromHandle (Handle);
439 if (DevicePath == NULL) {
440 return NULL;
441 }
442
443 while (!IsDevicePathEnd (DevicePath) && (DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH)) {
444 DevicePath = NextDevicePathNode (DevicePath);
445 }
446
447 if (IsDevicePathEnd (DevicePath)) {
448 return NULL;
449 }
450
451 if (DevicePathSubType (DevicePath) == MSG_SD_DP) {
452 BufferSize = sizeof (SD_CID);
453 Status = DiskInfo->Inquiry (DiskInfo, &SdCid, &BufferSize);
454 if (EFI_ERROR (Status)) {
455 return NULL;
456 }
457
458 Description = BmGetSdMmcDescription (
459 BmGetSdMmcManufacturerName (SdCid.ManufacturerId, FALSE),
460 SdCid.ProductName,
461 ARRAY_SIZE (SdCid.ProductName),
462 SdCid.ProductSerialNumber,
463 mBootDescSd
464 );
465 } else if (DevicePathSubType (DevicePath) == MSG_EMMC_DP) {
466 BufferSize = sizeof (EMMC_CID);
467 Status = DiskInfo->Inquiry (DiskInfo, &EmmcCid, &BufferSize);
468 if (EFI_ERROR (Status)) {
469 return NULL;
470 }
471
472 Description = mBootDescEmmc;
473
474 DevicePath = NextDevicePathNode (DevicePath);
475 if (DevicePath->SubType == HW_CONTROLLER_DP) {
476 Description = BmGetEmmcTypeDescription ((CONTROLLER_DEVICE_PATH *)DevicePath);
477 }
478
479 Description = BmGetSdMmcDescription (
480 BmGetSdMmcManufacturerName (EmmcCid.ManufacturerId, TRUE),
481 EmmcCid.ProductName,
482 ARRAY_SIZE (EmmcCid.ProductName),
483 EmmcCid.ProductSerialNumber,
484 Description
485 );
486 } else {
487 return NULL;
488 }
489
490 Description = AllocateCopyPool (StrSize (Description), Description);
491 }
492
493 return Description;
494}
495
496/**
497 Try to get the controller's USB description.
498
499 @param Handle Controller handle.
500
501 @return The description string.
502**/
503CHAR16 *
504BmGetUsbDescription (
505 IN EFI_HANDLE Handle
506 )
507{
508 EFI_STATUS Status;
509 EFI_USB_IO_PROTOCOL *UsbIo;
510 CHAR16 NullChar;
511 CHAR16 *Manufacturer;
512 CHAR16 *Product;
513 CHAR16 *SerialNumber;
514 CHAR16 *Description;
515 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
516 UINTN DescMaxSize;
517
518 Status = gBS->HandleProtocol (
519 Handle,
520 &gEfiUsbIoProtocolGuid,
521 (VOID **)&UsbIo
522 );
523 if (EFI_ERROR (Status)) {
524 return NULL;
525 }
526
527 NullChar = L'\0';
528
529 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
530 if (EFI_ERROR (Status)) {
531 return NULL;
532 }
533
534 Status = UsbIo->UsbGetStringDescriptor (
535 UsbIo,
536 mBmUsbLangId,
537 DevDesc.StrManufacturer,
538 &Manufacturer
539 );
540 if (EFI_ERROR (Status)) {
541 Manufacturer = &NullChar;
542 }
543
544 Status = UsbIo->UsbGetStringDescriptor (
545 UsbIo,
546 mBmUsbLangId,
547 DevDesc.StrProduct,
548 &Product
549 );
550 if (EFI_ERROR (Status)) {
551 Product = &NullChar;
552 }
553
554 Status = UsbIo->UsbGetStringDescriptor (
555 UsbIo,
556 mBmUsbLangId,
557 DevDesc.StrSerialNumber,
558 &SerialNumber
559 );
560 if (EFI_ERROR (Status)) {
561 SerialNumber = &NullChar;
562 }
563
564 if ((Manufacturer == &NullChar) &&
565 (Product == &NullChar) &&
566 (SerialNumber == &NullChar)
567 )
568 {
569 return NULL;
570 }
571
572 DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber);
573 Description = AllocateZeroPool (DescMaxSize);
574 ASSERT (Description != NULL);
575 StrCatS (Description, DescMaxSize/sizeof (CHAR16), Manufacturer);
576 StrCatS (Description, DescMaxSize/sizeof (CHAR16), L" ");
577
578 StrCatS (Description, DescMaxSize/sizeof (CHAR16), Product);
579 StrCatS (Description, DescMaxSize/sizeof (CHAR16), L" ");
580
581 StrCatS (Description, DescMaxSize/sizeof (CHAR16), SerialNumber);
582
583 if (Manufacturer != &NullChar) {
584 FreePool (Manufacturer);
585 }
586
587 if (Product != &NullChar) {
588 FreePool (Product);
589 }
590
591 if (SerialNumber != &NullChar) {
592 FreePool (SerialNumber);
593 }
594
595 BmEliminateExtraSpaces (Description);
596
597 return Description;
598}
599
600/**
601 Return the description for network boot device.
602
603 @param Handle Controller handle.
604
605 @return The description string.
606**/
607CHAR16 *
608BmGetNetworkDescription (
609 IN EFI_HANDLE Handle
610 )
611{
612 EFI_STATUS Status;
613 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
614 MAC_ADDR_DEVICE_PATH *Mac;
615 VLAN_DEVICE_PATH *Vlan;
616 EFI_DEVICE_PATH_PROTOCOL *Ip;
617 EFI_DEVICE_PATH_PROTOCOL *Uri;
618 CHAR16 *Description;
619 UINTN DescriptionSize;
620
621 Status = gBS->OpenProtocol (
622 Handle,
623 &gEfiLoadFileProtocolGuid,
624 NULL,
625 gImageHandle,
626 Handle,
627 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
628 );
629 if (EFI_ERROR (Status)) {
630 return NULL;
631 }
632
633 Status = gBS->OpenProtocol (
634 Handle,
635 &gEfiDevicePathProtocolGuid,
636 (VOID **)&DevicePath,
637 gImageHandle,
638 Handle,
639 EFI_OPEN_PROTOCOL_GET_PROTOCOL
640 );
641 if (EFI_ERROR (Status) || (DevicePath == NULL)) {
642 return NULL;
643 }
644
645 //
646 // The PXE device path is like:
647 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]
648 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)
649 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)
650 //
651 // The HTTP device path is like:
652 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...)
653 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...)
654 //
655 while (!IsDevicePathEnd (DevicePath) &&
656 ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
657 (DevicePathSubType (DevicePath) != MSG_MAC_ADDR_DP))
658 )
659 {
660 DevicePath = NextDevicePathNode (DevicePath);
661 }
662
663 if (IsDevicePathEnd (DevicePath)) {
664 return NULL;
665 }
666
667 Mac = (MAC_ADDR_DEVICE_PATH *)DevicePath;
668 DevicePath = NextDevicePathNode (DevicePath);
669
670 //
671 // Locate the optional Vlan node
672 //
673 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
674 (DevicePathSubType (DevicePath) == MSG_VLAN_DP)
675 )
676 {
677 Vlan = (VLAN_DEVICE_PATH *)DevicePath;
678 DevicePath = NextDevicePathNode (DevicePath);
679 } else {
680 Vlan = NULL;
681 }
682
683 //
684 // Skip the optional Wi-Fi node
685 //
686 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
687 (DevicePathSubType (DevicePath) == MSG_WIFI_DP)
688 )
689 {
690 DevicePath = NextDevicePathNode (DevicePath);
691 }
692
693 //
694 // Locate the IP node
695 //
696 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
697 ((DevicePathSubType (DevicePath) == MSG_IPv4_DP) ||
698 (DevicePathSubType (DevicePath) == MSG_IPv6_DP))
699 )
700 {
701 Ip = DevicePath;
702 DevicePath = NextDevicePathNode (DevicePath);
703 } else {
704 Ip = NULL;
705 }
706
707 //
708 // Skip the optional DNS node
709 //
710 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
711 (DevicePathSubType (DevicePath) == MSG_DNS_DP)
712 )
713 {
714 DevicePath = NextDevicePathNode (DevicePath);
715 }
716
717 //
718 // Locate the URI node
719 //
720 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
721 (DevicePathSubType (DevicePath) == MSG_URI_DP)
722 )
723 {
724 Uri = DevicePath;
725 DevicePath = NextDevicePathNode (DevicePath);
726 } else {
727 Uri = NULL;
728 }
729
730 //
731 // Build description like below:
732 // "PXEv6 (MAC:112233445566 VLAN1)"
733 // "HTTPv4 (MAC:112233445566)"
734 //
735 DescriptionSize = sizeof (L"HTTPv6 (MAC:112233445566 VLAN65535)");
736 Description = AllocatePool (DescriptionSize);
737 ASSERT (Description != NULL);
738 UnicodeSPrint (
739 Description,
740 DescriptionSize,
741 (Vlan == NULL) ?
742 L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :
743 L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",
744 (Uri == NULL) ? L"PXE" : L"HTTP",
745 ((Ip == NULL) || (DevicePathSubType (Ip) == MSG_IPv4_DP)) ? 4 : 6,
746 Mac->MacAddress.Addr[0],
747 Mac->MacAddress.Addr[1],
748 Mac->MacAddress.Addr[2],
749 Mac->MacAddress.Addr[3],
750 Mac->MacAddress.Addr[4],
751 Mac->MacAddress.Addr[5],
752 (Vlan == NULL) ? 0 : Vlan->VlanId
753 );
754 return Description;
755}
756
757/**
758 Return the boot description for LoadFile
759
760 @param Handle Controller handle.
761
762 @return The description string.
763**/
764CHAR16 *
765BmGetLoadFileDescription (
766 IN EFI_HANDLE Handle
767 )
768{
769 EFI_STATUS Status;
770 EFI_DEVICE_PATH_PROTOCOL *FilePath;
771 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
772 CHAR16 *Description;
773 EFI_LOAD_FILE_PROTOCOL *LoadFile;
774
775 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFile);
776 if (EFI_ERROR (Status)) {
777 return NULL;
778 }
779
780 //
781 // Get the file name
782 //
783 Description = NULL;
784 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&FilePath);
785 if (!EFI_ERROR (Status)) {
786 DevicePathNode = FilePath;
787 while (!IsDevicePathEnd (DevicePathNode)) {
788 if ((DevicePathNode->Type == MEDIA_DEVICE_PATH) && (DevicePathNode->SubType == MEDIA_FILEPATH_DP)) {
789 Description = (CHAR16 *)(DevicePathNode + 1);
790 break;
791 }
792
793 DevicePathNode = NextDevicePathNode (DevicePathNode);
794 }
795 }
796
797 if (Description != NULL) {
798 return AllocateCopyPool (StrSize (Description), Description);
799 }
800
801 return NULL;
802}
803
804/**
805 Return the boot description for NVME boot device.
806
807 @param Handle Controller handle.
808
809 @return The description string.
810**/
811CHAR16 *
812BmGetNvmeDescription (
813 IN EFI_HANDLE Handle
814 )
815{
816 EFI_STATUS Status;
817 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassthru;
818 EFI_DEV_PATH_PTR DevicePath;
819 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
820 EFI_NVM_EXPRESS_COMMAND Command;
821 EFI_NVM_EXPRESS_COMPLETION Completion;
822 NVME_ADMIN_CONTROLLER_DATA ControllerData;
823 CHAR16 *Description;
824 CHAR16 *Char;
825 UINTN Index;
826
827 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePath.DevPath);
828 if (EFI_ERROR (Status)) {
829 return NULL;
830 }
831
832 Status = gBS->LocateDevicePath (&gEfiNvmExpressPassThruProtocolGuid, &DevicePath.DevPath, &Handle);
833 if (EFI_ERROR (Status) ||
834 (DevicePathType (DevicePath.DevPath) != MESSAGING_DEVICE_PATH) ||
835 (DevicePathSubType (DevicePath.DevPath) != MSG_NVME_NAMESPACE_DP))
836 {
837 //
838 // Do not return description when the Handle is not a child of NVME controller.
839 //
840 return NULL;
841 }
842
843 //
844 // Send ADMIN_IDENTIFY command to NVME controller to get the model and serial number.
845 //
846 Status = gBS->HandleProtocol (Handle, &gEfiNvmExpressPassThruProtocolGuid, (VOID **)&NvmePassthru);
847 ASSERT_EFI_ERROR (Status);
848
849 ZeroMem (&CommandPacket, sizeof (EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
850 ZeroMem (&Command, sizeof (EFI_NVM_EXPRESS_COMMAND));
851 ZeroMem (&Completion, sizeof (EFI_NVM_EXPRESS_COMPLETION));
852
853 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
854 //
855 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
856 // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
857 //
858 Command.Nsid = 0;
859 CommandPacket.NvmeCmd = &Command;
860 CommandPacket.NvmeCompletion = &Completion;
861 CommandPacket.TransferBuffer = &ControllerData;
862 CommandPacket.TransferLength = sizeof (ControllerData);
863 CommandPacket.CommandTimeout = EFI_TIMER_PERIOD_SECONDS (5);
864 CommandPacket.QueueType = NVME_ADMIN_QUEUE;
865 //
866 // Set bit 0 (Cns bit) to 1 to identify a controller
867 //
868 Command.Cdw10 = 1;
869 Command.Flags = CDW10_VALID;
870
871 Status = NvmePassthru->PassThru (
872 NvmePassthru,
873 0,
874 &CommandPacket,
875 NULL
876 );
877 if (EFI_ERROR (Status)) {
878 return NULL;
879 }
880
881 Description = AllocateZeroPool (
882 (ARRAY_SIZE (ControllerData.Mn) + 1
883 + ARRAY_SIZE (ControllerData.Sn) + 1
884 + MAXIMUM_VALUE_CHARACTERS + 1
885 ) * sizeof (CHAR16)
886 );
887 if (Description != NULL) {
888 Char = Description;
889 for (Index = 0; Index < ARRAY_SIZE (ControllerData.Mn); Index++) {
890 *(Char++) = (CHAR16)ControllerData.Mn[Index];
891 }
892
893 *(Char++) = L' ';
894 for (Index = 0; Index < ARRAY_SIZE (ControllerData.Sn); Index++) {
895 *(Char++) = (CHAR16)ControllerData.Sn[Index];
896 }
897
898 *(Char++) = L' ';
899 UnicodeValueToStringS (
900 Char,
901 sizeof (CHAR16) * (MAXIMUM_VALUE_CHARACTERS + 1),
902 0,
903 DevicePath.NvmeNamespace->NamespaceId,
904 0
905 );
906 BmEliminateExtraSpaces (Description);
907 }
908
909 return Description;
910}
911
912/**
913 Return the boot description for the controller based on the type.
914
915 @param Handle Controller handle.
916
917 @return The description string.
918**/
919CHAR16 *
920BmGetMiscDescription (
921 IN EFI_HANDLE Handle
922 )
923{
924 EFI_STATUS Status;
925 CHAR16 *Description;
926 EFI_BLOCK_IO_PROTOCOL *BlockIo;
927 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
928
929 switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
930 case BmAcpiFloppyBoot:
931 Description = L"Floppy";
932 break;
933
934 case BmMessageAtapiBoot:
935 case BmMessageSataBoot:
936 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
937 ASSERT_EFI_ERROR (Status);
938 //
939 // Assume a removable SATA device should be the DVD/CD device
940 //
941 Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";
942 break;
943
944 case BmMessageUsbBoot:
945 Description = L"USB Device";
946 break;
947
948 case BmMessageScsiBoot:
949 Description = L"SCSI Device";
950 break;
951
952 case BmHardwareDeviceBoot:
953 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
954 if (!EFI_ERROR (Status)) {
955 Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";
956 } else {
957 Description = L"Misc Device";
958 }
959
960 break;
961
962 default:
963 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
964 if (!EFI_ERROR (Status)) {
965 Description = L"Non-Block Boot Device";
966 } else {
967 Description = L"Misc Device";
968 }
969
970 break;
971 }
972
973 return AllocateCopyPool (StrSize (Description), Description);
974}
975
976/**
977 Register the platform provided boot description handler.
978
979 @param Handler The platform provided boot description handler
980
981 @retval EFI_SUCCESS The handler was registered successfully.
982 @retval EFI_ALREADY_STARTED The handler was already registered.
983 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
984**/
985EFI_STATUS
986EFIAPI
987EfiBootManagerRegisterBootDescriptionHandler (
988 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
989 )
990{
991 LIST_ENTRY *Link;
992 BM_BOOT_DESCRIPTION_ENTRY *Entry;
993
994 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
995 ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
996 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
997 )
998 {
999 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
1000 if (Entry->Handler == Handler) {
1001 return EFI_ALREADY_STARTED;
1002 }
1003 }
1004
1005 Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY));
1006 if (Entry == NULL) {
1007 return EFI_OUT_OF_RESOURCES;
1008 }
1009
1010 Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE;
1011 Entry->Handler = Handler;
1012 InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link);
1013 return EFI_SUCCESS;
1014}
1015
1016BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {
1017 BmGetUsbDescription,
1018 BmGetDescriptionFromDiskInfo,
1019 BmGetNetworkDescription,
1020 BmGetLoadFileDescription,
1021 BmGetNvmeDescription,
1022 BmGetMiscDescription
1023};
1024
1025/**
1026 Return the boot description for the controller.
1027
1028 @param Handle Controller handle.
1029
1030 @return The description string.
1031**/
1032CHAR16 *
1033BmGetBootDescription (
1034 IN EFI_HANDLE Handle
1035 )
1036{
1037 LIST_ENTRY *Link;
1038 BM_BOOT_DESCRIPTION_ENTRY *Entry;
1039 CHAR16 *Description;
1040 CHAR16 *DefaultDescription;
1041 CHAR16 *Temp;
1042 UINTN Index;
1043
1044 //
1045 // Firstly get the default boot description
1046 //
1047 DefaultDescription = NULL;
1048 for (Index = 0; Index < ARRAY_SIZE (mBmBootDescriptionHandlers); Index++) {
1049 DefaultDescription = mBmBootDescriptionHandlers[Index](Handle);
1050 if (DefaultDescription != NULL) {
1051 //
1052 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
1053 // ONLY for core provided boot description handler.
1054 //
1055 Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix));
1056 ASSERT (Temp != NULL);
1057 StrCpyS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), mBmUefiPrefix);
1058 StrCatS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), DefaultDescription);
1059 FreePool (DefaultDescription);
1060 DefaultDescription = Temp;
1061 break;
1062 }
1063 }
1064
1065 ASSERT (DefaultDescription != NULL);
1066
1067 //
1068 // Secondly query platform for the better boot description
1069 //
1070 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
1071 ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
1072 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
1073 )
1074 {
1075 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
1076 Description = Entry->Handler (Handle, DefaultDescription);
1077 if (Description != NULL) {
1078 FreePool (DefaultDescription);
1079 return Description;
1080 }
1081 }
1082
1083 return DefaultDescription;
1084}
1085
1086/**
1087 Enumerate all boot option descriptions and append " 2"/" 3"/... to make
1088 unique description.
1089
1090 @param BootOptions Array of boot options.
1091 @param BootOptionCount Count of boot options.
1092**/
1093VOID
1094BmMakeBootOptionDescriptionUnique (
1095 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
1096 UINTN BootOptionCount
1097 )
1098{
1099 UINTN Base;
1100 UINTN Index;
1101 UINTN DescriptionSize;
1102 UINTN MaxSuffixSize;
1103 BOOLEAN *Visited;
1104 UINTN MatchCount;
1105
1106 if (BootOptionCount == 0) {
1107 return;
1108 }
1109
1110 //
1111 // Calculate the maximum buffer size for the number suffix.
1112 // The initial sizeof (CHAR16) is for the blank space before the number.
1113 //
1114 MaxSuffixSize = sizeof (CHAR16);
1115 for (Index = BootOptionCount; Index != 0; Index = Index / 10) {
1116 MaxSuffixSize += sizeof (CHAR16);
1117 }
1118
1119 Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);
1120 ASSERT (Visited != NULL);
1121
1122 for (Base = 0; Base < BootOptionCount; Base++) {
1123 if (!Visited[Base]) {
1124 MatchCount = 1;
1125 Visited[Base] = TRUE;
1126 DescriptionSize = StrSize (BootOptions[Base].Description);
1127 for (Index = Base + 1; Index < BootOptionCount; Index++) {
1128 if (!Visited[Index] && (StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0)) {
1129 Visited[Index] = TRUE;
1130 MatchCount++;
1131 FreePool (BootOptions[Index].Description);
1132 BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);
1133 UnicodeSPrint (
1134 BootOptions[Index].Description,
1135 DescriptionSize + MaxSuffixSize,
1136 L"%s %d",
1137 BootOptions[Base].Description,
1138 MatchCount
1139 );
1140 }
1141 }
1142 }
1143 }
1144
1145 FreePool (Visited);
1146}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette