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