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