]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c
Remove SafeFreePool from MemoryAllocationLib as this API's name is misleading. Its...
[mirror_edk2.git] / MdeModulePkg / Universal / BdsDxe / BootMaint / ConsoleOption.c
CommitLineData
fd6a62f3 1/** @file\r
2 handles console redirection from boot manager\r
3\r
4Copyright (c) 2004 - 2008, Intel Corporation. <BR>\r
93e3992d 5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
fd6a62f3 13**/\r
93e3992d 14\r
15#include "BootMaint.h"\r
16\r
b30312ba 17/**\r
dce655e8 18 Function creates a device path data structure that identically matches the\r
19 device path passed in.\r
b30312ba 20\r
b30312ba 21\r
dce655e8 22 @param DevPath A pointer to a device path data structure.\r
23\r
24 @return The new copy of DevPath is created to identically match the input.\r
25 @retval NULL Otherwise, NULL is returned.\r
b30312ba 26\r
27**/\r
93e3992d 28EFI_DEVICE_PATH_PROTOCOL *\r
29DevicePathInstanceDup (\r
30 IN EFI_DEVICE_PATH_PROTOCOL *DevPath\r
31 );\r
32\r
b30312ba 33/**\r
dce655e8 34 Update Com Ports attributes from DevicePath\r
b30312ba 35\r
b30312ba 36\r
dce655e8 37 @param DevicePath DevicePath that contains Com ports\r
38\r
39 @retval EFI_SUCCESS The update is successful.\r
b30312ba 40\r
41**/\r
93e3992d 42EFI_STATUS\r
43UpdateComAttributeFromVariable (\r
44 EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
45 );\r
46\r
b30312ba 47/**\r
dce655e8 48 Update the multi-instance device path of Terminal Device based on\r
49 the global TerminalMenu. If ChangeTernimal is TRUE, the terminal \r
50 device path in the Terminal Device in TerminalMenu is also updated.\r
b30312ba 51\r
dce655e8 52 @param DevicePath The multi-instance device path.\r
53 @param ChangeTerminal TRUE, then device path in the Terminal Device \r
54 in TerminalMenu is also updated; FALSE, no update.\r
b30312ba 55\r
dce655e8 56 @return EFI_SUCCESS The function completes successfully.\r
b30312ba 57\r
58**/\r
93e3992d 59EFI_STATUS\r
60ChangeTerminalDevicePath (\r
744fc758 61 IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
62 IN BOOLEAN ChangeTerminal\r
93e3992d 63 )\r
64{\r
65 EFI_DEVICE_PATH_PROTOCOL *Node;\r
66 EFI_DEVICE_PATH_PROTOCOL *Node1;\r
67 ACPI_HID_DEVICE_PATH *Acpi;\r
68 UART_DEVICE_PATH *Uart;\r
69 UART_DEVICE_PATH *Uart1;\r
70 UINTN Com;\r
71 UINT32 Match;\r
72 BM_TERMINAL_CONTEXT *NewTerminalContext;\r
73 BM_MENU_ENTRY *NewMenuEntry;\r
74\r
75 Match = EISA_PNP_ID (0x0501);\r
76 Node = DevicePath;\r
77 Node = NextDevicePathNode (Node);\r
78 Com = 0;\r
79 while (!IsDevicePathEnd (Node)) {\r
80 if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {\r
81 Acpi = (ACPI_HID_DEVICE_PATH *) Node;\r
82 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
83 CopyMem (&Com, &Acpi->UID, sizeof (UINT32));\r
84 }\r
85 }\r
86\r
87 NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Com);\r
93e3992d 88\r
89 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;\r
90 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {\r
91 Uart = (UART_DEVICE_PATH *) Node;\r
92 CopyMem (\r
93 &Uart->BaudRate,\r
94 &NewTerminalContext->BaudRate,\r
95 sizeof (UINT64)\r
96 );\r
97\r
98 CopyMem (\r
99 &Uart->DataBits,\r
100 &NewTerminalContext->DataBits,\r
101 sizeof (UINT8)\r
102 );\r
103\r
104 CopyMem (\r
105 &Uart->Parity,\r
106 &NewTerminalContext->Parity,\r
107 sizeof (UINT8)\r
108 );\r
109\r
110 CopyMem (\r
111 &Uart->StopBits,\r
112 &NewTerminalContext->StopBits,\r
113 sizeof (UINT8)\r
114 );\r
115 //\r
116 // Change the device path in the ComPort\r
117 //\r
118 if (ChangeTerminal) {\r
119 Node1 = NewTerminalContext->DevicePath;\r
120 Node1 = NextDevicePathNode (Node1);\r
121 while (!IsDevicePathEnd (Node1)) {\r
122 if ((DevicePathType (Node1) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node1) == MSG_UART_DP)) {\r
123 Uart1 = (UART_DEVICE_PATH *) Node1;\r
124 CopyMem (\r
125 &Uart1->BaudRate,\r
126 &NewTerminalContext->BaudRate,\r
127 sizeof (UINT64)\r
128 );\r
129\r
130 CopyMem (\r
131 &Uart1->DataBits,\r
132 &NewTerminalContext->DataBits,\r
133 sizeof (UINT8)\r
134 );\r
135\r
136 CopyMem (\r
137 &Uart1->Parity,\r
138 &NewTerminalContext->Parity,\r
139 sizeof (UINT8)\r
140 );\r
141\r
142 CopyMem (\r
143 &Uart1->StopBits,\r
144 &NewTerminalContext->StopBits,\r
145 sizeof (UINT8)\r
146 );\r
147 break;\r
148 }\r
149 //\r
150 // end if\r
151 //\r
152 Node1 = NextDevicePathNode (Node1);\r
153 }\r
154 //\r
155 // end while\r
156 //\r
157 break;\r
158 }\r
159 }\r
160\r
161 Node = NextDevicePathNode (Node);\r
162 }\r
163\r
164 return EFI_SUCCESS;\r
165\r
166}\r
167\r
b30312ba 168/**\r
dce655e8 169 Update the device path that describing a terminal device\r
170 based on the new BaudRate, Data Bits, parity and Stop Bits\r
171 set.\r
b30312ba 172\r
30394aa1 173 @param DevicePath terminal device's path\r
b30312ba 174\r
175**/\r
93e3992d 176VOID\r
177ChangeVariableDevicePath (\r
dce655e8 178 IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
93e3992d 179 )\r
180{\r
181 EFI_DEVICE_PATH_PROTOCOL *Node;\r
182 ACPI_HID_DEVICE_PATH *Acpi;\r
183 UART_DEVICE_PATH *Uart;\r
184 UINTN Com;\r
185 UINT32 Match;\r
186 BM_TERMINAL_CONTEXT *NewTerminalContext;\r
187 BM_MENU_ENTRY *NewMenuEntry;\r
188\r
189 Match = EISA_PNP_ID (0x0501);\r
190 Node = DevicePath;\r
191 Node = NextDevicePathNode (Node);\r
192 Com = 0;\r
193 while (!IsDevicePathEnd (Node)) {\r
194 if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {\r
195 Acpi = (ACPI_HID_DEVICE_PATH *) Node;\r
196 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
197 CopyMem (&Com, &Acpi->UID, sizeof (UINT32));\r
198 }\r
199 }\r
200\r
201 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {\r
202 NewMenuEntry = BOpt_GetMenuEntry (\r
203 &TerminalMenu,\r
204 Com\r
205 );\r
206 ASSERT (NewMenuEntry != NULL);\r
207 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;\r
208 Uart = (UART_DEVICE_PATH *) Node;\r
209 CopyMem (\r
210 &Uart->BaudRate,\r
211 &NewTerminalContext->BaudRate,\r
212 sizeof (UINT64)\r
213 );\r
214\r
215 CopyMem (\r
216 &Uart->DataBits,\r
217 &NewTerminalContext->DataBits,\r
218 sizeof (UINT8)\r
219 );\r
220\r
221 CopyMem (\r
222 &Uart->Parity,\r
223 &NewTerminalContext->Parity,\r
224 sizeof (UINT8)\r
225 );\r
226\r
227 CopyMem (\r
228 &Uart->StopBits,\r
229 &NewTerminalContext->StopBits,\r
230 sizeof (UINT8)\r
231 );\r
232 }\r
233\r
234 Node = NextDevicePathNode (Node);\r
235 }\r
93e3992d 236}\r
237\r
b30312ba 238/**\r
239 Retrieve ACPI UID of UART from device path\r
240\r
dce655e8 241 @param Handle The handle for the UART device.\r
242 @param AcpiUid The ACPI UID on output.\r
b30312ba 243\r
244 @retval TRUE Find valid UID from device path\r
245 @retval FALSE Can't find\r
246\r
247**/\r
93e3992d 248BOOLEAN\r
249RetrieveUartUid (\r
250 IN EFI_HANDLE Handle,\r
251 IN OUT UINT32 *AcpiUid\r
252 )\r
93e3992d 253{\r
254 UINT32 Match;\r
255 UINT8 *Ptr;\r
256 ACPI_HID_DEVICE_PATH *Acpi;\r
257 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
258\r
259 gBS->HandleProtocol (\r
260 Handle,\r
261 &gEfiDevicePathProtocolGuid,\r
262 (VOID **) &DevicePath\r
263 );\r
264 Ptr = (UINT8 *) DevicePath;\r
265\r
266 while (*Ptr != END_DEVICE_PATH_TYPE) {\r
267 Ptr++;\r
268 }\r
269\r
270 Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);\r
271 Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;\r
272 Match = EISA_PNP_ID (0x0501);\r
273\r
274 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
275 if (AcpiUid != NULL) {\r
276 *AcpiUid = Acpi->UID;\r
277 }\r
278 return TRUE;\r
279 } else {\r
280 return FALSE;\r
281 }\r
282}\r
283\r
b30312ba 284/**\r
744fc758 285 Sort Uart handles array with Acpi->UID from low to high.\r
b30312ba 286\r
b30312ba 287 @param Handles EFI_SERIAL_IO_PROTOCOL handle buffer\r
288 @param NoHandles EFI_SERIAL_IO_PROTOCOL handle count\r
b30312ba 289**/\r
93e3992d 290VOID\r
291SortedUartHandle (\r
292 IN EFI_HANDLE *Handles,\r
293 IN UINTN NoHandles\r
294 )\r
93e3992d 295{\r
296 UINTN Index1;\r
297 UINTN Index2;\r
298 UINTN Position;\r
299 UINT32 AcpiUid1;\r
300 UINT32 AcpiUid2;\r
301 UINT32 TempAcpiUid;\r
302 EFI_HANDLE TempHandle;\r
303\r
304 for (Index1 = 0; Index1 < NoHandles-1; Index1++) {\r
305 if (!RetrieveUartUid (Handles[Index1], &AcpiUid1)) {\r
306 continue;\r
307 }\r
308 TempHandle = Handles[Index1];\r
309 Position = Index1;\r
310 TempAcpiUid = AcpiUid1;\r
311\r
312 for (Index2 = Index1+1; Index2 < NoHandles; Index2++) {\r
313 if (!RetrieveUartUid (Handles[Index2], &AcpiUid2)) {\r
314 continue;\r
315 }\r
316 if (AcpiUid2 < TempAcpiUid) {\r
317 TempAcpiUid = AcpiUid2;\r
318 TempHandle = Handles[Index2];\r
319 Position = Index2;\r
320 }\r
321 }\r
322 Handles[Position] = Handles[Index1];\r
323 Handles[Index1] = TempHandle;\r
324 }\r
325}\r
326\r
b30312ba 327/**\r
dce655e8 328 Test whether DevicePath is a valid Terminal\r
b30312ba 329\r
b30312ba 330\r
dce655e8 331 @param DevicePath DevicePath to be checked\r
332 @param Termi If DevicePath is valid Terminal, terminal type is returned.\r
333 @param Com If DevicePath is valid Terminal, Com Port type is returned.\r
334\r
335 @retval TRUE If DevicePath point to a Terminal.\r
336 @retval FALSE If DevicePath does not point to a Terminal.\r
b30312ba 337\r
338**/\r
93e3992d 339BOOLEAN\r
340IsTerminalDevicePath (\r
341 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
342 OUT TYPE_OF_TERMINAL *Termi,\r
343 OUT UINTN *Com\r
344 );\r
345\r
b30312ba 346/**\r
744fc758 347 Build a list containing all serial devices.\r
93e3992d 348\r
93e3992d 349\r
744fc758 350 @retval EFI_SUCCESS The function complete successfully.\r
351 @retval EFI_UNSUPPORTED No serial ports present.\r
93e3992d 352\r
b30312ba 353**/\r
354EFI_STATUS\r
355LocateSerialIo (\r
356 VOID\r
357 )\r
93e3992d 358{\r
359 UINT8 *Ptr;\r
360 UINTN Index;\r
361 UINTN Index2;\r
362 UINTN NoHandles;\r
363 EFI_HANDLE *Handles;\r
364 EFI_STATUS Status;\r
365 ACPI_HID_DEVICE_PATH *Acpi;\r
366 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
367 UINT32 Match;\r
368 EFI_SERIAL_IO_PROTOCOL *SerialIo;\r
369 EFI_DEVICE_PATH_PROTOCOL *OutDevicePath;\r
370 EFI_DEVICE_PATH_PROTOCOL *InpDevicePath;\r
371 EFI_DEVICE_PATH_PROTOCOL *ErrDevicePath;\r
372 BM_MENU_ENTRY *NewMenuEntry;\r
373 BM_TERMINAL_CONTEXT *NewTerminalContext;\r
374 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
375 VENDOR_DEVICE_PATH Vendor;\r
376 //\r
377 // Get all handles that have SerialIo protocol installed\r
378 //\r
379 InitializeListHead (&TerminalMenu.Head);\r
380 TerminalMenu.MenuNumber = 0;\r
381 Status = gBS->LocateHandleBuffer (\r
382 ByProtocol,\r
383 &gEfiSerialIoProtocolGuid,\r
384 NULL,\r
385 &NoHandles,\r
386 &Handles\r
387 );\r
388 if (EFI_ERROR (Status)) {\r
389 //\r
390 // No serial ports present\r
391 //\r
392 return EFI_UNSUPPORTED;\r
393 }\r
394\r
395 //\r
396 // Sort Uart handles array with Acpi->UID from low to high\r
397 // then Terminal menu can be built from low Acpi->UID to high Acpi->UID\r
398 //\r
399 SortedUartHandle (Handles, NoHandles);\r
400\r
401 for (Index = 0; Index < NoHandles; Index++) {\r
402 //\r
403 // Check to see whether the handle has DevicePath Protocol installed\r
404 //\r
405 gBS->HandleProtocol (\r
406 Handles[Index],\r
407 &gEfiDevicePathProtocolGuid,\r
408 (VOID **) &DevicePath\r
409 );\r
410 Ptr = (UINT8 *) DevicePath;\r
411 while (*Ptr != END_DEVICE_PATH_TYPE) {\r
412 Ptr++;\r
413 }\r
414\r
415 Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);\r
416 Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;\r
417 Match = EISA_PNP_ID (0x0501);\r
418\r
419 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
420 NewMenuEntry = BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT);\r
a78b08d1 421 if (NewMenuEntry == NULL) {\r
93e3992d 422 SafeFreePool (Handles);\r
423 return EFI_OUT_OF_RESOURCES;\r
424 }\r
425\r
426 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;\r
427 CopyMem (&NewMenuEntry->OptionNumber, &Acpi->UID, sizeof (UINT32));\r
428 NewTerminalContext->DevicePath = DevicePathInstanceDup (DevicePath);\r
429 //\r
430 // BugBug: I have no choice, calling EfiLibStrFromDatahub will hang the system!\r
431 // coz' the misc data for each platform is not correct, actually it's the device path stored in\r
432 // datahub which is not completed, so a searching for end of device path will enter a\r
433 // dead-loop.\r
434 //\r
435 NewMenuEntry->DisplayString = EfiLibStrFromDatahub (DevicePath);\r
436 if (NULL == NewMenuEntry->DisplayString) {\r
437 NewMenuEntry->DisplayString = DevicePathToStr (DevicePath);\r
438 }\r
439\r
440 NewMenuEntry->HelpString = NULL;\r
441\r
442 gBS->HandleProtocol (\r
443 Handles[Index],\r
444 &gEfiSerialIoProtocolGuid,\r
445 (VOID **) &SerialIo\r
446 );\r
447\r
448 CopyMem (\r
449 &NewTerminalContext->BaudRate,\r
450 &SerialIo->Mode->BaudRate,\r
451 sizeof (UINT64)\r
452 );\r
453\r
454 CopyMem (\r
455 &NewTerminalContext->DataBits,\r
456 &SerialIo->Mode->DataBits,\r
457 sizeof (UINT8)\r
458 );\r
459\r
460 CopyMem (\r
461 &NewTerminalContext->Parity,\r
462 &SerialIo->Mode->Parity,\r
463 sizeof (UINT8)\r
464 );\r
465\r
466 CopyMem (\r
467 &NewTerminalContext->StopBits,\r
468 &SerialIo->Mode->StopBits,\r
469 sizeof (UINT8)\r
470 );\r
471 InsertTailList (&TerminalMenu.Head, &NewMenuEntry->Link);\r
472 TerminalMenu.MenuNumber++;\r
473 }\r
474 }\r
475 SafeFreePool (Handles);\r
476\r
477 //\r
478 // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var\r
479 //\r
480 OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid);\r
481 InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid);\r
482 ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid);\r
a78b08d1 483 if (OutDevicePath != NULL) {\r
93e3992d 484 UpdateComAttributeFromVariable (OutDevicePath);\r
485 }\r
486\r
a78b08d1 487 if (InpDevicePath != NULL) {\r
93e3992d 488 UpdateComAttributeFromVariable (InpDevicePath);\r
489 }\r
490\r
a78b08d1 491 if (ErrDevicePath != NULL) {\r
93e3992d 492 UpdateComAttributeFromVariable (ErrDevicePath);\r
493 }\r
494\r
495 for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {\r
496 NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);\r
497 if (NULL == NewMenuEntry) {\r
498 return EFI_NOT_FOUND;\r
499 }\r
500\r
501 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;\r
502\r
503 NewTerminalContext->TerminalType = 0;\r
504 NewTerminalContext->IsConIn = FALSE;\r
505 NewTerminalContext->IsConOut = FALSE;\r
506 NewTerminalContext->IsStdErr = FALSE;\r
507\r
508 Vendor.Header.Type = MESSAGING_DEVICE_PATH;\r
509 Vendor.Header.SubType = MSG_VENDOR_DP;\r
510\r
511 for (Index2 = 0; Index2 < 4; Index2++) {\r
dce655e8 512 CopyMem (&Vendor.Guid, &TerminalTypeGuid[Index2], sizeof (EFI_GUID));\r
93e3992d 513 SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));\r
514 NewDevicePath = AppendDevicePathNode (\r
515 NewTerminalContext->DevicePath,\r
516 (EFI_DEVICE_PATH_PROTOCOL *) &Vendor\r
517 );\r
518 SafeFreePool (NewMenuEntry->HelpString);\r
519 //\r
520 // NewMenuEntry->HelpString = DevicePathToStr (NewDevicePath);\r
521 // NewMenuEntry->DisplayString = NewMenuEntry->HelpString;\r
522 //\r
523 NewMenuEntry->HelpString = NULL;\r
524\r
525 if (BdsLibMatchDevicePaths (OutDevicePath, NewDevicePath)) {\r
526 NewTerminalContext->IsConOut = TRUE;\r
527 NewTerminalContext->TerminalType = (UINT8) Index2;\r
528 }\r
529\r
530 if (BdsLibMatchDevicePaths (InpDevicePath, NewDevicePath)) {\r
531 NewTerminalContext->IsConIn = TRUE;\r
532 NewTerminalContext->TerminalType = (UINT8) Index2;\r
533 }\r
534\r
535 if (BdsLibMatchDevicePaths (ErrDevicePath, NewDevicePath)) {\r
536 NewTerminalContext->IsStdErr = TRUE;\r
537 NewTerminalContext->TerminalType = (UINT8) Index2;\r
538 }\r
539 }\r
540 }\r
541\r
542 return EFI_SUCCESS;\r
543}\r
544\r
b30312ba 545/**\r
93e3992d 546 Update Com Ports attributes from DevicePath\r
547\r
93e3992d 548\r
b30312ba 549 @param DevicePath DevicePath that contains Com ports\r
93e3992d 550\r
dce655e8 551 @retval EFI_SUCCESS The update is successful.\r
30394aa1 552 @retval EFI_NOT_FOUND Can not find specific menu entry\r
b30312ba 553**/\r
554EFI_STATUS\r
555UpdateComAttributeFromVariable (\r
556 EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
557 )\r
93e3992d 558{\r
559 EFI_DEVICE_PATH_PROTOCOL *Node;\r
560 EFI_DEVICE_PATH_PROTOCOL *SerialNode;\r
561 ACPI_HID_DEVICE_PATH *Acpi;\r
562 UART_DEVICE_PATH *Uart;\r
563 UART_DEVICE_PATH *Uart1;\r
564 UINT32 Match;\r
565 UINTN TerminalNumber;\r
566 BM_MENU_ENTRY *NewMenuEntry;\r
567 BM_TERMINAL_CONTEXT *NewTerminalContext;\r
568 UINTN Index;\r
569\r
570 Match = EISA_PNP_ID (0x0501);\r
571 Node = DevicePath;\r
572 Node = NextDevicePathNode (Node);\r
573 TerminalNumber = 0;\r
574 for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {\r
575 while (!IsDevicePathEnd (Node)) {\r
576 if ((DevicePathType (Node) == ACPI_DEVICE_PATH) && (DevicePathSubType (Node) == ACPI_DP)) {\r
577 Acpi = (ACPI_HID_DEVICE_PATH *) Node;\r
578 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
579 CopyMem (&TerminalNumber, &Acpi->UID, sizeof (UINT32));\r
580 }\r
581 }\r
582\r
583 if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {\r
584 Uart = (UART_DEVICE_PATH *) Node;\r
585 NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalNumber);\r
586 if (NULL == NewMenuEntry) {\r
587 return EFI_NOT_FOUND;\r
588 }\r
589\r
590 NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;\r
591 CopyMem (\r
592 &NewTerminalContext->BaudRate,\r
593 &Uart->BaudRate,\r
594 sizeof (UINT64)\r
595 );\r
596\r
597 CopyMem (\r
598 &NewTerminalContext->DataBits,\r
599 &Uart->DataBits,\r
600 sizeof (UINT8)\r
601 );\r
602\r
603 CopyMem (\r
604 &NewTerminalContext->Parity,\r
605 &Uart->Parity,\r
606 sizeof (UINT8)\r
607 );\r
608\r
609 CopyMem (\r
610 &NewTerminalContext->StopBits,\r
611 &Uart->StopBits,\r
612 sizeof (UINT8)\r
613 );\r
614\r
615 SerialNode = NewTerminalContext->DevicePath;\r
616 SerialNode = NextDevicePathNode (SerialNode);\r
617 while (!IsDevicePathEnd (SerialNode)) {\r
618 if ((DevicePathType (SerialNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (SerialNode) == MSG_UART_DP)) {\r
619 //\r
620 // Update following device paths according to\r
621 // previous acquired uart attributes\r
622 //\r
623 Uart1 = (UART_DEVICE_PATH *) SerialNode;\r
624 CopyMem (\r
625 &Uart1->BaudRate,\r
626 &NewTerminalContext->BaudRate,\r
627 sizeof (UINT64)\r
628 );\r
629\r
630 CopyMem (\r
631 &Uart1->DataBits,\r
632 &NewTerminalContext->DataBits,\r
633 sizeof (UINT8)\r
634 );\r
635 CopyMem (\r
636 &Uart1->Parity,\r
637 &NewTerminalContext->Parity,\r
638 sizeof (UINT8)\r
639 );\r
640 CopyMem (\r
641 &Uart1->StopBits,\r
642 &NewTerminalContext->StopBits,\r
643 sizeof (UINT8)\r
644 );\r
645\r
646 break;\r
647 }\r
648\r
649 SerialNode = NextDevicePathNode (SerialNode);\r
650 }\r
651 //\r
652 // end while\r
653 //\r
654 }\r
655\r
656 Node = NextDevicePathNode (Node);\r
657 }\r
658 //\r
659 // end while\r
660 //\r
661 }\r
662\r
663 return EFI_SUCCESS;\r
664}\r
665\r
b30312ba 666/**\r
93e3992d 667 Function creates a device path data structure that identically matches the\r
668 device path passed in.\r
669\r
93e3992d 670\r
b30312ba 671 @param DevPath A pointer to a device path data structure.\r
93e3992d 672\r
dce655e8 673 @return The new copy of DevPath is created to identically match the input.\r
674 @retval NULL Otherwise, NULL is returned.\r
93e3992d 675\r
b30312ba 676**/\r
677EFI_DEVICE_PATH_PROTOCOL *\r
678DevicePathInstanceDup (\r
679 IN EFI_DEVICE_PATH_PROTOCOL *DevPath\r
680 )\r
93e3992d 681{\r
682 EFI_DEVICE_PATH_PROTOCOL *NewDevPath;\r
683 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
684 EFI_DEVICE_PATH_PROTOCOL *Temp;\r
685 UINT8 *Ptr;\r
686 UINTN Size;\r
687\r
688 //\r
689 // get the size of an instance from the input\r
690 //\r
691 Temp = DevPath;\r
692 DevicePathInst = GetNextDevicePathInstance (&Temp, &Size);\r
693\r
694 //\r
695 // Make a copy and set proper end type\r
696 //\r
697 NewDevPath = NULL;\r
a78b08d1 698 if (Size != 0) {\r
dce655e8 699 NewDevPath = AllocateZeroPool (Size);\r
93e3992d 700 ASSERT (NewDevPath != NULL);\r
701 }\r
702\r
a78b08d1 703 if (NewDevPath != NULL) {\r
93e3992d 704 CopyMem (NewDevPath, DevicePathInst, Size);\r
705 Ptr = (UINT8 *) NewDevPath;\r
706 Ptr += Size - sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
707 Temp = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
708 SetDevicePathEndNode (Temp);\r
709 }\r
710\r
711 return NewDevPath;\r
712}\r
713\r
b30312ba 714/**\r
dce655e8 715 Build up Console Menu based on types passed in. The type can\r
716 be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT\r
717 and BM_CONSOLE_ERR_CONTEXT_SELECT.\r
b30312ba 718\r
dce655e8 719 @param ConsoleMenuType Can be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT\r
720 and BM_CONSOLE_ERR_CONTEXT_SELECT.\r
b30312ba 721\r
dce655e8 722 @retval EFI_UNSUPPORTED The type passed in is not in the 3 types defined.\r
723 @retval EFI_NOT_FOUND If the EFI Variable defined in UEFI spec with name "ConOutDev", \r
724 "ConInDev" or "ConErrDev" doesn't exists.\r
725 @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operations.\r
726 @retval EFI_SUCCESS Function completes successfully.\r
b30312ba 727\r
728**/\r
93e3992d 729EFI_STATUS\r
730GetConsoleMenu (\r
731 IN UINTN ConsoleMenuType\r
732 )\r
733{\r
734 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
735 EFI_DEVICE_PATH_PROTOCOL *AllDevicePath;\r
736 EFI_DEVICE_PATH_PROTOCOL *MultiDevicePath;\r
737 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;\r
738 UINTN Size;\r
739 UINTN AllCount;\r
740 UINTN Index;\r
741 UINTN Index2;\r
742 BM_MENU_ENTRY *NewMenuEntry;\r
743 BM_CONSOLE_CONTEXT *NewConsoleContext;\r
744 TYPE_OF_TERMINAL Terminal;\r
745 UINTN Com;\r
746 BM_MENU_OPTION *ConsoleMenu;\r
747\r
748 DevicePath = NULL;\r
749 AllDevicePath = NULL;\r
750 AllCount = 0;\r
751 switch (ConsoleMenuType) {\r
752 case BM_CONSOLE_IN_CONTEXT_SELECT:\r
753 ConsoleMenu = &ConsoleInpMenu;\r
754 DevicePath = EfiLibGetVariable (\r
755 L"ConIn",\r
756 &gEfiGlobalVariableGuid\r
757 );\r
758\r
759 AllDevicePath = EfiLibGetVariable (\r
760 L"ConInDev",\r
761 &gEfiGlobalVariableGuid\r
762 );\r
763 break;\r
764\r
765 case BM_CONSOLE_OUT_CONTEXT_SELECT:\r
766 ConsoleMenu = &ConsoleOutMenu;\r
767 DevicePath = EfiLibGetVariable (\r
768 L"ConOut",\r
769 &gEfiGlobalVariableGuid\r
770 );\r
771\r
772 AllDevicePath = EfiLibGetVariable (\r
773 L"ConOutDev",\r
774 &gEfiGlobalVariableGuid\r
775 );\r
776 break;\r
777\r
778 case BM_CONSOLE_ERR_CONTEXT_SELECT:\r
779 ConsoleMenu = &ConsoleErrMenu;\r
780 DevicePath = EfiLibGetVariable (\r
781 L"ErrOut",\r
782 &gEfiGlobalVariableGuid\r
783 );\r
784\r
785 AllDevicePath = EfiLibGetVariable (\r
786 L"ErrOutDev",\r
787 &gEfiGlobalVariableGuid\r
788 );\r
789 break;\r
790\r
791 default:\r
792 return EFI_UNSUPPORTED;\r
793 }\r
794\r
795 if (NULL == AllDevicePath) {\r
796 return EFI_NOT_FOUND;\r
797 }\r
798\r
799 InitializeListHead (&ConsoleMenu->Head);\r
800\r
801 AllCount = EfiDevicePathInstanceCount (AllDevicePath);\r
802 ConsoleMenu->MenuNumber = 0;\r
803 //\r
dce655e8 804 // Following is menu building up for Console Devices selected.\r
93e3992d 805 //\r
806 MultiDevicePath = AllDevicePath;\r
807 Index2 = 0;\r
808 for (Index = 0; Index < AllCount; Index++) {\r
809 DevicePathInst = GetNextDevicePathInstance (&MultiDevicePath, &Size);\r
810\r
811 NewMenuEntry = BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT);\r
812 if (NULL == NewMenuEntry) {\r
813 return EFI_OUT_OF_RESOURCES;\r
814 }\r
815\r
816 NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;\r
817 NewMenuEntry->OptionNumber = Index2;\r
818\r
819 NewConsoleContext->DevicePath = DevicePathInstanceDup (DevicePathInst);\r
820 NewMenuEntry->DisplayString = EfiLibStrFromDatahub (NewConsoleContext->DevicePath);\r
821 if (NULL == NewMenuEntry->DisplayString) {\r
822 NewMenuEntry->DisplayString = DevicePathToStr (NewConsoleContext->DevicePath);\r
823 }\r
824\r
825 NewConsoleContext->IsTerminal = IsTerminalDevicePath (\r
826 NewConsoleContext->DevicePath,\r
827 &Terminal,\r
828 &Com\r
829 );\r
830\r
831 NewConsoleContext->IsActive = BdsLibMatchDevicePaths (\r
832 DevicePath,\r
833 NewConsoleContext->DevicePath\r
834 );\r
835\r
836 if (NewConsoleContext->IsTerminal) {\r
837 BOpt_DestroyMenuEntry (NewMenuEntry);\r
838 } else {\r
839 Index2++;\r
840 ConsoleMenu->MenuNumber++;\r
841 InsertTailList (&ConsoleMenu->Head, &NewMenuEntry->Link);\r
842 }\r
843 }\r
844\r
845 return EFI_SUCCESS;\r
846}\r
847\r
b30312ba 848/**\r
93e3992d 849 Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu\r
850\r
dce655e8 851 @retval EFI_SUCCESS The function always complete successfully.\r
b30312ba 852\r
853**/\r
854EFI_STATUS\r
855GetAllConsoles (\r
856 VOID\r
857 )\r
93e3992d 858{\r
859 GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT);\r
860 GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT);\r
861 GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT);\r
862 return EFI_SUCCESS;\r
863}\r
864\r
b30312ba 865/**\r
93e3992d 866 Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu\r
867\r
dce655e8 868 @retval EFI_SUCCESS The function always complete successfully.\r
b30312ba 869**/\r
870EFI_STATUS\r
871FreeAllConsoles (\r
872 VOID\r
873 )\r
93e3992d 874{\r
875 BOpt_FreeMenu (&ConsoleOutMenu);\r
876 BOpt_FreeMenu (&ConsoleInpMenu);\r
877 BOpt_FreeMenu (&ConsoleErrMenu);\r
878 BOpt_FreeMenu (&TerminalMenu);\r
879 return EFI_SUCCESS;\r
880}\r
881\r
b30312ba 882/**\r
883 Test whether DevicePath is a valid Terminal\r
884\r
885\r
886 @param DevicePath DevicePath to be checked\r
dce655e8 887 @param Termi If DevicePath is valid Terminal, terminal type is returned.\r
888 @param Com If DevicePath is valid Terminal, Com Port type is returned.\r
b30312ba 889\r
dce655e8 890 @retval TRUE If DevicePath point to a Terminal.\r
891 @retval FALSE If DevicePath does not point to a Terminal.\r
b30312ba 892\r
893**/\r
93e3992d 894BOOLEAN\r
895IsTerminalDevicePath (\r
896 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
897 OUT TYPE_OF_TERMINAL *Termi,\r
898 OUT UINTN *Com\r
899 )\r
93e3992d 900{\r
901 UINT8 *Ptr;\r
902 BOOLEAN IsTerminal;\r
903 VENDOR_DEVICE_PATH *Vendor;\r
904 ACPI_HID_DEVICE_PATH *Acpi;\r
905 UINT32 Match;\r
906 EFI_GUID TempGuid;\r
907\r
908 IsTerminal = FALSE;\r
909\r
910 //\r
911 // Parse the Device Path, should be change later!!!\r
912 //\r
913 Ptr = (UINT8 *) DevicePath;\r
914 while (*Ptr != END_DEVICE_PATH_TYPE) {\r
915 Ptr++;\r
916 }\r
917\r
918 Ptr = Ptr - sizeof (VENDOR_DEVICE_PATH);\r
919 Vendor = (VENDOR_DEVICE_PATH *) Ptr;\r
920\r
921 //\r
922 // There are four kinds of Terminal types\r
923 // check to see whether this devicepath\r
924 // is one of that type\r
925 //\r
926 CopyMem (&TempGuid, &Vendor->Guid, sizeof (EFI_GUID));\r
927\r
dce655e8 928 if (CompareGuid (&TempGuid, &TerminalTypeGuid[0])) {\r
93e3992d 929 *Termi = PC_ANSI;\r
930 IsTerminal = TRUE;\r
931 } else {\r
dce655e8 932 if (CompareGuid (&TempGuid, &TerminalTypeGuid[1])) {\r
93e3992d 933 *Termi = VT_100;\r
934 IsTerminal = TRUE;\r
935 } else {\r
dce655e8 936 if (CompareGuid (&TempGuid, &TerminalTypeGuid[2])) {\r
93e3992d 937 *Termi = VT_100_PLUS;\r
938 IsTerminal = TRUE;\r
939 } else {\r
dce655e8 940 if (CompareGuid (&TempGuid, &TerminalTypeGuid[3])) {\r
93e3992d 941 *Termi = VT_UTF8;\r
942 IsTerminal = TRUE;\r
943 } else {\r
944 IsTerminal = FALSE;\r
945 }\r
946 }\r
947 }\r
948 }\r
949\r
950 if (!IsTerminal) {\r
951 return FALSE;\r
952 }\r
953\r
954 Ptr = Ptr - sizeof (UART_DEVICE_PATH) - sizeof (ACPI_HID_DEVICE_PATH);\r
955 Acpi = (ACPI_HID_DEVICE_PATH *) Ptr;\r
956 Match = EISA_PNP_ID (0x0501);\r
957 if (CompareMem (&Acpi->HID, &Match, sizeof (UINT32)) == 0) {\r
958 CopyMem (Com, &Acpi->UID, sizeof (UINT32));\r
959 } else {\r
960 return FALSE;\r
961 }\r
962\r
963 return TRUE;\r
964}\r
965\r
b30312ba 966/**\r
93e3992d 967 Get mode number according to column and row\r
968\r
dce655e8 969 @param CallbackData The BMM context data.\r
b30312ba 970**/\r
971VOID\r
972GetConsoleOutMode (\r
973 IN BMM_CALLBACK_DATA *CallbackData\r
974 )\r
93e3992d 975{\r
976 UINTN Col;\r
977 UINTN Row;\r
978 UINTN CurrentCol;\r
979 UINTN CurrentRow;\r
980 UINTN Mode;\r
981 UINTN MaxMode;\r
982 EFI_STATUS Status;\r
983 CONSOLE_OUT_MODE *ModeInfo;\r
984 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;\r
985\r
986 ConOut = gST->ConOut;\r
987 MaxMode = (UINTN) (ConOut->Mode->MaxMode);\r
744fc758 988 ModeInfo = EfiLibGetVariable (VAR_CON_OUT_MODE, &gEfiGenericPlatformVariableGuid);\r
93e3992d 989\r
990 if (ModeInfo != NULL) {\r
991 CurrentCol = ModeInfo->Column;\r
992 CurrentRow = ModeInfo->Row;\r
993 for (Mode = 0; Mode < MaxMode; Mode++) {\r
994 Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);\r
995 if (!EFI_ERROR(Status)) {\r
996 if (CurrentCol == Col && CurrentRow == Row) {\r
997 CallbackData->BmmFakeNvData.ConsoleOutMode = (UINT16) Mode;\r
998 break;\r
999 }\r
1000 }\r
1001 }\r
1002 }\r
1003 SafeFreePool (ModeInfo);\r
1004}\r