【UEFI实战】UEFI图形显示(显示驱动)

news2024/11/20 10:36:42

显示驱动

OVMF BIOS使用了这个作为显卡驱动,具体图形显示的底层实现不是重点,所以这里只是简单介绍。

QemuVideoDxe是一个UEFI Driver Model,对应的EFI_DRIVER_BINDING_PROTOCOL

EFI_DRIVER_BINDING_PROTOCOL  gQemuVideoDriverBinding = {
  QemuVideoControllerDriverSupported,
  QemuVideoControllerDriverStart,
  QemuVideoControllerDriverStop,
  0x10,
  NULL,
  NULL
};
  • Supported函数的流程:
判断是否存在gEfiPciIoProtocolGuid
读取PCI Header为后续使用
QemuVideoDetect
找到支持的显卡之后返回成功

重点是QemuVideoDetect()的实现,找到的显卡:

QemuVideo: QEMU Standard VGA detected

这是QEMU模拟的显卡,具体实现可以不用关注。

  • Start函数中的初始化部分也不需要特别关注,重点在于这里安装的Protocol:
struct _EFI_GRAPHICS_OUTPUT_PROTOCOL {
  EFI_GRAPHICS_OUTPUT_PROTOCOL_QUERY_MODE    QueryMode;
  EFI_GRAPHICS_OUTPUT_PROTOCOL_SET_MODE      SetMode;
  EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT           Blt;
  ///
  /// Pointer to EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE data.
  ///
  EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE          *Mode;
};

对应的GUID是gEfiGraphicsOutputProtocolGuid,这个Protocol会被后续的UEFI显示模块使用,简称是GOP

这个Protocol的成员可以分为两类,跟Mode及相关的操作为一类,Blt为一类。前者是模式的设置,而后者的全称是Block Transfer,真正的作用就是显示输出,之所以叫这个名字,是因为实际上它做的事情就是一个数据的搬运,这个在后面会进一步说明。

Mode的结构体如下:

typedef struct {
  ///
  /// The version of this data structure. A value of zero represents the
  /// EFI_GRAPHICS_OUTPUT_MODE_INFORMATION structure as defined in this specification.
  ///
  UINT32                       Version;
  ///
  /// The size of video screen in pixels in the X dimension.
  ///
  UINT32                       HorizontalResolution;
  ///
  /// The size of video screen in pixels in the Y dimension.
  ///
  UINT32                       VerticalResolution;
  ///
  /// Enumeration that defines the physical format of the pixel. A value of PixelBltOnly
  /// implies that a linear frame buffer is not available for this mode.
  ///
  EFI_GRAPHICS_PIXEL_FORMAT    PixelFormat;
  ///
  /// This bit-mask is only valid if PixelFormat is set to PixelPixelBitMask.
  /// A bit being set defines what bits are used for what purpose such as Red, Green, Blue, or Reserved.
  ///
  EFI_PIXEL_BITMASK            PixelInformation;
  ///
  /// Defines the number of pixel elements per video memory line.
  ///
  UINT32                       PixelsPerScanLine;
} EFI_GRAPHICS_OUTPUT_MODE_INFORMATION;

typedef struct {
  ///
  /// The number of modes supported by QueryMode() and SetMode().
  ///
  UINT32                                  MaxMode;
  ///
  /// Current Mode of the graphics device. Valid mode numbers are 0 to MaxMode -1.
  ///
  UINT32                                  Mode;
  ///
  /// Pointer to read-only EFI_GRAPHICS_OUTPUT_MODE_INFORMATION data.
  ///
  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION    *Info;
  ///
  /// Size of Info structure in bytes.
  ///
  UINTN                                   SizeOfInfo;
  ///
  /// Base address of graphics linear frame buffer.
  /// Offset zero in FrameBufferBase represents the upper left pixel of the display.
  ///
  EFI_PHYSICAL_ADDRESS                    FrameBufferBase;
  ///
  /// Amount of frame buffer needed to support the active mode as defined by
  /// PixelsPerScanLine xVerticalResolution x PixelElementSize.
  ///
  UINTN                                   FrameBufferSize;
} EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE;

以上信息主要是显卡的物理参数,在显卡本身的初始化过程中就会被确定下来,后面的UEFI驱动会使用到这些参数。

下面是一个获取上述信息的代码示例(beni\BeniPkg\DynamicCommand\DisplayDynamicCommand\Display.c):

  for (Index = 0; Index < GopHandleCount; Index++) {
    Status = gBS->HandleProtocol (
                    GopHandleBuffer[Index],
                    &gEfiGraphicsOutputProtocolGuid,
                    (VOID *)&Gop
                    );
    if (EFI_ERROR (Status)) {
      continue;
    }
    Print (L"MaxMode                        : %d\r\n", Gop->Mode->MaxMode);
    Print (L"Mode                           : %d\r\n", Gop->Mode->Mode);
    Print (L"Info.Version                   : 0x%04x\r\n", Gop->Mode->Info->Version);
    Print (L"Info.HorizontalResolution      : %d\r\n", Gop->Mode->Info->HorizontalResolution);
    Print (L"Info.VerticalResolution        : %d\r\n", Gop->Mode->Info->VerticalResolution);
    Print (L"Info.PixelFormat               : %s\r\n", gPixelFormat[Gop->Mode->Info->PixelFormat]);
    Print (L"PixelInformation.RedMask       : 0x%04x\r\n",
            Gop->Mode->Info->PixelInformation.RedMask);
    Print (L"PixelInformation.GreenMask     : 0x%04x\r\n",
            Gop->Mode->Info->PixelInformation.GreenMask);
    Print (L"PixelInformation.BlueMask      : 0x%04x\r\n",
            Gop->Mode->Info->PixelInformation.BlueMask);
    Print (L"PixelInformation.ReservedMask  : 0x%04x\r\n",
            Gop->Mode->Info->PixelInformation.ReservedMask);
    Print (L"PixelsPerScanLine              : 0x%04x\r\n", Gop->Mode->Info->PixelsPerScanLine);
    Print (L"SizeOfInfo                     : %d\r\n", Gop->Mode->SizeOfInfo);
    Print (L"FrameBufferBase                : 0x%lx\r\n", Gop->Mode->FrameBufferBase);
    Print (L"FrameBufferSize                : 0x%lx\r\n", Gop->Mode->FrameBufferSize);
  }

得到的结果:

在这里插入图片描述

这里得到了两个GOP,但是实际上OVFM中只有一张虚拟的显卡,这个看上去会比较奇怪,但是实际上上述两个Protocol指向的是同一张显卡,之所以会出现两个,直接的原因就是安装了两次EFI_GRAPHICS_OUTPUT_PROTOCOL,而之所以要安装两次的原因在于ConSplitterDxe.inf模块:

  //
  // If both ConOut and StdErr incorporate the same Text Out device,
  // their MaxMode and QueryData should be the intersection of both.
  //
  Status = ConSplitterTextOutAddDevice (&mConOut, TextOut, GraphicsOutput, UgaDraw);

由于本节只讨论图形显示,所以关于UEFI的Console部分不做介绍。如果想要只获取显卡本身的信息,可以通过判断该Protocol对应的Handle是否有安装Device Path来确定,对应的示例函数:

EFI_GRAPHICS_OUTPUT_PROTOCOL *
GetSpecificGop (
  VOID
  )
{
  EFI_STATUS                    Status = EFI_NOT_FOUND;
  EFI_GRAPHICS_OUTPUT_PROTOCOL  *Gop = NULL;
  UINTN                         Index = 0;
  UINTN                         GopHandleCount = 0;
  EFI_HANDLE                    *GopHandleBuffer = NULL;
  EFI_DEVICE_PATH_PROTOCOL      *GopDevicePath = NULL;

  //
  // Get all GOP responding independent video card.
  //
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiGraphicsOutputProtocolGuid,
                  NULL,
                  &GopHandleCount,
                  &GopHandleBuffer
                  );
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_ERROR, "[%a][%d] Failed. - %r\n", __FUNCTION__, __LINE__, Status));
    goto DONE;
  }

  for (Index = 0; Index < GopHandleCount; Index++) {
    //
    // The video card should have device path.
    //
    Status = gBS->HandleProtocol (
                    GopHandleBuffer[Index],
                    &gEfiDevicePathProtocolGuid,
                    (VOID *)&GopDevicePath
                    );
    if (EFI_ERROR (Status)) {
      continue;
    }
    Status = gBS->HandleProtocol (
                    GopHandleBuffer[Index],
                    &gEfiGraphicsOutputProtocolGuid,
                    (VOID *)&Gop
                    );
    if (EFI_ERROR (Status)) {
      continue;
    } else {
      Print (L"Video card evice path: %s\r\n",
              ConvertDevicePathToText (GopDevicePath, TRUE, TRUE));
      break;
    }
  }

DONE:

  if (NULL != GopHandleBuffer) {
    FreePool (GopHandleBuffer);
    GopHandleBuffer = NULL;
  }

  return Gop;
}

下面对模式的值进行说明:

MaxMode                        : 30	# 显卡支持的所有模式
Mode                           : 0	# 当前使用的模式
Info.Version                   : 0x0000	# 模式版本信息
Info.HorizontalResolution      : 1280	# 分辨率
Info.VerticalResolution        : 800	# 分辨率
Info.PixelFormat               : PixelBlueGreenRedReserved8BitPerColor	# 像素相关的变量,跟具体的显卡有关,这里不用特别关注
PixelInformation.RedMask       : 0x0000
PixelInformation.GreenMask     : 0x0000
PixelInformation.BlueMask      : 0x0000
PixelInformation.ReservedMask  : 0x0000
PixelsPerScanLine              : 0x0500
SizeOfInfo                     : 36	# EFI_GRAPHICS_OUTPUT_MODE_INFORMATION的大小,共计36个字节
FrameBufferBase                : 0xC0000000	# 这个值实际上是显卡的MMIO Bar地址,跟下面的值一起,是底层操作需要关注的
FrameBufferSize                : 0x3E8000

GOP输出的最小单元是像素,所以这里才会涉及到各类像素相关的参数,合起来组成了模式(Mode)的概念。当前的显卡支持30种模式,通过代码可以一一读取:

  for (Index = 0; Index < Gop->Mode->MaxMode; Index++) {
    Status = Gop->QueryMode (Gop, Index, &SizeOfInfo, &ModeInfo);
    if (!EFI_ERROR (Status)) {
      Print (L"Mode                           : %d\r\n", Index);
      Print (L"Info.Version                   : 0x%04x\r\n", ModeInfo->Version);
      Print (L"Info.HorizontalResolution      : %d\r\n", ModeInfo->HorizontalResolution);
      Print (L"Info.VerticalResolution        : %d\r\n", ModeInfo->VerticalResolution);
      Print (L"Info.PixelFormat               : %s\r\n", gPixelFormat[ModeInfo->PixelFormat]);
      Print (L"PixelInformation.RedMask       : 0x%04x\r\n",
              ModeInfo->PixelInformation.RedMask);
      Print (L"PixelInformation.GreenMask     : 0x%04x\r\n",
              ModeInfo->PixelInformation.GreenMask);
      Print (L"PixelInformation.BlueMask      : 0x%04x\r\n",
              ModeInfo->PixelInformation.BlueMask);
      Print (L"PixelInformation.ReservedMask  : 0x%04x\r\n",
              ModeInfo->PixelInformation.ReservedMask);
      Print (L"PixelsPerScanLine              : 0x%04x\r\n", ModeInfo->PixelsPerScanLine);
      Print (L"SizeOfInfo                     : %d\r\n", SizeOfInfo);
      Print (L"----------------------------------------------\r\n");
      FreePool (ModeInfo);
    }

通过上述代码的打印信息可以看到的是各类模式的差别主要来自分辨率,这里不再列出。

最后简单说明如何操作像素,对应的Blt函数声明如下:

typedef
EFI_STATUS
(EFIAPI *EFI_GRAPHICS_OUTPUT_PROTOCOL_BLT)(
  IN  EFI_GRAPHICS_OUTPUT_PROTOCOL            *This,
  IN  EFI_GRAPHICS_OUTPUT_BLT_PIXEL           *BltBuffer    OPTIONAL,
  IN  EFI_GRAPHICS_OUTPUT_BLT_OPERATION       BltOperation,
  IN  UINTN                                   SourceX,
  IN  UINTN                                   SourceY,
  IN  UINTN                                   DestinationX,
  IN  UINTN                                   DestinationY,
  IN  UINTN                                   Width,
  IN  UINTN                                   Height,
  IN  UINTN                                   Delta         OPTIONAL
  );

函数的入参说明如下:

  • This:Protocol指针本身。
  • BltBufferEFI_GRAPHICS_OUTPUT_BLT_PIXEL指针,它的结构体如下:
typedef struct {
  UINT8    Blue;
  UINT8    Green;
  UINT8    Red;
  UINT8    Reserved;
} EFI_GRAPHICS_OUTPUT_BLT_PIXEL;

表示的是一个像素的三原色。比如“Blue=0,Green=0,Red=255“表示的就是一个红色的像素。

而对于BltBuffer,它表示的可以是一个像素,也可以指向像素数组来表示一个区域的所有像素的颜色。

  • BltOperation:输出的操作,其值如下:
///
/// actions for BltOperations
///
typedef enum {
  ///
  /// Write data from the BltBuffer pixel (0, 0)
  /// directly to every pixel of the video display rectangle
  /// (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height).
  /// Only one pixel will be used from the BltBuffer. Delta is NOT used.
  ///
  EfiBltVideoFill,

  ///
  /// Read data from the video display rectangle
  /// (SourceX, SourceY) (SourceX + Width, SourceY + Height) and place it in
  /// the BltBuffer rectangle (DestinationX, DestinationY )
  /// (DestinationX + Width, DestinationY + Height). If DestinationX or
  /// DestinationY is not zero then Delta must be set to the length in bytes
  /// of a row in the BltBuffer.
  ///
  EfiBltVideoToBltBuffer,

  ///
  /// Write data from the BltBuffer rectangle
  /// (SourceX, SourceY) (SourceX + Width, SourceY + Height) directly to the
  /// video display rectangle (DestinationX, DestinationY)
  /// (DestinationX + Width, DestinationY + Height). If SourceX or SourceY is
  /// not zero then Delta must be set to the length in bytes of a row in the
  /// BltBuffer.
  ///
  EfiBltBufferToVideo,

  ///
  /// Copy from the video display rectangle (SourceX, SourceY)
  /// (SourceX + Width, SourceY + Height) to the video display rectangle
  /// (DestinationX, DestinationY) (DestinationX + Width, DestinationY + Height).
  /// The BltBuffer and Delta are not used in this mode.
  ///
  EfiBltVideoToVideo,

  EfiGraphicsOutputBltOperationMax
} EFI_GRAPHICS_OUTPUT_BLT_OPERATION;
  • SourceX/SourceY:表示BltBuffer或者显示器Buffer中的一个区域的左上角的坐标。
  • DestinationX/DestinationY:表示BltBuffer或者显示器Buffer中的一个区域的左上角的坐标。关于Source和Destination具体是BltBuffer还是显示器Buffer,需要靠BltOperation来确定。
  • Width/Height:表示显示的矩形区域的长和宽。
  • Delta:它在EfiBltVideoFillEfiBltVideoToVideo操作时无效,其它时候表示BltBuffer的偏移,单位是字节。

下面是一个示例:

  SetMem (&FillColour, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
  FillColour.Red = 255;
  Status = Gop->Blt (
                  Gop,
                  &FillColour,
                  EfiBltVideoFill,
                  0,
                  0,
                  0,
                  0,
                  Gop->Mode->Info->HorizontalResolution,
                  Gop->Mode->Info->VerticalResolution,
                  0
                  );

此时是会显示一个红色的全屏:

在这里插入图片描述

这里使用了EfiBltVideoFill,而它通过一个像素(这里是一个红色的像素)铺满了一个矩形区域(这里根据后续的参数指定了整个屏幕)。

具体的代码实现可以在https://gitee.com/jiangwei0512/edk2-beni.git找到。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680687.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据库】事务、事务并发问题、并发事务隔离级别、及sql演示

文章目录 一、事务1.1 事务简介 及 sql 操作1.2 事务的特性 二、事务并发问题三、事务隔离级别四、sql 演示4.1 脏读4.2 不可重复读4.3 幻读 五、演示代码 一、事务 1.1 事务简介 及 sql 操作 事务&#xff1a;数据库执行的一系列操作&#xff0c;这些操作要么全部执行&#x…

【Java技术专题】「入门到精通系列教程」深入探索Java特性中并发编程体系的原理和实战开发指南(内存模型技术专题)

深入探索Java特性中并发编程体系的原理和实战开发指南&#xff08; 线程进阶技术专题&#xff09; 前言介绍JVM内存模型运行时数据区域堆内存栈内存 内存访问规则原子性对象类型基本类型 可见性有序性&#xff08;Happen Before法则&#xff09;系统内存&#xff08;MESI协议&a…

【OS】【期末选择题】【2023春】【仅供参考】

文章目录 题型一、选择第一章(10)第二章(19)第三章(23)第四章(32)第五章(15)第六章(15) 二、填空题三、简答题1.信号量2.调度算法3.页面置换4.虚拟地址到物理地址的映射 Reference 题型 题型题量分值选择10%填空25%10%10%解答题210’大题215’ 一、选择 第一章(10) 操作系统…

HuggingFace-RL-Unit2-Part1——Q-learning算法介绍

Q-learning算法介绍 文章目录 Q-learning算法介绍回顾: 什么是RL? 两种基于价值的方法状态价值函数动作价值函数 贝尔曼方程&#xff1a;简化价值计算蒙特卡罗 VS 时序差分学习蒙特卡洛&#xff1a;在一个回合结束后进行学习时序差分算法&#xff1a;在每一步进行学习 学习进展…

定时器的实现原理

文章目录 1.定时器的作用?2.数据结构要求3.时间轮4.分级时间轮5.业界实现方案参考文献 1.定时器的作用? 定时器的主要用途是执行定时任务。 定时任务在很多场景都需要用到&#xff0c;比如游戏的 Buff 实现&#xff0c;Redis 中的过期任务&#xff0c;Linux 中的定时任务&a…

java——多线程

文章目录 Java 的并发基础知识1. 创建线程2. 同步方法和同步代码块3. 线程安全的容器4. volatile 关键字5. Lock 和 Condition 接口 Java 多线程编程的基本框架1. 创建和启动线程2. 线程的状态转换3. 线程安全4. 死锁 Java 并发编程的高级技术1. 线程池2. 并发集合3. 原子类4. …

测试:进阶篇

在本篇章开始之前&#xff0c;先对之前的内容进行一个简单的总结回顾一下&#xff1a; 基于需求设计测试用例&#xff0c;这里有个测试用例的万能公式&#xff1a; 功能&#xff08;如果是软件&#xff0c;需要参考依据需求规格说明书&#xff1b;如果是物体&#xff0c;这个…

2023年7月电脑选择

文章目录 一、笔记本1.1 确定需求1.2 确定预算1.3 性能指标1.4 其他 二、台式电脑 最近有朋友让我推荐一下能做3D建模的笔记本电脑&#xff0c;本文就讲一下台式机和笔记本怎么选择。 一、笔记本 1.1 确定需求 当我们在选择笔记本时&#xff0c;首先需要确定自己的需求&#x…

CSS基础学习--24 表单

一、一个表单案例&#xff0c;我们使用 CSS 来渲染 HTML 的表单元素 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>CSS基础学习-表单</title> </head> <style> input[typetext], select {width:…

计算机基础--->数据结构(3)【堆(超详细)】

文章目录 堆堆的时间复杂度堆的分类堆的存储堆的操作插入元素删除堆顶元素 堆排序建堆排序 所有操作代码 堆 堆一般分为两种类型&#xff1a;最大堆和最小堆。在最大堆中&#xff0c;父节点的值总是大于或等于子节点的值&#xff0c;而在最小堆中&#xff0c;父节点的值总是小于…

计算机自我介绍500字范文(合集)

计算机自我介绍500字范文1 本人是___大学计算机系统维护专业的学生。大学四年的学习&#xff0c;积累了丰富的专业知识&#xff0c;广泛的人际关系&#xff0c;培养我成为一个敢于承担责任&#xff0c;对待生活乐观积极&#xff0c;吃苦耐劳的青年。在专业方面我的主攻方向是计…

Ffmpeg6.0版本源码解读第一期!

前言&#xff1a; 大家好&#xff0c;最近一直在直播讲解Ffmpeg6.0版本的源码解析&#xff0c;这里要明白学习源码能给我们带来什么好处&#xff1f;我相信很多小伙伴已经用过Ffmpeg去开发&#xff0c;不知道大家有没有在开发的过程&#xff0c;调用接口的时候&#xff0c;是否…

PowerDesigner面向对象建模-常用UML图

1 PowerDesigner简介 PowerDesigner最初由Xiao-Yun Wang&#xff08;王晓昀&#xff09;在SDP Technologies公司开发完成。PowerDesigner是Sybase的企业建模和设计解决方案&#xff0c;采用模型驱动方法&#xff0c;将业务与IT结合起来&#xff0c;可帮助部署有效的企业体系架…

python熟悉python基础语法,了解html网络结构,了解json格式数据,含有字符串

前言 Python网络爬虫是利用Python编写的程序&#xff0c;通过自动化地访问网页、解析html或json数据&#xff0c;并提取所需信息的技术。下面将详细介绍一些与Python网络爬虫相关的重要知识点。 1、Python基础语法&#xff1a; 变量和数据类型&#xff1a;学习如何声明变量以及…

使用R语言绘制富集条形图,轻松分析基因表达数据

一、引言 富集分析&#xff08;enrichment analysis&#xff09;是一种生物信息学方法&#xff0c;它可以帮助我们识别基因或其他的生物实体在某个特定的类别中过度表示的趋势。通俗来说&#xff0c;富集分析通过将基因分类到特定的集合中&#xff0c;然后根据基因在集合中的分…

万字长文带你深入理解JavaNIO并手动实现多人聊天室

NIO 网络编程 代码已同步至GitCode&#xff1a;https://gitcode.net/ruozhuliufeng/java-project.git Java NIO简介 IO概述 ​ IO的操作方式通常分为几种&#xff1a;同步阻塞BIO、同步非阻塞NIO、异步非阻塞AIO。 ​ &#xff08;1&#xff09;在JDK1.4之前&#xff0c;我们…

哈希表/散列表(HashTable)c++实现

目录 哈希表实现的思想 除留余数法 哈希冲突 第一种方法&#xff1a;探测法实现哈希表 探测法的思想 结点类 插入数据(insert) 冲突因子 数据扩容 哈希值 插入的代码实现以及哈希类 查找数据(find) 删除数据(erase) 第二种方法&#xff1a;拉链法实现哈希表 …

Kotlin~迭代器模式

概念 提供一种遍历集合元素的方法&#xff0c;而不暴露集合内部的实现。 角色介绍 iterator 迭代器接口: 定义访问和遍历集合元素的接口&#xff0c;一般包含next和hasNext方法。concrete iterator 具体迭代器: 实现迭代器接口&#xff0c;迭代器的核心逻辑实现。aggregate …

极致呈现系列之:Echarts热力图的神奇光晕

目录 什么是热力图热力图的特性及应用场景热力图的特性热力图的应用场景 Echarts中热力图的常用属性vue3中创建热力图 什么是热力图 热力图&#xff08;Heatmap&#xff09;是一种基于颜色映射的数据可视化图表&#xff0c;用于展示数据点的密度和分布情况。它使用不同的颜色强…