BIOS/UEFI基础——EFI System Table中的输入输出

UEFI中的输入输出

UEFI下面有如下的输出函数:
1. DEBUG,它一般通过串口输出,这个是调试的时候最常用的;
2. Print,这个一般会输出到串口和显示器;
3. gST->ConOut->OutputString,这个一般也是输出到串口和显示器,其实Print也是调用的这里:
InternalPrint (Format, gST->ConOut, Marker);
4. 还有一个输出是Setup界面,但是目前还不知道它是怎么输出的;

DEBUG已经在之前的文章中写过:
这里主要讲的是gST下的ConOut(ConIn跟它类似,再这里不多讲)。
本文讲到的代码是edk2017版本的。


EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL

这个protocol的结构如下:
///
/// The SIMPLE_TEXT_OUTPUT protocol is used to control text-based output devices. 
/// It is the minimum required protocol for any handle supplied as the ConsoleOut 
/// or StandardError device. In addition, the minimum supported text mode of such 
/// devices is at least 80 x 25 characters.
///
struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
  EFI_TEXT_RESET                Reset;

  EFI_TEXT_STRING               OutputString;
  EFI_TEXT_TEST_STRING          TestString;

  EFI_TEXT_QUERY_MODE           QueryMode;
  EFI_TEXT_SET_MODE             SetMode;
  EFI_TEXT_SET_ATTRIBUTE        SetAttribute;

  EFI_TEXT_CLEAR_SCREEN         ClearScreen;
  EFI_TEXT_SET_CURSOR_POSITION  SetCursorPosition;
  EFI_TEXT_ENABLE_CURSOR        EnableCursor;

  ///
  /// Pointer to SIMPLE_TEXT_OUTPUT_MODE data.
  ///
  EFI_SIMPLE_TEXT_OUTPUT_MODE   *Mode;
};
gST->ConOut在不同的地方会初始化。
下面是在ConSplitter.c的ConSplitterDriverEntry()函数中:
  //
  // Create virtual device handle for ConOut Splitter
  //
  Status = ConSplitterTextOutConstructor (&mConOut);
  if (!EFI_ERROR (Status)) {
    Status = gBS->InstallMultipleProtocolInterfaces (
                    &mConOut.VirtualHandle,
                    &gEfiSimpleTextOutProtocolGuid,
                    &mConOut.TextOut,
                    NULL
                    );
    if (!EFI_ERROR (Status)) {
      //
      // Update the EFI System Table with new virtual console
      // and Update the pointer to Text Output protocol.
      //
      gST->ConsoleOutHandle = mConOut.VirtualHandle;
      gST->ConOut           = &mConOut.TextOut;
    }
  }
另外还有在BdsConsole.c的BdsLibConnectAllDefaultConsoles():
  if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
    SystemTableUpdated = TRUE;
  }
gST->ConOut还会跟gST->ConsoleOutHandle对应,最终跟一个gEfiSimpleTextOutProtocolGuid对应。
gEfiSimpleTextOutProtocolGuid的安装对应到不同的情况,比如对于串口就需要有gEfiSerialIoProtocolGuid,对于显示器就需要依赖于gEfiUgaDrawProtocolGuid或者gEfiGraphicsOutputProtocolGuid等与图形输出有关的protocols。
而gST->ConOut->OutputString()最终会调用这些protocols来实现输出。

这里有一个问题,即为什么一个gST->ConOut->OutputString()可以在多个位置输出,以ConSplitter.c里面为例,在ConSplitterTextOutOutputString()中有如下的代码:
  //
  // return the worst status met
  //
  for (Index = 0, ReturnStatus = EFI_SUCCESS; Index < Private->CurrentNumberOfConsoles; Index++) {
    Status = Private->TextOutList[Index].TextOut->OutputString (
                                                    Private->TextOutList[Index].TextOut,
                                                    WString
                                                    );
    if (EFI_ERROR (Status)) {
      ReturnStatus = Status;
    }
  }
这里有一个循环,可以起到多个位置打印的效果,而ConSplitterTextOutAddDevice()可以增加输出位置。

输出Protocol路线图

UEFI下为了要有输出,并且具有好的兼容性,需要有一套比较复杂的流程,要安装很多的protocols,最简单的一个形式如下:


另外还有从USB输出的,这里没有画出来。

猜你喜欢

转载自blog.csdn.net/jiangwei0512/article/details/78300713