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