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