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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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