如何直接写入屏幕?

use*_*462 21 io graphics x86 assembly

我是一个对汇编语言非常感兴趣的少年.我正在尝试在Intel x86汇编程序中编写一个小型操作系统,我想知道如何直接写入屏幕,就像不依赖于BIOS或任何其他操作系统一样.我正在查看coreboot,Linux和Kolibri等的来源,希望能够找到并理解一些执行此操作的代码.我还没有在这方面取得成功,虽然我相信我会再看一下Linux源代码,但对于我搜索过的源代码来说,这是最容易理解的.

如果有人知道这一点,或者知道我可以看到哪些源代码,我会很感激,如果他们告诉我的话.

或者更好的是,如果有人知道如何识别Intel x86 CPU上的I/O端口连接到哪个硬件,那也是值得赞赏的.我需要问的是,在英特尔64和IA-32架构软件开发人员手册第1卷:基础架构的输入/输出章节中,以及第3卷中的IN或OUT指令的章节中都没有,我能找到这些信息吗?而且因为在我拥有的资源中搜索相关指令太费劲了.

Bre*_*dan 19

第1部分

对于旧VGA模式,有一个固定地址可写入(传统)显示存储区.对于文本模式,此区域从0x000B8000开始.对于图形模式,它从0x000A0000开始.

对于高分辨率视频模式(例如由VESA/VBE接口设置的模式),这不起作用,因为传统显示存储区域的大小限制为64 KiB,大多数高分辨率视频模式需要更多空间(例如1024*768*32-bpp = 2.25 MiB).为了解决这个问题,VBE支持两种不同的方法.

第一种方法称为"银行切换",其中只有部分视频卡的显示存储器随时被映射到传统区域(您可以更改映射的部分).这可能非常混乱 - 例如,要绘制一个像素,您可能需要计算像素所在的哪个库,然后切换到该库,然后计算库中的哪个偏移量.更糟糕的是,对于某些视频模式(例如每像素有3个字节的24-bpp视频模式),只有像素数据的第一部分可能位于一个存储区中,而同一像素数据的第二部分位于不同的存储区中.这样做的主要好处是它可以与实模式寻址一起使用,因为传统的显示存储区域低于0x00100000.

第二种方法称为"线性帧缓冲器"(或仅"LFB"),其中可以访问视频卡的整个显示存储区域而无需任何杂乱的存储体切换.您必须询问此区域所在的VESA/VBE接口(并且它通常位于0xC0000000和0xFFF00000之间的"PCI孔"中).这意味着您无法在实模式下访问它,并且需要使用保护模式或长模式或"虚幻模式".

要在使用LFB模式时查找像素的地址,您需要执行类似"pixel_address = display_memory_address + y*bytes_per_line + x*bytes_per_pixel"的操作."bytes_per_line"来自VESA/VBE接口(可能与"horizo​​ntal_resolution*bytes_per_line"不同,因为水平线之间可能有填充).

对于"银行转换"的VBE/VESA模式,它变得更像:

pixel_offset = y * bytes_per_line + x * bytes_per_pixel;
bank_number = pixel_offset / bank_size;
pixel_starting_address_within_bank = pixel_offset % bank_size;
Run Code Online (Sandbox Code Playgroud)

对于一些旧的VGA模式(例如256色"模式0x13"),它与LFB非常相似,除了行之间没有填充,你可以做"pixel_address = display_memory_address +(y*horizo​​ntal_resolution + x)*bytes_per_pixel".对于文本模式,它基本上是相同的,除了2个字节确定每个字符及其属性 - 例如"char_address = display_memory_address +(y*horizo​​ntal_resolution + x)*2".对于其他旧的VGA模式(单色/双色,4色和16色模式),视频卡的内存排列完全不同.它被分成"平面",其中每个平面包含一位像素,并且(例如)在16色模式下更新一个像素,您需要写入4个单独的平面.

第2部分

对于I/O端口(在80x86上,"PC兼容性"),有3种常规类别.第一种是使用固定I/O端口的"事实上的标准"传统设备.这包括PIC芯片,ISA DMA控制器,PS/2控制器,PIT芯片,串行/并行端口等.几乎所有描述如何编程这些设备的内容都将告诉您设备使用哪些I/O端口.

下一类是传统/ ISA设备,其中设备使用的I/O端口由卡本身的跳线决定,并且没有合理的方法来确定它们从软件使用哪些I/O端口.为了解决这个问题,最终用户必须告诉OS每个设备使用哪个I/O端口.值得庆幸的是,这些暴躁的东西都已经过时了(虽然这并不一定意味着没有人使用它).

第三类是"即插即用",其中有一些方法可以询问设备使用哪个I/O端口(在大多数情况下,更改设备使用的I/O端口).这方面的一个例子是PCI,其中有一个"PCI配置空间",可以告诉您有关每个PCI设备的大量信息.对于这些类别,没有人可以确定哪些设备将在运行时使用哪个I/O端口,并且更改某些BIOS设置可能导致任何/所有这些设备更改I/O端口.

另请注意,Intel CPU只是一个CPU.没有什么能阻止这些CPU被用于与"PC兼容"计算机完全不同的东西.英特尔的CPU手册永远不会告诉您有关CPU本身以外的硬件(包括芯片组或设备)的任何信息.

第3部分

可能是获取更多信息(适用于OS开发人员/业余爱好者)的最佳位置是http://osdev.org/(他们的wiki和他们的论坛).

  • 我想补充一点,除非你为自己的操作系统构建一个GUI,否则它将节省时间,你可以花费大量时间来完成任务切换和内存管理等"有趣"的事情.PS我认为每个青少年程序员都应该编写一个操作系统;)即使它只是一个启动加载程序.你学到了很多东西 (3认同)
  • @preciousbetine 如果你可以分享你的代码(无论你认为它有多糟糕......),那么有趣的是,像我这样的人对事物如何工作的更基本的层面感兴趣。在 YouTube 上观看了 Ben Eater 的很多关于构建计算机的视频,这可能是 x86 上的 ASM 的一个很好的介绍。 (2认同)

And*_*ell 2

有点超出了我的范围,但您可能想研究一下VESA