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