GOP(Graphic Output Protocol),是用来将图形驱动程序延伸至UEFI固件的接口,借以取代传统VBIOS(视讯BIOS)在开机资源要求等初始化行为。
一、Intel GOP简介
Intel GOP(Grapshics Output Protocol )是 UEFI 定义的 Pre-OS 显示接口,目标就是提供显示的基本功能。 无论你使用何种显卡,如果想让屏幕在开机过程有所显示,必须遵从这个协议。这次简单介绍一下 Intel 的 GOP。
二、Intel GOP流程
Intel 的GOP 会放在BIOS 中,可以看作 BIOS 的一部分。
Intel Release 的 GOP有三部分:
- IntelGopDriver: 这是DXE 的GOP Driver
- IntelGraphicsPeim: 这是 PEI 阶段的 GOP。用户按下开机键后会希望尽快点亮屏幕看到提示信息,因此在 PEI 阶段点亮屏幕是非常必要的。如果希望上电就能显示,还可以去找屏幕厂商进行定制。
- VBT:GOP 的配置文件,比如:要求某个端口输出eDP 还是HDMI信号。
BIOS 会在 PEI 阶段 调用IntelGraphicsPeim,然后 DXE 阶段调用IntelGopDriver.efi。和其他的 UEFI 下的Driver一样,这两个文件是C语言编写的,如果由需要可以联系Intel FAE 索要 DEBUG 版本的 GOP。
在OS启动过程中,OS Loader会通过 ExitBootervices()通知 Driver 退出,这时 GOP 会在从系统中卸载。
但是 Intel GFX Driver会继续使用 VBT 提供的配置信息(之前的文章提到过如何在 Windows 下查找VBT)。
在 S4 和 S5 的阶段,会调用 GOP。但是 S3 和 ModernStandby 不会调用 GOP。
特别是后者,如果遇到问题通常都是 Graphics Driver的问题。
目前用于修改 VBT 进行 GOP 配置的软件是: DisCon (Display Conigureation Tool),上一代的工具是 BMP (至少用了十年以上)。
个人感觉这两种没有什么差别。使用的方法都是一个 Binary File 配合一个解释文件(BMP 用的是 BSF , DisCon 用的是 XML文件)来使用。特别注意,我感觉目前 DisCon 似乎还不稳定,有时候在解析 XML 配置文件的时候会遇到问题。出现这种问题请检查 DisCon 的版本和 VBT/Json 文件是否匹配。
特别提一下 VBT 一个新功能:LFP PnP ID。使用场景是:当你打算使用一个 VBT 支持多个LFP(Local Front Panel,内置屏幕),比如一个型号的笔记本有多个 SKU,使用了几种不同的屏幕。
之前的解决方法是在 BIOS 中放置多个 VBT,然后通过 GPIO 之类的作为 BoardID,在POST过程中Load不同的 VBT。
显而易见的是这样会比较麻烦,BIOS 改动较大(作为BIOS工程师,最好的设计就是不要BIOS修改)。
另外,还有直接在C 代码中,通过结构体来更改 VBT 数值的方法,这种方法会让接手的人一头雾水:放在BIOS 中的 VBT 和最终 OS 下 Dump 出来的结果不同。
因此,在新版的 VBT 中增加了使用 LFP PnP ID 来区分不同Panel 的方法。
在 Panel #0X 的 PnP ID 中填写你屏幕的 PnP ID 在开机过程中 GOP ,会从 Panel #01 开始扫描,如果发现有匹配的 PnP ID ,那就会使用对应的 Panel 参数 对于这个功能,如果 GOP 扫描中没有发现,那么会使用 Panel #01 的设定值;如果Select Panel Type 中没有使用Panel #FF,那么这个功能不会开启。
Protocol : 为什么要有Protocol
大家都知道,UEFI的英文翻译过来应该叫“可扩展固件接口”。
这个名词中最重要的事实上是“可扩展”这三个字。换言之,相比传统的系统固件而言,UEFI固件具备了完善的可扩展支持。
这个概念对软件行业不是一个新概念,但是对bios这样一个陈旧腐朽的东西而言,的确是一个创新的思想。
所谓可扩展的含义就是可以在系统完成后(编译为binary)之后,再次为系统增加新的功能,而不用重新rebuild整个系统。
在这个大的需求的前提下,还有一些其他的重要的含义,比如必须支持不同的组件的独立开发。
比如A厂商今天针对某硬件开发了一个驱动,他们发布了一个二进制包APackage;
而B厂商则针对另一个硬件开发了一个驱动,他们发布了一个二进制包BPackage;
现在APackage和BPackage都需要集成到bios内。
且必须以二进制的形式集成。
因为A和B厂商的知识产权需要得到尊重。
或者像OS下那样,可以通过某种方法在系统已经运行起来后加载到内存。
更好玩的是,A厂商并不希望自己需要重新从车轮开始发明。
比如他们针对的硬件是一个PCI的适配器,他们希望希望系统里已经有了诸如ReadPci()或者WritePci()这样调用来简化他们编程上的工作。
换言之,他们希望目标系统能够支持不同的二进制组件之间的运行时通讯。
支持二进制组件的运行时通讯是一个十分复杂的技术。
这里所谓的通讯,包括但不限于如下的含义:
1。 互操作。A组件自由可以调用B组件实现的函数。反过来也一样。
2。 数据传递。双方可以通过某种方法(shared memory, pipes and etc)互相交换数据。
3。 可探测。某组件必须具备探测另一个组件是否存在的能力。
4。 组件的开发必须是独立的。开发A组件不需要B组件的源代码,反之亦然。
这可以说是现代操作系统的一个核心概念。熟悉Windows的朋友可能十分清楚Windows下的COM组件,所有的COM组件都可以互相通讯的。且应用程序可以自由的使用任何一个组件提供的服务。
只有具备了这样的能力的系统才可以被叫做“可扩展”的。
而UEFI为了达到可扩展的能力,必须提供一种机制来提供支持,于是UEFI领域的专家们发明了Protocol。
Protocol : 从约定到接口
Protocol从本质上说是一种调用者与被调用者之间的“约定”。
而这种“约定”在软件开发领域有另一个更形象化的名字叫接口(Interface)。
为了做到二进制间的互操作,那么参与操作的双方(调用者与被调用者)都必须做出一定的让步,这个让步就是双方必须遵循实现商量好的调用方法(接口)。
而这种事先的约定的接口就是protocol的定义。
而这种定义尤以.h文件的形式加以实现。
谈到这里,我插一句,由于目前UEFI还是几乎是用C语言开发,基本上不存在跨语言的问题,所以Protocol才可以表达成.h文件。
而Windows下的COM的Interface,由于考虑到跨语言的问题,才专门有了一个新的通用语言叫接口定义语言(IDL,Interface Definiton Language),使用时候专门有一个IDL的compiler将IDL翻译成各个其他语言专用的表达方法(对于C语言,就是生成对应的.h文件)。
我们现在来看一个.h文件,看看一个protocol到底是怎样定义出来的。
用任意一个编辑器打开Edl/Foundation/Efi/Protocol/Include/BlockIo.h文件,这个是UEFI规范内Media Access一章中所定义的EFI_BLOCK_IO_PROTOCOL的具体定义。
实现UEFI GOP协议解决方案
我将带领你了解如何实现“UEFI GOP协议解决方案”。UEFI(Unified Extensible Firmware Interface)是一种标准的固件接口,而GOP(Graphics Output Protocol)则是UEFI中用于操作图形输出的协议。
接下来,我们将逐步进行操作,通过代码示例来演示如何解决UEFI GOP协议相关问题。
流程概览
首先,让我们来看一下实现UEFI GOP协议解决方案的整体流程,如下表所示:
步骤 | 操作 |
---|---|
1. | 初始化UEFI环境 |
2. | 获取UEFI GOP协议接口 |
3. | 设置显示模式 |
4. | 显示图形内容 |