VirtualBox

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

Last change on this file since 77662 was 77662, checked in by vboxsync, 6 years ago

EFI: First step in UDK2018 merge. Does not build yet.

  • Property svn:eol-style set to native
File size: 26.8 KB
Line 
1/** @file
2 Library functions which relate with boot option description.
3
4Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
5(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution. The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16#include "InternalBm.h"
17
18#define VENDOR_IDENTIFICATION_OFFSET 3
19#define VENDOR_IDENTIFICATION_LENGTH 8
20#define PRODUCT_IDENTIFICATION_OFFSET 11
21#define PRODUCT_IDENTIFICATION_LENGTH 16
22
23CONST UINT16 mBmUsbLangId = 0x0409; // English
24CHAR16 mBmUefiPrefix[] = L"UEFI ";
25
26LIST_ENTRY mPlatformBootDescriptionHandlers = INITIALIZE_LIST_HEAD_VARIABLE (mPlatformBootDescriptionHandlers);
27
28/**
29 For a bootable Device path, return its boot type.
30
31 @param DevicePath The bootable device Path to check
32
33 @retval AcpiFloppyBoot If given device path contains ACPI_DEVICE_PATH type device path node
34 which HID is floppy device.
35 @retval MessageAtapiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
36 and its last device path node's subtype is MSG_ATAPI_DP.
37 @retval MessageSataBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
38 and its last device path node's subtype is MSG_SATA_DP.
39 @retval MessageScsiBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
40 and its last device path node's subtype is MSG_SCSI_DP.
41 @retval MessageUsbBoot If given device path contains MESSAGING_DEVICE_PATH type device path node
42 and its last device path node's subtype is MSG_USB_DP.
43 @retval BmMiscBoot If tiven device path doesn't match the above condition.
44
45**/
46BM_BOOT_TYPE
47BmDevicePathType (
48 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
49 )
50{
51 EFI_DEVICE_PATH_PROTOCOL *Node;
52 EFI_DEVICE_PATH_PROTOCOL *NextNode;
53
54 ASSERT (DevicePath != NULL);
55
56 for (Node = DevicePath; !IsDevicePathEndType (Node); Node = NextDevicePathNode (Node)) {
57 switch (DevicePathType (Node)) {
58
59 case ACPI_DEVICE_PATH:
60 if (EISA_ID_TO_NUM (((ACPI_HID_DEVICE_PATH *) Node)->HID) == 0x0604) {
61 return BmAcpiFloppyBoot;
62 }
63 break;
64
65 case HARDWARE_DEVICE_PATH:
66 if (DevicePathSubType (Node) == HW_CONTROLLER_DP) {
67 return BmHardwareDeviceBoot;
68 }
69 break;
70
71 case MESSAGING_DEVICE_PATH:
72 //
73 // Skip LUN device node
74 //
75 NextNode = Node;
76 do {
77 NextNode = NextDevicePathNode (NextNode);
78 } while (
79 (DevicePathType (NextNode) == MESSAGING_DEVICE_PATH) &&
80 (DevicePathSubType(NextNode) == MSG_DEVICE_LOGICAL_UNIT_DP)
81 );
82
83 //
84 // If the device path not only point to driver device, it is not a messaging device path,
85 //
86 if (!IsDevicePathEndType (NextNode)) {
87 continue;
88 }
89
90 switch (DevicePathSubType (Node)) {
91 case MSG_ATAPI_DP:
92 return BmMessageAtapiBoot;
93 break;
94
95 case MSG_SATA_DP:
96 return BmMessageSataBoot;
97 break;
98
99 case MSG_USB_DP:
100 return BmMessageUsbBoot;
101 break;
102
103 case MSG_SCSI_DP:
104 return BmMessageScsiBoot;
105 break;
106 }
107 }
108 }
109
110 return BmMiscBoot;
111}
112
113/**
114 Eliminate the extra spaces in the Str to one space.
115
116 @param Str Input string info.
117**/
118VOID
119BmEliminateExtraSpaces (
120 IN CHAR16 *Str
121 )
122{
123 UINTN Index;
124 UINTN ActualIndex;
125
126 for (Index = 0, ActualIndex = 0; Str[Index] != L'\0'; Index++) {
127 if ((Str[Index] != L' ') || ((ActualIndex > 0) && (Str[ActualIndex - 1] != L' '))) {
128 Str[ActualIndex++] = Str[Index];
129 }
130 }
131 Str[ActualIndex] = L'\0';
132}
133
134/**
135 Try to get the controller's ATA/ATAPI description.
136
137 @param Handle Controller handle.
138
139 @return The description string.
140**/
141CHAR16 *
142BmGetDescriptionFromDiskInfo (
143 IN EFI_HANDLE Handle
144 )
145{
146 UINTN Index;
147 EFI_STATUS Status;
148 EFI_DISK_INFO_PROTOCOL *DiskInfo;
149 UINT32 BufferSize;
150 EFI_ATAPI_IDENTIFY_DATA IdentifyData;
151 EFI_SCSI_INQUIRY_DATA InquiryData;
152 CHAR16 *Description;
153 UINTN Length;
154 CONST UINTN ModelNameLength = 40;
155 CONST UINTN SerialNumberLength = 20;
156 CHAR8 *StrPtr;
157 UINT8 Temp;
158 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
159
160 Description = NULL;
161
162 Status = gBS->HandleProtocol (
163 Handle,
164 &gEfiDiskInfoProtocolGuid,
165 (VOID **) &DiskInfo
166 );
167 if (EFI_ERROR (Status)) {
168 return NULL;
169 }
170
171 if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoAhciInterfaceGuid) ||
172 CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
173 BufferSize = sizeof (EFI_ATAPI_IDENTIFY_DATA);
174 Status = DiskInfo->Identify (
175 DiskInfo,
176 &IdentifyData,
177 &BufferSize
178 );
179 if (!EFI_ERROR (Status)) {
180 Description = AllocateZeroPool ((ModelNameLength + SerialNumberLength + 2) * sizeof (CHAR16));
181 ASSERT (Description != NULL);
182 for (Index = 0; Index + 1 < ModelNameLength; Index += 2) {
183 Description[Index] = (CHAR16) IdentifyData.ModelName[Index + 1];
184 Description[Index + 1] = (CHAR16) IdentifyData.ModelName[Index];
185 }
186
187 Length = Index;
188 Description[Length++] = L' ';
189
190 for (Index = 0; Index + 1 < SerialNumberLength; Index += 2) {
191 Description[Length + Index] = (CHAR16) IdentifyData.SerialNo[Index + 1];
192 Description[Length + Index + 1] = (CHAR16) IdentifyData.SerialNo[Index];
193 }
194 Length += Index;
195 Description[Length++] = L'\0';
196 ASSERT (Length == ModelNameLength + SerialNumberLength + 2);
197
198 BmEliminateExtraSpaces (Description);
199 }
200 } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {
201 BufferSize = sizeof (EFI_SCSI_INQUIRY_DATA);
202 Status = DiskInfo->Inquiry (
203 DiskInfo,
204 &InquiryData,
205 &BufferSize
206 );
207 if (!EFI_ERROR (Status)) {
208 Description = AllocateZeroPool ((VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2) * sizeof (CHAR16));
209 ASSERT (Description != NULL);
210
211 //
212 // Per SCSI spec, EFI_SCSI_INQUIRY_DATA.Reserved_5_95[3 - 10] save the Verdor identification
213 // EFI_SCSI_INQUIRY_DATA.Reserved_5_95[11 - 26] save the product identification,
214 // Here combine the vendor identification and product identification to the description.
215 //
216 StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET]);
217 Temp = StrPtr[VENDOR_IDENTIFICATION_LENGTH];
218 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = '\0';
219 AsciiStrToUnicodeStrS (StrPtr, Description, VENDOR_IDENTIFICATION_LENGTH + 1);
220 StrPtr[VENDOR_IDENTIFICATION_LENGTH] = Temp;
221
222 //
223 // Add one space at the middle of vendor information and product information.
224 //
225 Description[VENDOR_IDENTIFICATION_LENGTH] = L' ';
226
227 StrPtr = (CHAR8 *) (&InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET]);
228 StrPtr[PRODUCT_IDENTIFICATION_LENGTH] = '\0';
229 AsciiStrToUnicodeStrS (StrPtr, Description + VENDOR_IDENTIFICATION_LENGTH + 1, PRODUCT_IDENTIFICATION_LENGTH + 1);
230
231 BmEliminateExtraSpaces (Description);
232 }
233 } else if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoSdMmcInterfaceGuid)) {
234 DevicePath = DevicePathFromHandle (Handle);
235 if (DevicePath == NULL) {
236 return NULL;
237 }
238
239 while (!IsDevicePathEnd (DevicePath) && (DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH)) {
240 DevicePath = NextDevicePathNode (DevicePath);
241 }
242 if (IsDevicePathEnd (DevicePath)) {
243 return NULL;
244 }
245
246 if (DevicePathSubType (DevicePath) == MSG_SD_DP) {
247 Description = L"SD Device";
248 } else if (DevicePathSubType (DevicePath) == MSG_EMMC_DP) {
249 Description = L"eMMC Device";
250 } else {
251 return NULL;
252 }
253
254 Description = AllocateCopyPool (StrSize (Description), Description);
255 }
256
257 return Description;
258}
259
260/**
261 Try to get the controller's USB description.
262
263 @param Handle Controller handle.
264
265 @return The description string.
266**/
267CHAR16 *
268BmGetUsbDescription (
269 IN EFI_HANDLE Handle
270 )
271{
272 EFI_STATUS Status;
273 EFI_USB_IO_PROTOCOL *UsbIo;
274 CHAR16 NullChar;
275 CHAR16 *Manufacturer;
276 CHAR16 *Product;
277 CHAR16 *SerialNumber;
278 CHAR16 *Description;
279 EFI_USB_DEVICE_DESCRIPTOR DevDesc;
280 UINTN DescMaxSize;
281
282 Status = gBS->HandleProtocol (
283 Handle,
284 &gEfiUsbIoProtocolGuid,
285 (VOID **) &UsbIo
286 );
287 if (EFI_ERROR (Status)) {
288 return NULL;
289 }
290
291 NullChar = L'\0';
292
293 Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
294 if (EFI_ERROR (Status)) {
295 return NULL;
296 }
297
298 Status = UsbIo->UsbGetStringDescriptor (
299 UsbIo,
300 mBmUsbLangId,
301 DevDesc.StrManufacturer,
302 &Manufacturer
303 );
304 if (EFI_ERROR (Status)) {
305 Manufacturer = &NullChar;
306 }
307
308 Status = UsbIo->UsbGetStringDescriptor (
309 UsbIo,
310 mBmUsbLangId,
311 DevDesc.StrProduct,
312 &Product
313 );
314 if (EFI_ERROR (Status)) {
315 Product = &NullChar;
316 }
317
318 Status = UsbIo->UsbGetStringDescriptor (
319 UsbIo,
320 mBmUsbLangId,
321 DevDesc.StrSerialNumber,
322 &SerialNumber
323 );
324 if (EFI_ERROR (Status)) {
325 SerialNumber = &NullChar;
326 }
327
328 if ((Manufacturer == &NullChar) &&
329 (Product == &NullChar) &&
330 (SerialNumber == &NullChar)
331 ) {
332 return NULL;
333 }
334
335 DescMaxSize = StrSize (Manufacturer) + StrSize (Product) + StrSize (SerialNumber);
336 Description = AllocateZeroPool (DescMaxSize);
337 ASSERT (Description != NULL);
338 StrCatS (Description, DescMaxSize/sizeof(CHAR16), Manufacturer);
339 StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");
340
341 StrCatS (Description, DescMaxSize/sizeof(CHAR16), Product);
342 StrCatS (Description, DescMaxSize/sizeof(CHAR16), L" ");
343
344 StrCatS (Description, DescMaxSize/sizeof(CHAR16), SerialNumber);
345
346 if (Manufacturer != &NullChar) {
347 FreePool (Manufacturer);
348 }
349 if (Product != &NullChar) {
350 FreePool (Product);
351 }
352 if (SerialNumber != &NullChar) {
353 FreePool (SerialNumber);
354 }
355
356 BmEliminateExtraSpaces (Description);
357
358 return Description;
359}
360
361/**
362 Return the description for network boot device.
363
364 @param Handle Controller handle.
365
366 @return The description string.
367**/
368CHAR16 *
369BmGetNetworkDescription (
370 IN EFI_HANDLE Handle
371 )
372{
373 EFI_STATUS Status;
374 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
375 MAC_ADDR_DEVICE_PATH *Mac;
376 VLAN_DEVICE_PATH *Vlan;
377 EFI_DEVICE_PATH_PROTOCOL *Ip;
378 EFI_DEVICE_PATH_PROTOCOL *Uri;
379 CHAR16 *Description;
380 UINTN DescriptionSize;
381
382 Status = gBS->OpenProtocol (
383 Handle,
384 &gEfiLoadFileProtocolGuid,
385 NULL,
386 gImageHandle,
387 Handle,
388 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
389 );
390 if (EFI_ERROR (Status)) {
391 return NULL;
392 }
393
394 Status = gBS->OpenProtocol (
395 Handle,
396 &gEfiDevicePathProtocolGuid,
397 (VOID **) &DevicePath,
398 gImageHandle,
399 Handle,
400 EFI_OPEN_PROTOCOL_GET_PROTOCOL
401 );
402 if (EFI_ERROR (Status) || (DevicePath == NULL)) {
403 return NULL;
404 }
405
406 //
407 // The PXE device path is like:
408 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]
409 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)
410 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)
411 //
412 // The HTTP device path is like:
413 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...)
414 // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...)
415 //
416 while (!IsDevicePathEnd (DevicePath) &&
417 ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) ||
418 (DevicePathSubType (DevicePath) != MSG_MAC_ADDR_DP))
419 ) {
420 DevicePath = NextDevicePathNode (DevicePath);
421 }
422
423 if (IsDevicePathEnd (DevicePath)) {
424 return NULL;
425 }
426
427 Mac = (MAC_ADDR_DEVICE_PATH *) DevicePath;
428 DevicePath = NextDevicePathNode (DevicePath);
429
430 //
431 // Locate the optional Vlan node
432 //
433 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
434 (DevicePathSubType (DevicePath) == MSG_VLAN_DP)
435 ) {
436 Vlan = (VLAN_DEVICE_PATH *) DevicePath;
437 DevicePath = NextDevicePathNode (DevicePath);
438 } else {
439 Vlan = NULL;
440 }
441
442 //
443 // Skip the optional Wi-Fi node
444 //
445 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
446 (DevicePathSubType (DevicePath) == MSG_WIFI_DP)
447 ) {
448 DevicePath = NextDevicePathNode (DevicePath);
449 }
450
451 //
452 // Locate the IP node
453 //
454 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
455 ((DevicePathSubType (DevicePath) == MSG_IPv4_DP) ||
456 (DevicePathSubType (DevicePath) == MSG_IPv6_DP))
457 ) {
458 Ip = DevicePath;
459 DevicePath = NextDevicePathNode (DevicePath);
460 } else {
461 Ip = NULL;
462 }
463
464 //
465 // Skip the optional DNS node
466 //
467 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
468 (DevicePathSubType (DevicePath) == MSG_DNS_DP)
469 ) {
470 DevicePath = NextDevicePathNode (DevicePath);
471 }
472
473 //
474 // Locate the URI node
475 //
476 if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
477 (DevicePathSubType (DevicePath) == MSG_URI_DP)
478 ) {
479 Uri = DevicePath;
480 DevicePath = NextDevicePathNode (DevicePath);
481 } else {
482 Uri = NULL;
483 }
484
485 //
486 // Build description like below:
487 // "PXEv6 (MAC:112233445566 VLAN1)"
488 // "HTTPv4 (MAC:112233445566)"
489 //
490 DescriptionSize = sizeof (L"HTTPv6 (MAC:112233445566 VLAN65535)");
491 Description = AllocatePool (DescriptionSize);
492 ASSERT (Description != NULL);
493 UnicodeSPrint (
494 Description, DescriptionSize,
495 (Vlan == NULL) ?
496 L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x)" :
497 L"%sv%d (MAC:%02x%02x%02x%02x%02x%02x VLAN%d)",
498 (Uri == NULL) ? L"PXE" : L"HTTP",
499 ((Ip == NULL) || (DevicePathSubType (Ip) == MSG_IPv4_DP)) ? 4 : 6,
500 Mac->MacAddress.Addr[0], Mac->MacAddress.Addr[1], Mac->MacAddress.Addr[2],
501 Mac->MacAddress.Addr[3], Mac->MacAddress.Addr[4], Mac->MacAddress.Addr[5],
502 (Vlan == NULL) ? 0 : Vlan->VlanId
503 );
504 return Description;
505}
506
507/**
508 Return the boot description for LoadFile
509
510 @param Handle Controller handle.
511
512 @return The description string.
513**/
514CHAR16 *
515BmGetLoadFileDescription (
516 IN EFI_HANDLE Handle
517 )
518{
519 EFI_STATUS Status;
520 EFI_DEVICE_PATH_PROTOCOL *FilePath;
521 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
522 CHAR16 *Description;
523 EFI_LOAD_FILE_PROTOCOL *LoadFile;
524
525 Status = gBS->HandleProtocol (Handle, &gEfiLoadFileProtocolGuid, (VOID **)&LoadFile);
526 if (EFI_ERROR (Status)) {
527 return NULL;
528 }
529
530 //
531 // Get the file name
532 //
533 Description = NULL;
534 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&FilePath);
535 if (!EFI_ERROR (Status)) {
536 DevicePathNode = FilePath;
537 while (!IsDevicePathEnd (DevicePathNode)) {
538 if (DevicePathNode->Type == MEDIA_DEVICE_PATH && DevicePathNode->SubType == MEDIA_FILEPATH_DP) {
539 Description = (CHAR16 *)(DevicePathNode + 1);
540 break;
541 }
542 DevicePathNode = NextDevicePathNode (DevicePathNode);
543 }
544 }
545
546 if (Description != NULL) {
547 return AllocateCopyPool (StrSize (Description), Description);
548 }
549
550 return NULL;
551}
552
553/**
554 Return the boot description for NVME boot device.
555
556 @param Handle Controller handle.
557
558 @return The description string.
559**/
560CHAR16 *
561BmGetNvmeDescription (
562 IN EFI_HANDLE Handle
563 )
564{
565 EFI_STATUS Status;
566 EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL *NvmePassthru;
567 EFI_DEV_PATH_PTR DevicePath;
568 EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
569 EFI_NVM_EXPRESS_COMMAND Command;
570 EFI_NVM_EXPRESS_COMPLETION Completion;
571 NVME_ADMIN_CONTROLLER_DATA ControllerData;
572 CHAR16 *Description;
573 CHAR16 *Char;
574 UINTN Index;
575
576 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath.DevPath);
577 if (EFI_ERROR (Status)) {
578 return NULL;
579 }
580
581 Status = gBS->LocateDevicePath (&gEfiNvmExpressPassThruProtocolGuid, &DevicePath.DevPath, &Handle);
582 if (EFI_ERROR (Status) ||
583 (DevicePathType (DevicePath.DevPath) != MESSAGING_DEVICE_PATH) ||
584 (DevicePathSubType (DevicePath.DevPath) != MSG_NVME_NAMESPACE_DP)) {
585 //
586 // Do not return description when the Handle is not a child of NVME controller.
587 //
588 return NULL;
589 }
590
591 //
592 // Send ADMIN_IDENTIFY command to NVME controller to get the model and serial number.
593 //
594 Status = gBS->HandleProtocol (Handle, &gEfiNvmExpressPassThruProtocolGuid, (VOID **) &NvmePassthru);
595 ASSERT_EFI_ERROR (Status);
596
597 ZeroMem (&CommandPacket, sizeof(EFI_NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
598 ZeroMem (&Command, sizeof(EFI_NVM_EXPRESS_COMMAND));
599 ZeroMem (&Completion, sizeof(EFI_NVM_EXPRESS_COMPLETION));
600
601 Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_CMD;
602 //
603 // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
604 // For the Identify command, the Namespace Identifier is only used for the Namespace data structure.
605 //
606 Command.Nsid = 0;
607 CommandPacket.NvmeCmd = &Command;
608 CommandPacket.NvmeCompletion = &Completion;
609 CommandPacket.TransferBuffer = &ControllerData;
610 CommandPacket.TransferLength = sizeof (ControllerData);
611 CommandPacket.CommandTimeout = EFI_TIMER_PERIOD_SECONDS (5);
612 CommandPacket.QueueType = NVME_ADMIN_QUEUE;
613 //
614 // Set bit 0 (Cns bit) to 1 to identify a controller
615 //
616 Command.Cdw10 = 1;
617 Command.Flags = CDW10_VALID;
618
619 Status = NvmePassthru->PassThru (
620 NvmePassthru,
621 0,
622 &CommandPacket,
623 NULL
624 );
625 if (EFI_ERROR (Status)) {
626 return NULL;
627 }
628
629 Description = AllocateZeroPool (
630 (ARRAY_SIZE (ControllerData.Mn) + 1
631 + ARRAY_SIZE (ControllerData.Sn) + 1
632 + MAXIMUM_VALUE_CHARACTERS + 1
633 ) * sizeof (CHAR16));
634 if (Description != NULL) {
635 Char = Description;
636 for (Index = 0; Index < ARRAY_SIZE (ControllerData.Mn); Index++) {
637 *(Char++) = (CHAR16) ControllerData.Mn[Index];
638 }
639 *(Char++) = L' ';
640 for (Index = 0; Index < ARRAY_SIZE (ControllerData.Sn); Index++) {
641 *(Char++) = (CHAR16) ControllerData.Sn[Index];
642 }
643 *(Char++) = L' ';
644 UnicodeValueToStringS (
645 Char, sizeof (CHAR16) * (MAXIMUM_VALUE_CHARACTERS + 1),
646 0, DevicePath.NvmeNamespace->NamespaceId, 0
647 );
648 BmEliminateExtraSpaces (Description);
649 }
650
651 return Description;
652}
653
654/**
655 Return the boot description for the controller based on the type.
656
657 @param Handle Controller handle.
658
659 @return The description string.
660**/
661CHAR16 *
662BmGetMiscDescription (
663 IN EFI_HANDLE Handle
664 )
665{
666 EFI_STATUS Status;
667 CHAR16 *Description;
668 EFI_BLOCK_IO_PROTOCOL *BlockIo;
669 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
670
671 switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
672 case BmAcpiFloppyBoot:
673 Description = L"Floppy";
674 break;
675
676 case BmMessageAtapiBoot:
677 case BmMessageSataBoot:
678 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
679 ASSERT_EFI_ERROR (Status);
680 //
681 // Assume a removable SATA device should be the DVD/CD device
682 //
683 Description = BlockIo->Media->RemovableMedia ? L"DVD/CDROM" : L"Hard Drive";
684 break;
685
686 case BmMessageUsbBoot:
687 Description = L"USB Device";
688 break;
689
690 case BmMessageScsiBoot:
691 Description = L"SCSI Device";
692 break;
693
694 case BmHardwareDeviceBoot:
695 Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
696 if (!EFI_ERROR (Status)) {
697 Description = BlockIo->Media->RemovableMedia ? L"Removable Disk" : L"Hard Drive";
698 } else {
699 Description = L"Misc Device";
700 }
701 break;
702
703 default:
704 Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &Fs);
705 if (!EFI_ERROR (Status)) {
706 Description = L"Non-Block Boot Device";
707 } else {
708 Description = L"Misc Device";
709 }
710 break;
711 }
712
713 return AllocateCopyPool (StrSize (Description), Description);
714}
715
716/**
717 Register the platform provided boot description handler.
718
719 @param Handler The platform provided boot description handler
720
721 @retval EFI_SUCCESS The handler was registered successfully.
722 @retval EFI_ALREADY_STARTED The handler was already registered.
723 @retval EFI_OUT_OF_RESOURCES There is not enough resource to perform the registration.
724**/
725EFI_STATUS
726EFIAPI
727EfiBootManagerRegisterBootDescriptionHandler (
728 IN EFI_BOOT_MANAGER_BOOT_DESCRIPTION_HANDLER Handler
729 )
730{
731 LIST_ENTRY *Link;
732 BM_BOOT_DESCRIPTION_ENTRY *Entry;
733
734 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
735 ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
736 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
737 ) {
738 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
739 if (Entry->Handler == Handler) {
740 return EFI_ALREADY_STARTED;
741 }
742 }
743
744 Entry = AllocatePool (sizeof (BM_BOOT_DESCRIPTION_ENTRY));
745 if (Entry == NULL) {
746 return EFI_OUT_OF_RESOURCES;
747 }
748
749 Entry->Signature = BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE;
750 Entry->Handler = Handler;
751 InsertTailList (&mPlatformBootDescriptionHandlers, &Entry->Link);
752 return EFI_SUCCESS;
753}
754
755BM_GET_BOOT_DESCRIPTION mBmBootDescriptionHandlers[] = {
756 BmGetUsbDescription,
757 BmGetDescriptionFromDiskInfo,
758 BmGetNetworkDescription,
759 BmGetLoadFileDescription,
760 BmGetNvmeDescription,
761 BmGetMiscDescription
762};
763
764/**
765 Return the boot description for the controller.
766
767 @param Handle Controller handle.
768
769 @return The description string.
770**/
771CHAR16 *
772BmGetBootDescription (
773 IN EFI_HANDLE Handle
774 )
775{
776 LIST_ENTRY *Link;
777 BM_BOOT_DESCRIPTION_ENTRY *Entry;
778 CHAR16 *Description;
779 CHAR16 *DefaultDescription;
780 CHAR16 *Temp;
781 UINTN Index;
782
783 //
784 // Firstly get the default boot description
785 //
786 DefaultDescription = NULL;
787 for (Index = 0; Index < ARRAY_SIZE (mBmBootDescriptionHandlers); Index++) {
788 DefaultDescription = mBmBootDescriptionHandlers[Index] (Handle);
789 if (DefaultDescription != NULL) {
790 //
791 // Avoid description confusion between UEFI & Legacy boot option by adding "UEFI " prefix
792 // ONLY for core provided boot description handler.
793 //
794 Temp = AllocatePool (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix));
795 ASSERT (Temp != NULL);
796 StrCpyS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), mBmUefiPrefix);
797 StrCatS (Temp, (StrSize (DefaultDescription) + sizeof (mBmUefiPrefix)) / sizeof (CHAR16), DefaultDescription);
798 FreePool (DefaultDescription);
799 DefaultDescription = Temp;
800 break;
801 }
802 }
803 ASSERT (DefaultDescription != NULL);
804
805 //
806 // Secondly query platform for the better boot description
807 //
808 for ( Link = GetFirstNode (&mPlatformBootDescriptionHandlers)
809 ; !IsNull (&mPlatformBootDescriptionHandlers, Link)
810 ; Link = GetNextNode (&mPlatformBootDescriptionHandlers, Link)
811 ) {
812 Entry = CR (Link, BM_BOOT_DESCRIPTION_ENTRY, Link, BM_BOOT_DESCRIPTION_ENTRY_SIGNATURE);
813 Description = Entry->Handler (Handle, DefaultDescription);
814 if (Description != NULL) {
815 FreePool (DefaultDescription);
816 return Description;
817 }
818 }
819
820 return DefaultDescription;
821}
822
823/**
824 Enumerate all boot option descriptions and append " 2"/" 3"/... to make
825 unique description.
826
827 @param BootOptions Array of boot options.
828 @param BootOptionCount Count of boot options.
829**/
830VOID
831BmMakeBootOptionDescriptionUnique (
832 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions,
833 UINTN BootOptionCount
834 )
835{
836 UINTN Base;
837 UINTN Index;
838 UINTN DescriptionSize;
839 UINTN MaxSuffixSize;
840 BOOLEAN *Visited;
841 UINTN MatchCount;
842
843 if (BootOptionCount == 0) {
844 return;
845 }
846
847 //
848 // Calculate the maximum buffer size for the number suffix.
849 // The initial sizeof (CHAR16) is for the blank space before the number.
850 //
851 MaxSuffixSize = sizeof (CHAR16);
852 for (Index = BootOptionCount; Index != 0; Index = Index / 10) {
853 MaxSuffixSize += sizeof (CHAR16);
854 }
855
856 Visited = AllocateZeroPool (sizeof (BOOLEAN) * BootOptionCount);
857 ASSERT (Visited != NULL);
858
859 for (Base = 0; Base < BootOptionCount; Base++) {
860 if (!Visited[Base]) {
861 MatchCount = 1;
862 Visited[Base] = TRUE;
863 DescriptionSize = StrSize (BootOptions[Base].Description);
864 for (Index = Base + 1; Index < BootOptionCount; Index++) {
865 if (!Visited[Index] && StrCmp (BootOptions[Base].Description, BootOptions[Index].Description) == 0) {
866 Visited[Index] = TRUE;
867 MatchCount++;
868 FreePool (BootOptions[Index].Description);
869 BootOptions[Index].Description = AllocatePool (DescriptionSize + MaxSuffixSize);
870 UnicodeSPrint (
871 BootOptions[Index].Description, DescriptionSize + MaxSuffixSize,
872 L"%s %d",
873 BootOptions[Base].Description, MatchCount
874 );
875 }
876 }
877 }
878 }
879
880 FreePool (Visited);
881}
Note: See TracBrowser for help on using the repository browser.

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