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 < ARRAY_SIZE (DataBitsList); AttributeIndex++) {
1171 if (NewTerminalContext->DataBits == (UINT64) (DataBitsList[AttributeIndex].Value)) {
1172 NewTerminalContext->DataBitsIndex = AttributeIndex;
1173 break;
1174 }
1175 }
1176
1177 for (AttributeIndex = 0; AttributeIndex < ARRAY_SIZE (ParityList); AttributeIndex++) {
1178 if (NewTerminalContext->Parity == (UINT64) (ParityList[AttributeIndex].Value)) {
1179 NewTerminalContext->ParityIndex = AttributeIndex;
1180 break;
1181 }
1182 }
1183
1184 for (AttributeIndex = 0; AttributeIndex < ARRAY_SIZE (StopBitsList); 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