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

Posted

技术标签:

【中文标题】如何在不使用 BIOS 的情况下将数据写入显卡?【英文标题】:How to write data to a graphics card without using BIOS? 【发布时间】:2017-11-10 15:03:27 【问题描述】:

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

这是我目前所知道的(如果我错了,请纠正我):

显卡有两种模式:文本模式和图形模式。 您可以使用 Bios 将数据写入显卡(而不是直接访问显卡)。

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

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

编辑:我使用的是 x86。

【问题讨论】:

最简单的就是坚持VGA兼容的东西。 VGA 卡有不止两种模式。例如,16 色 EGA 模式、256 色 320x100“模式 13h”模式和早期的 SVGA 模式之间存在巨大差异,虽然您可以直接写入 VRAM,但它们的基本指针和 VRAM 的组织方式完全不同。而且所有的显卡都不一样,你必须为特定的一个创建驱动程序,唯一有点标准化的方式是早期PC时代的CGA/EGA/VGA标准,而VESA(SVGA)确实适用于许多显卡,但由于3D加速卡时代,您需要特定卡的特定驱动程序(它们可能已模拟 VGA) 在我年轻的时候,我使用了Ferraro 的 EGA 和 VGA 显卡程序员指南。如果您的环境允许直接 R/W 图形控制器。 现代显卡都兼容 VGA,但不一定在每个小细节上都 100% 兼容。 VGA 兼容性将您限制为 16 色的 648x480 和 256 色的 320x200,尽管您不介意使用非标准模式,您可以使用 16 色实现 800x600。如果您想超越这些分辨率,那么您需要为所有各种类型的视频卡安装驱动程序。 物理内存不是虚拟的。 【参考方案1】:

简介

显卡是一个非常复杂的话题,我有信心说它们是您在 PC 上找到的最复杂的子系统。 如果您发现自己在编写XHCI (USB 3.0) 或旧的RTL8239A 网络接口卡时迷失了方向,请做好准备,因为这要复杂得多。

图形控制器是竞争激烈的营销产品 - rarely a vendor opens the specifications,当它出现时,它会故意提供糟糕的支持。 如果您添加硬件本身处理:codecs、audio (yes, audio streams too)、3D programmable pipelines、video signals and video outputs、表面格式、媒体格式、DMA and memory remapping,那么您会发现编写视频并不是一件容易的事卡片。

在我看来,更好的方法是“追溯视频卡的历史”。 从MDA 开始,然后移动到CGA,然后是EGA,最后是VGA。

仍然支持 VGA 旧版,规格可以在 here 或英特尔的 this PDF 的第一部分找到。 您可以“轻松”地在没有 BIOS 的情况下对 VGA 进行编程 - 这意味着它是一种众所周知且有文档记录的硬件架构(但不一定易于配置)。 我不记得以前的适配器是否是 VGA 的子集,如果不是,它们可能不再受支持。 您可以尝试使用虚拟机或模拟器。

如果您对 VGA 感到满意,您可以转到 SVGA。 麻烦来了:正如***所证实的,VGA 是最后一个真正标准化的视频卡/适配器接口:

与 VGA(纯 IBM 定义的标准)不同,Super VGA 从未正式定义。

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

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

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

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

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

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

常见VGA模式编程简述

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

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

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

答案

显卡有两种模式:文本模式和图形模式。

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

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

您可以使用 BIOS 将数据写入显卡

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

我怎么知道显卡显存的基地址是什么,是通过探测PCI总线得到基地址,还是基地址是固定的(就像COM口基地址是例如固定)?

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

为了获得显卡的 MMIO 寄存器的基地址,必须读取/设置 PCI 或 PCIe 总线 must be enumerated 和配置空间中的标准寄存器。

处理PCIe并不像处理PCI那么容易。

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

是否所有显卡都以相同的方式访问,还是我必须为所有可用的显卡创建设备驱动程序?

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

【讨论】:

“我不记得以前的适配器是否是 VGA 的子集。” EGA 在很大程度上是 VGA 的子集。或者,更准确地说,VGA 是 EGA 的超集。不过,这并不意味着它会受到现代机器(或模拟器)的支持。几乎所有东西都假设 VGA 作为基线,并且会尝试使用 VGA 模式,这可能会损坏(或至少无法在)EGA 卡。当然,老式系统的模拟器是另一回事。

以上是关于如何在不使用 BIOS 的情况下将数据写入显卡?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不写入磁盘的情况下将 XML 从 Delphi 传递到 C#?

如何在不使用 HDP 3.1 中的仓库连接器的情况下将表从 spark 中写入 hive

如何在不使用 PHP 将文件写入磁盘的情况下将文件发布到 REST 服务器?

如何在不知道编码的情况下将字节写入 Python 3 中的文件?

如何在不写入磁盘的情况下将 AWS S3 上的文本文件导入 pandas

如何在不覆盖现有记录的情况下将新行添加到数据表