1. Do not use tab characters 2. No trailing white space in one line 3. All files must end with CRLF Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
		
			
				
	
	
		
			768 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			768 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Library functions which contain all the code to connect console device.
 | 
						|
 | 
						|
Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "InternalBm.h"
 | 
						|
 | 
						|
CHAR16       *mConVarName[] = {
 | 
						|
  L"ConIn",
 | 
						|
  L"ConOut",
 | 
						|
  L"ErrOut",
 | 
						|
  L"ConInDev",
 | 
						|
  L"ConOutDev",
 | 
						|
  L"ErrOutDev"
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Search out the video controller.
 | 
						|
 | 
						|
  @return  PCI device path of the video controller.
 | 
						|
**/
 | 
						|
EFI_HANDLE
 | 
						|
BmGetVideoController (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UINTN                     RootBridgeHandleCount;
 | 
						|
  EFI_HANDLE                *RootBridgeHandleBuffer;
 | 
						|
  UINTN                     HandleCount;
 | 
						|
  EFI_HANDLE                *HandleBuffer;
 | 
						|
  UINTN                     RootBridgeIndex;
 | 
						|
  UINTN                     Index;
 | 
						|
  EFI_HANDLE                VideoController;
 | 
						|
  EFI_PCI_IO_PROTOCOL       *PciIo;
 | 
						|
  PCI_TYPE00                Pci;
 | 
						|
 | 
						|
  //
 | 
						|
  // Make all the PCI_IO protocols show up
 | 
						|
  //
 | 
						|
  Status = gBS->LocateHandleBuffer (
 | 
						|
                  ByProtocol,
 | 
						|
                  &gEfiPciRootBridgeIoProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  &RootBridgeHandleCount,
 | 
						|
                  &RootBridgeHandleBuffer
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status) || (RootBridgeHandleCount == 0)) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  VideoController = NULL;
 | 
						|
  for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
 | 
						|
    gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
 | 
						|
 | 
						|
    //
 | 
						|
    // Start to check all the pci io to find the first video controller
 | 
						|
    //
 | 
						|
    Status = gBS->LocateHandleBuffer (
 | 
						|
                    ByProtocol,
 | 
						|
                    &gEfiPciIoProtocolGuid,
 | 
						|
                    NULL,
 | 
						|
                    &HandleCount,
 | 
						|
                    &HandleBuffer
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    for (Index = 0; Index < HandleCount; Index++) {
 | 
						|
      Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        // Check for all video controller
 | 
						|
        //
 | 
						|
        Status = PciIo->Pci.Read (
 | 
						|
                          PciIo,
 | 
						|
                          EfiPciIoWidthUint32,
 | 
						|
                          0,
 | 
						|
                          sizeof (Pci) / sizeof (UINT32),
 | 
						|
                          &Pci
 | 
						|
                          );
 | 
						|
        if (!EFI_ERROR (Status) && IS_PCI_VGA (&Pci)) {
 | 
						|
          // TODO: use IS_PCI_DISPLAY??
 | 
						|
          VideoController = HandleBuffer[Index];
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    FreePool (HandleBuffer);
 | 
						|
 | 
						|
    if (VideoController != NULL) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  FreePool (RootBridgeHandleBuffer);
 | 
						|
 | 
						|
  return VideoController;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Query all the children of VideoController and return the device paths of all the
 | 
						|
  children that support GraphicsOutput protocol.
 | 
						|
 | 
						|
  @param VideoController       PCI handle of video controller.
 | 
						|
 | 
						|
  @return  Device paths of all the children that support GraphicsOutput protocol.
 | 
						|
**/
 | 
						|
EFI_DEVICE_PATH_PROTOCOL *
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerGetGopDevicePath (
 | 
						|
  IN  EFI_HANDLE                       VideoController
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                                Index;
 | 
						|
  EFI_STATUS                           Status;
 | 
						|
  EFI_GUID                             **ProtocolBuffer;
 | 
						|
  UINTN                                ProtocolBufferCount;
 | 
						|
  UINTN                                ProtocolIndex;
 | 
						|
  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
 | 
						|
  UINTN                                EntryCount;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL             *DevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL             *Next;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL             *Previous;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL             *TempDevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL             *GopPool;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL             *ReturnDevicePath;
 | 
						|
 | 
						|
 | 
						|
  Status = gBS->ProtocolsPerHandle (
 | 
						|
                  VideoController,
 | 
						|
                  &ProtocolBuffer,
 | 
						|
                  &ProtocolBufferCount
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  GopPool = NULL;
 | 
						|
 | 
						|
  for (ProtocolIndex = 0; ProtocolIndex < ProtocolBufferCount; ProtocolIndex++) {
 | 
						|
    Status = gBS->OpenProtocolInformation (
 | 
						|
                    VideoController,
 | 
						|
                    ProtocolBuffer[ProtocolIndex],
 | 
						|
                    &OpenInfoBuffer,
 | 
						|
                    &EntryCount
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    for (Index = 0; Index < EntryCount; Index++) {
 | 
						|
      //
 | 
						|
      // Query all the children
 | 
						|
      //
 | 
						|
      if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
 | 
						|
        Status = gBS->OpenProtocol (
 | 
						|
                        OpenInfoBuffer[Index].ControllerHandle,
 | 
						|
                        &gEfiDevicePathProtocolGuid,
 | 
						|
                        (VOID **) &DevicePath,
 | 
						|
                        NULL,
 | 
						|
                        NULL,
 | 
						|
                        EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                        );
 | 
						|
        if (EFI_ERROR (Status)) {
 | 
						|
          continue;
 | 
						|
        }
 | 
						|
 | 
						|
        Previous = NULL;
 | 
						|
        for (Next = DevicePath; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
 | 
						|
          Previous = Next;
 | 
						|
        }
 | 
						|
        ASSERT (Previous != NULL);
 | 
						|
 | 
						|
        if (DevicePathType (Previous) == ACPI_DEVICE_PATH && DevicePathSubType (Previous) == ACPI_ADR_DP) {
 | 
						|
          Status = gBS->OpenProtocol (
 | 
						|
                          OpenInfoBuffer[Index].ControllerHandle,
 | 
						|
                          &gEfiGraphicsOutputProtocolGuid,
 | 
						|
                          NULL,
 | 
						|
                          NULL,
 | 
						|
                          NULL,
 | 
						|
                          EFI_OPEN_PROTOCOL_TEST_PROTOCOL
 | 
						|
                          );
 | 
						|
          if (!EFI_ERROR (Status)) {
 | 
						|
            //
 | 
						|
            // Append the device path to GOP pool when there is GOP protocol installed.
 | 
						|
            //
 | 
						|
            TempDevicePath = GopPool;
 | 
						|
            GopPool = AppendDevicePathInstance (GopPool, DevicePath);
 | 
						|
            gBS->FreePool (TempDevicePath);
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        if (DevicePathType (Previous) == HARDWARE_DEVICE_PATH && DevicePathSubType (Previous) == HW_CONTROLLER_DP) {
 | 
						|
          //
 | 
						|
          // Recursively look for GOP child in this frame buffer handle
 | 
						|
          //
 | 
						|
          DEBUG ((EFI_D_INFO, "[Bds] Looking for GOP child deeper ... \n"));
 | 
						|
          TempDevicePath = GopPool;
 | 
						|
          ReturnDevicePath = EfiBootManagerGetGopDevicePath (OpenInfoBuffer[Index].ControllerHandle);
 | 
						|
          GopPool = AppendDevicePathInstance (GopPool, ReturnDevicePath);
 | 
						|
          gBS->FreePool (ReturnDevicePath);
 | 
						|
          gBS->FreePool (TempDevicePath);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (OpenInfoBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (ProtocolBuffer);
 | 
						|
 | 
						|
  return GopPool;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Connect the platform active active video controller.
 | 
						|
 | 
						|
  @param VideoController       PCI handle of video controller.
 | 
						|
 | 
						|
  @retval EFI_NOT_FOUND There is no active video controller.
 | 
						|
  @retval EFI_SUCCESS   The video controller is connected.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerConnectVideoController (
 | 
						|
  EFI_HANDLE                 VideoController  OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL   *Gop;
 | 
						|
 | 
						|
  if (VideoController == NULL) {
 | 
						|
    //
 | 
						|
    // Get the platform vga device
 | 
						|
    //
 | 
						|
    VideoController = BmGetVideoController ();
 | 
						|
  }
 | 
						|
 | 
						|
  if (VideoController == NULL) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Try to connect the PCI device path, so that GOP driver could start on this
 | 
						|
  // device and create child handles with GraphicsOutput Protocol installed
 | 
						|
  // on them, then we get device paths of these child handles and select
 | 
						|
  // them as possible console device.
 | 
						|
  //
 | 
						|
  gBS->ConnectController (VideoController, NULL, NULL, FALSE);
 | 
						|
 | 
						|
  Gop = EfiBootManagerGetGopDevicePath (VideoController);
 | 
						|
  if (Gop == NULL) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  EfiBootManagerUpdateConsoleVariable (ConOut, Gop, NULL);
 | 
						|
  FreePool (Gop);
 | 
						|
 | 
						|
  //
 | 
						|
  // Necessary for ConPlatform and ConSplitter driver to start up again after ConOut is updated.
 | 
						|
  //
 | 
						|
  return gBS->ConnectController (VideoController, NULL, NULL, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Fill console handle in System Table if there are no valid console handle in.
 | 
						|
 | 
						|
  Firstly, check the validation of console handle in System Table. If it is invalid,
 | 
						|
  update it by the first console device handle from EFI console variable.
 | 
						|
 | 
						|
  @param  VarName            The name of the EFI console variable.
 | 
						|
  @param  ConsoleGuid        Specified Console protocol GUID.
 | 
						|
  @param  ConsoleHandle      On IN,  console handle in System Table to be checked.
 | 
						|
                             On OUT, new console handle in system table.
 | 
						|
  @param  ProtocolInterface  On IN,  console protocol on console handle in System Table to be checked.
 | 
						|
                             On OUT, new console protocol on new console handle in system table.
 | 
						|
 | 
						|
  @retval TRUE               System Table has been updated.
 | 
						|
  @retval FALSE              System Table hasn't been updated.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
BmUpdateSystemTableConsole (
 | 
						|
  IN     CHAR16                   *VarName,
 | 
						|
  IN     EFI_GUID                 *ConsoleGuid,
 | 
						|
  IN OUT EFI_HANDLE               *ConsoleHandle,
 | 
						|
  IN OUT VOID                     **ProtocolInterface
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  UINTN                           DevicePathSize;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL        *FullDevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL        *VarConsole;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL        *Instance;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL        *FullInstance;
 | 
						|
  VOID                            *Interface;
 | 
						|
  EFI_HANDLE                      NewHandle;
 | 
						|
  EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
 | 
						|
 | 
						|
  ASSERT (VarName != NULL);
 | 
						|
  ASSERT (ConsoleHandle != NULL);
 | 
						|
  ASSERT (ConsoleGuid != NULL);
 | 
						|
  ASSERT (ProtocolInterface != NULL);
 | 
						|
 | 
						|
  if (*ConsoleHandle != NULL) {
 | 
						|
    Status = gBS->HandleProtocol (
 | 
						|
                   *ConsoleHandle,
 | 
						|
                   ConsoleGuid,
 | 
						|
                   &Interface
 | 
						|
                   );
 | 
						|
    if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) {
 | 
						|
      //
 | 
						|
      // If ConsoleHandle is valid and console protocol on this handle also
 | 
						|
      // also matched, just return.
 | 
						|
      //
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get all possible consoles device path from EFI variable
 | 
						|
  //
 | 
						|
  GetEfiGlobalVariable2 (VarName, (VOID **) &VarConsole, NULL);
 | 
						|
  if (VarConsole == NULL) {
 | 
						|
    //
 | 
						|
    // If there is no any console device, just return.
 | 
						|
    //
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  FullDevicePath = VarConsole;
 | 
						|
 | 
						|
  do {
 | 
						|
    //
 | 
						|
    // Check every instance of the console variable
 | 
						|
    //
 | 
						|
    Instance  = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);
 | 
						|
    if (Instance == NULL) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "[Bds] No valid console instance is found for %s!\n", VarName));
 | 
						|
      // We should not ASSERT when all the console devices are removed.
 | 
						|
      // ASSERT_EFI_ERROR (EFI_NOT_FOUND);
 | 
						|
      FreePool (FullDevicePath);
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Find console device handle by device path instance
 | 
						|
    //
 | 
						|
    FullInstance = Instance;
 | 
						|
    Status = gBS->LocateDevicePath (
 | 
						|
                    ConsoleGuid,
 | 
						|
                    &Instance,
 | 
						|
                    &NewHandle
 | 
						|
                    );
 | 
						|
    FreePool (FullInstance);
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // Get the console protocol on this console device handle
 | 
						|
      //
 | 
						|
      Status = gBS->HandleProtocol (
 | 
						|
                      NewHandle,
 | 
						|
                      ConsoleGuid,
 | 
						|
                      &Interface
 | 
						|
                      );
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        // Update new console handle in System Table.
 | 
						|
        //
 | 
						|
        *ConsoleHandle     = NewHandle;
 | 
						|
        *ProtocolInterface = Interface;
 | 
						|
        if (CompareGuid (ConsoleGuid, &gEfiSimpleTextOutProtocolGuid)) {
 | 
						|
          //
 | 
						|
          // If it is console out device, set console mode 80x25 if current mode is invalid.
 | 
						|
          //
 | 
						|
          TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *) Interface;
 | 
						|
          if (TextOut->Mode->Mode == -1) {
 | 
						|
            TextOut->SetMode (TextOut, 0);
 | 
						|
          }
 | 
						|
        }
 | 
						|
        FreePool (FullDevicePath);
 | 
						|
        return TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
  } while (Instance != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // No any available console devcie found.
 | 
						|
  //
 | 
						|
  FreePool (FullDevicePath);
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function updates the console variable based on ConVarName. It can
 | 
						|
  add or remove one specific console device path from the variable
 | 
						|
 | 
						|
  @param  ConsoleType              ConIn, ConOut, ErrOut, ConInDev, ConOutDev or ErrOutDev.
 | 
						|
  @param  CustomizedConDevicePath  The console device path to be added to
 | 
						|
                                   the console variable. Cannot be multi-instance.
 | 
						|
  @param  ExclusiveDevicePath      The console device path to be removed
 | 
						|
                                   from the console variable. Cannot be multi-instance.
 | 
						|
 | 
						|
  @retval EFI_UNSUPPORTED          The added device path is the same as a removed one.
 | 
						|
  @retval EFI_SUCCESS              Successfully added or removed the device path from the
 | 
						|
                                   console variable.
 | 
						|
  @retval others                   Return status of RT->SetVariable().
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerUpdateConsoleVariable (
 | 
						|
  IN  CONSOLE_TYPE              ConsoleType,
 | 
						|
  IN  EFI_DEVICE_PATH_PROTOCOL  *CustomizedConDevicePath,
 | 
						|
  IN  EFI_DEVICE_PATH_PROTOCOL  *ExclusiveDevicePath
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *VarConsole;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *TempNewDevicePath;
 | 
						|
 | 
						|
  if (ConsoleType >= ARRAY_SIZE (mConVarName)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Notes: check the device path point, here should check
 | 
						|
  // with compare memory
 | 
						|
  //
 | 
						|
  if (CustomizedConDevicePath == ExclusiveDevicePath) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Delete the ExclusiveDevicePath from current default console
 | 
						|
  //
 | 
						|
  GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **) &VarConsole, NULL);
 | 
						|
  //
 | 
						|
  // Initialize NewDevicePath
 | 
						|
  //
 | 
						|
  NewDevicePath = VarConsole;
 | 
						|
 | 
						|
  //
 | 
						|
  // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.
 | 
						|
  // In the end, NewDevicePath is the final device path.
 | 
						|
  //
 | 
						|
  if (ExclusiveDevicePath != NULL && VarConsole != NULL) {
 | 
						|
      NewDevicePath = BmDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Try to append customized device path to NewDevicePath.
 | 
						|
  //
 | 
						|
  if (CustomizedConDevicePath != NULL) {
 | 
						|
    if (!BmMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
 | 
						|
      //
 | 
						|
      // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
 | 
						|
      //
 | 
						|
      NewDevicePath = BmDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);
 | 
						|
      //
 | 
						|
      // In the first check, the default console variable will be _ModuleEntryPoint,
 | 
						|
      // just append current customized device path
 | 
						|
      //
 | 
						|
      TempNewDevicePath = NewDevicePath;
 | 
						|
      NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);
 | 
						|
      if (TempNewDevicePath != NULL) {
 | 
						|
        FreePool(TempNewDevicePath);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Finally, Update the variable of the default console by NewDevicePath
 | 
						|
  //
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  mConVarName[ConsoleType],
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
 | 
						|
                                                  | ((ConsoleType < ConInDev) ? EFI_VARIABLE_NON_VOLATILE : 0),
 | 
						|
                  GetDevicePathSize (NewDevicePath),
 | 
						|
                  NewDevicePath
 | 
						|
                  );
 | 
						|
 | 
						|
  if (VarConsole == NewDevicePath) {
 | 
						|
    if (VarConsole != NULL) {
 | 
						|
      FreePool(VarConsole);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    if (VarConsole != NULL) {
 | 
						|
      FreePool(VarConsole);
 | 
						|
    }
 | 
						|
    if (NewDevicePath != NULL) {
 | 
						|
      FreePool(NewDevicePath);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Connect the console device base on the variable ConsoleType.
 | 
						|
 | 
						|
  @param  ConsoleType              ConIn, ConOut or ErrOut.
 | 
						|
 | 
						|
  @retval EFI_NOT_FOUND            There is not any console devices connected
 | 
						|
                                   success
 | 
						|
  @retval EFI_SUCCESS              Success connect any one instance of the console
 | 
						|
                                   device path base on the variable ConVarName.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerConnectConsoleVariable (
 | 
						|
  IN  CONSOLE_TYPE              ConsoleType
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *StartDevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *Instance;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *Next;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevicePath;
 | 
						|
  UINTN                     Size;
 | 
						|
  BOOLEAN                   DeviceExist;
 | 
						|
  EFI_HANDLE                Handle;
 | 
						|
 | 
						|
  if ((ConsoleType != ConIn) && (ConsoleType != ConOut) && (ConsoleType != ErrOut)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Status      = EFI_SUCCESS;
 | 
						|
  DeviceExist = FALSE;
 | 
						|
  Handle      = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check if the console variable exist
 | 
						|
  //
 | 
						|
  GetEfiGlobalVariable2 (mConVarName[ConsoleType], (VOID **) &StartDevicePath, NULL);
 | 
						|
  if (StartDevicePath == NULL) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyOfDevicePath = StartDevicePath;
 | 
						|
  do {
 | 
						|
    //
 | 
						|
    // Check every instance of the console variable
 | 
						|
    //
 | 
						|
    Instance  = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);
 | 
						|
    if (Instance == NULL) {
 | 
						|
      FreePool (StartDevicePath);
 | 
						|
      return EFI_UNSUPPORTED;
 | 
						|
    }
 | 
						|
 | 
						|
    Next      = Instance;
 | 
						|
    while (!IsDevicePathEndType (Next)) {
 | 
						|
      Next = NextDevicePathNode (Next);
 | 
						|
    }
 | 
						|
 | 
						|
    SetDevicePathEndNode (Next);
 | 
						|
    //
 | 
						|
    // Connect the USB console
 | 
						|
    // USB console device path is a short-form device path that
 | 
						|
    //  starts with the first element being a USB WWID
 | 
						|
    //  or a USB Class device path
 | 
						|
    //
 | 
						|
    if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
 | 
						|
        ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP) || (DevicePathSubType (Instance) == MSG_USB_WWID_DP))
 | 
						|
       ) {
 | 
						|
      Status = BmConnectUsbShortFormDevicePath (Instance);
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        DeviceExist = TRUE;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      for (Next = Instance; !IsDevicePathEnd (Next); Next = NextDevicePathNode (Next)) {
 | 
						|
        if (DevicePathType (Next) == ACPI_DEVICE_PATH && DevicePathSubType (Next) == ACPI_ADR_DP) {
 | 
						|
          break;
 | 
						|
        } else if (DevicePathType (Next) == HARDWARE_DEVICE_PATH &&
 | 
						|
                   DevicePathSubType (Next) == HW_CONTROLLER_DP &&
 | 
						|
                   DevicePathType (NextDevicePathNode (Next)) == ACPI_DEVICE_PATH &&
 | 
						|
                   DevicePathSubType (NextDevicePathNode (Next)) == ACPI_ADR_DP
 | 
						|
                   ) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if (!IsDevicePathEnd (Next)) {
 | 
						|
        //
 | 
						|
        // For GOP device path, start the video driver with NULL remaining device path
 | 
						|
        //
 | 
						|
        SetDevicePathEndNode (Next);
 | 
						|
        Status = EfiBootManagerConnectDevicePath (Instance, &Handle);
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          gBS->ConnectController (Handle, NULL, NULL, TRUE);
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        Status = EfiBootManagerConnectDevicePath (Instance, NULL);
 | 
						|
      }
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        // Delete the instance from the console varialbe
 | 
						|
        //
 | 
						|
        EfiBootManagerUpdateConsoleVariable (ConsoleType, NULL, Instance);
 | 
						|
      } else {
 | 
						|
        DeviceExist = TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    FreePool(Instance);
 | 
						|
  } while (CopyOfDevicePath != NULL);
 | 
						|
 | 
						|
  FreePool (StartDevicePath);
 | 
						|
 | 
						|
  if (!DeviceExist) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  This function will search every input/output device in current system,
 | 
						|
  and make every input/output device as potential console device.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerConnectAllConsoles (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                     Index;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *ConDevicePath;
 | 
						|
  UINTN                     HandleCount;
 | 
						|
  EFI_HANDLE                *HandleBuffer;
 | 
						|
 | 
						|
  Index         = 0;
 | 
						|
  HandleCount   = 0;
 | 
						|
  HandleBuffer  = NULL;
 | 
						|
  ConDevicePath = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Update all the console variables
 | 
						|
  //
 | 
						|
  gBS->LocateHandleBuffer (
 | 
						|
          ByProtocol,
 | 
						|
          &gEfiSimpleTextInProtocolGuid,
 | 
						|
          NULL,
 | 
						|
          &HandleCount,
 | 
						|
          &HandleBuffer
 | 
						|
          );
 | 
						|
 | 
						|
  for (Index = 0; Index < HandleCount; Index++) {
 | 
						|
    gBS->HandleProtocol (
 | 
						|
            HandleBuffer[Index],
 | 
						|
            &gEfiDevicePathProtocolGuid,
 | 
						|
            (VOID **) &ConDevicePath
 | 
						|
            );
 | 
						|
    EfiBootManagerUpdateConsoleVariable (ConIn, ConDevicePath, NULL);
 | 
						|
  }
 | 
						|
 | 
						|
  if (HandleBuffer != NULL) {
 | 
						|
    FreePool(HandleBuffer);
 | 
						|
    HandleBuffer = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->LocateHandleBuffer (
 | 
						|
          ByProtocol,
 | 
						|
          &gEfiSimpleTextOutProtocolGuid,
 | 
						|
          NULL,
 | 
						|
          &HandleCount,
 | 
						|
          &HandleBuffer
 | 
						|
          );
 | 
						|
  for (Index = 0; Index < HandleCount; Index++) {
 | 
						|
    gBS->HandleProtocol (
 | 
						|
            HandleBuffer[Index],
 | 
						|
            &gEfiDevicePathProtocolGuid,
 | 
						|
            (VOID **) &ConDevicePath
 | 
						|
            );
 | 
						|
    EfiBootManagerUpdateConsoleVariable (ConOut, ConDevicePath, NULL);
 | 
						|
    EfiBootManagerUpdateConsoleVariable (ErrOut, ConDevicePath, NULL);
 | 
						|
  }
 | 
						|
 | 
						|
  if (HandleBuffer != NULL) {
 | 
						|
    FreePool(HandleBuffer);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Connect all console variables
 | 
						|
  //
 | 
						|
  EfiBootManagerConnectAllDefaultConsoles ();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  This function will connect all the console devices base on the console
 | 
						|
  device variable ConIn, ConOut and ErrOut.
 | 
						|
 | 
						|
  @retval EFI_DEVICE_ERROR         All the consoles were not connected due to an error.
 | 
						|
  @retval EFI_SUCCESS              Success connect any one instance of the console
 | 
						|
                                   device path base on the variable ConVarName.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
EfiBootManagerConnectAllDefaultConsoles (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  BOOLEAN                   OneConnected;
 | 
						|
  BOOLEAN                   SystemTableUpdated;
 | 
						|
 | 
						|
  OneConnected = FALSE;
 | 
						|
 | 
						|
  Status = EfiBootManagerConnectConsoleVariable (ConOut);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    OneConnected = TRUE;
 | 
						|
  }
 | 
						|
  PERF_EVENT ("ConOutReady");
 | 
						|
 | 
						|
 | 
						|
  Status = EfiBootManagerConnectConsoleVariable (ConIn);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    OneConnected = TRUE;
 | 
						|
  }
 | 
						|
  PERF_EVENT ("ConInReady");
 | 
						|
 | 
						|
  Status = EfiBootManagerConnectConsoleVariable (ErrOut);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    OneConnected = TRUE;
 | 
						|
  }
 | 
						|
  PERF_EVENT ("ErrOutReady");
 | 
						|
 | 
						|
  SystemTableUpdated = FALSE;
 | 
						|
  //
 | 
						|
  // Fill console handles in System Table if no console device assignd.
 | 
						|
  //
 | 
						|
  if (BmUpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {
 | 
						|
    SystemTableUpdated = TRUE;
 | 
						|
  }
 | 
						|
  if (BmUpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
 | 
						|
    SystemTableUpdated = TRUE;
 | 
						|
  }
 | 
						|
  if (BmUpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
 | 
						|
    SystemTableUpdated = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (SystemTableUpdated) {
 | 
						|
    //
 | 
						|
    // Update the CRC32 in the EFI System Table header
 | 
						|
    //
 | 
						|
    gST->Hdr.CRC32 = 0;
 | 
						|
    gBS->CalculateCrc32 (
 | 
						|
          (UINT8 *) &gST->Hdr,
 | 
						|
          gST->Hdr.HeaderSize,
 | 
						|
          &gST->Hdr.CRC32
 | 
						|
          );
 | 
						|
  }
 | 
						|
 | 
						|
  return OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR;
 | 
						|
}
 |