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