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