如何在不使用BIOS的情况下向显卡写入数据?

How to write data to a graphics card without using BIOS?

我想做一个(非常简单的)操作系统。我目前正在学习显卡。

这是我目前知道的(如有错误请指正):

我想做的是不使用 BIOS 直接写入显卡的显存(因为我想了解它是如何工作的)。所以我有以下问题:

  1. 怎么知道显卡显存的基地址是多少,是这个 通过探测 PCI 总线以获取基地址来完成,或者基地址是固定的(例如,就像 COM 端口基地址是固定的一样)?
  2. 是否所有显卡都以相同的方式访问,还是我必须为所有可用的显卡创建设备驱动程序?

编辑: 我正在使用 x86。

简介

显卡是一个非常复杂的主题,我可以自信地说它们是您在 PC 上可以找到的复杂的子系统。
如果您发现自己迷失了 XHCI (USB 3.0) or an old RTL8239A 网络接口卡的编程,那么请做好准备,因为这要复杂得多。

图形控制器是市场竞争非常激烈的产品 - rarely a vendor opens the specifications当它出现时,它会故意提供较差的支持。
如果你加上硬件本身处理:codecs, audio (yes, audio streams too), 3D programmable pipelines, video signals and video outputs, surface formats, media formats, DMA and memory remapping 那么你可以看到对视频卡进行编程并不是一件容易的事。

在我看来,更好的方法是 "retrace the history" 显卡。 从 MDA then move to CGA then EGA and finally to VGA.

开始

仍然支持 VGA legacy,规格可以从 Intel 找到 here or in the first part of this PDF
您可以在没有 BIOS "easily" 的情况下对 VGA 进行编程 - 这意味着它是一个已经众所周知且有文档记录的硬件架构(但不一定易于配置)。
我不记得以前的适配器是否是 VGA 的子集,如果不是,可能不再支持它们。
您可以尝试使用虚拟机或模拟器。

当您对 VGA 感到满意时,您可以移动到 SVGA
麻烦来了:正如维基百科证实的那样,VGA 是最后一个真正标准化的视频 card/adapter 接口:

Unlike VGA—a purely IBM-defined standard—Super VGA was never formally defined.

VESA 组织标准化了一个名为 Video BIOS Extensions 的 BIOS API 以允许将 SVGA 卡用于无人驾驶 OSes 但这不是你要找的.
您可以尝试对 VBE BIOS 进行逆向工程,但我认为这将是一场噩梦 - 对 IO 端口和 MMIO 的毫无意义的写入流。
在没有任何参考的情况下理解十分之一的配置寄存器几乎是不可能的。

请注意,到目前为止我们仍在谈论 1998 年的技术。
在 VESA VBE 努力之后,没有发布更多的标准接口 - 对不到 20 年的视频卡进行编程的唯一可靠方法是与其供应商签署 NDA。

幸运的是,最近(实际上,不再是),英特尔凭借其英特尔 GFX(a.k.a。英特尔高清显卡)卡进入市场。
英特尔从未打算制造一流的视频卡,甚至没有密切关注 - 因此他们可以公开他们的架构,因为这不是他们的核心业务。
结果是这组描述其视频卡功能的精彩 Programming Reference Manuals
完成(传统的)最少的信息来对它们进行编程。

一般爱好者在这个点之前(在SVGA检查点)就停止了,因为硬件变得非常复杂并且工作量非常大。
例如,我的 Haswell 集成视频卡记录了 17 个 PDF,每个约 250 页(平均)。
显示部分单独记录在 PDF 中,帧缓冲区已消失,取而代之的是 显示表面 ,硬件的显示部分是这样的:

虽然这可能不是很容易理解,但足以了解程序员在对现代视频卡进行编程之前必须了解的众多技术。

您当然可以查看 Linux 源代码,但请注意 Linux 内核即使对于简单的控制器也通常无法立即理解 - 它不是玩具 OS,它是一个真正的 OS,它有自己的 API 和必须适合硬件接口的接口(实际上是相反的方式)。
此外,只有 Intel 和 AMD 视频驱动程序是真正开源的,其他的要么是专有的,要么只是一堆未记录的代码。

常见 VGA 模式编程的简要概述

如果您只想对 VGA 进行编程(确实是一项非常值得尊敬的任务!),您可以从 setting the video modes 03h(文本模式)或 13h(图形模式)开始。

视频模式03h
帧缓冲区位于 0b8000h(物理地址),通常作为 0b800h:0000h 访问,因为零偏移量很方便。
屏幕由80x25个字符组成,每个字符在帧缓冲区中占用一个字(16位)。
低字节是字符代码 - 使用的字符映射会将 glyph 关联到代码(例如 41h 到 A)。
高位字节为属性字节-低四位为前景色,高位为背景色。
可以在上面的 EGA/CGA/VGA 链接中找到更多信息。

视频模式 13h
这是一个 320x200 像素的图形模式,帧缓冲区位于 0a0000h(物理地址),出于与上述相同的原因,通常访问为 0a000h:0000h。
每个像素都是一个字节,字节的值选择像素的颜色。
可以通过编程 DAC 寄存器(VGA 适配器为 3c7h、3c8h、3c9h)来更改默认调色板。

答案

A graphics card has two modes: a text mode, and a graphics mode.

不一定,今天这种区别可能已经不存在了。
MDA 只有文本模式。
EGA、CGA和VGA、SVGA都有。

现代方法是绘制文本,但是在启动期间或在特定情况下(例如 BSOD)使用文本模式下的基本视频驱动程序。
该驱动程序可能使用 BIOS 服务,因为视频驱动程序可能不是 available/reliable。

You can write data to a graphics cards using BIOS

直到 SVGA 时代,BIOS 支持才停止。

How do I know what is the base address of the video memory of the graphics card, is this done by probing the PCI bus to get the base address, or is the base address fixed (just like the COM ports base addresses is fixed for example)?

显卡在历史上一直连接到 ISA、PCI、AGP 和 PCIe 总线。
只有 ISA 总线不可配置(至少从一开始就不是),其他总线的每个功能(PCI 总线中最小的可寻址实体)都有可配置的 BAR(基地址寄存器)。

为了获得显卡 MMIO 寄存器的基地址,PCI 或 PCIe 总线 must be enumerated 和配置 space 中的标准寄存器必须是 read/set。

处理 PCIe 不像处理 PCI 那样容易。

请注意,即使是 UART 也没有固定地址,它们默认配置为映射到旧版(3f8h、2f8h、3e8h 和 2e8h)地址,但硬件是(是?)在 SuperIO 模拟 PCI-to-ISA 桥的 PCI-to-LPC 桥后面的芯片。
随着英特尔平台集线器架构的出现(即南北桥的死亡),SuperIO 芯片最终进入了PCH or moved behind the SPI controller

Are all graphics cards accessed in the same way, or do I have to create device drivers for all available graphics cards?

每张显卡本身就是一个美丽的邪恶生物。
每个型号都需要一个设备驱动程序。
某些驱动程序可以重复用于整个系列的模型,但通常情况并非如此。