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