????????显卡用于连接CPU和显示器,我们调用显示器时,其实就是利用显卡提供的IO接口间接地对显示器进行操作,所以显卡也称之为显示适配器。接下来我们将优化之前写的MBR程序(参考:【操作系统】BIOS与MBR之间的过渡实践),使我们的程序通过直接操作显卡来输出,显卡给我们的输入接口有显存和端口,而本文中主要用到显存。
????????如果看过我之前发过的文章(参考:【操作系统】BIOS开机自检)就可以知道,内存布局中关于显存地址分布如下:
????????显卡支持三种模式:文本模式、黑白图形模式以及彩色图形模式,本文中我们将使用文本模式,以实现类似Linux控制台风格的字符界面。从起始地址0XB800到C7FFF这片32KB大小的内存区域用于文本显示,我们只需要把要显示在显示器上的字符直接输入到0XB800开始的显存中,显存有了数据,会直接将数据搬到显示器屏幕上,至于数据怎么搬到屏幕上的不用我们了解,我们只要保证写入的数据符合格式就好了。
???????? 由于在文本模式下,字符不仅可以显示黑白颜色,也可以打印出彩色,所以每个显示在屏幕上的字符都由2个连续的字节表示,一个字节存储ASCII码的数据,另一个字节存储字符的属性:
????????在屏幕上每个字符的低字节是字符的ASCII码,高字节属于字符的属性信息,其中低4位是字符前景色,高4位是字符背景色,颜色由RGB三色调和,第11位和第15位分别控制亮度位以及是否闪烁(1为高亮/闪烁,0为正常/不闪)。
????????有了上面的知识,我们就可以通过改编之前的MBR程序来调用显存了,代码如下:
????????我们保留原先的MBR程序滚屏的操作,将通过BIOS输出改成通过显存输出。我们重点来分析第9~10行,以及第19~32行代码,其他代码在另外一篇文章已经解析过了,不再次赘述。
????????在第一节我们已经知道,内存地址0XB8000为显存的文本模式,在实模式下,内存的访址方式是“段基址×16+段内偏移地址”,所以我们直接在段寄存器gs(通过通用寄存器ax中转,原因已在上一篇文章说明,不再赘述)中存入0xb800即可。在此有个小知识点:在进行内存访址时,CPU将ds作为默认的段基址寄存器,如果不用CPU默认寄存器,我们就需要自行指定具体的段基址寄存器,而这个行为叫做“段跨越前缀”。
9 mov ax,0xb800
10 mov gs,ax
????????我们直接拿前面两段作为例子,后面的都是大同小异:
????????“mov ?byte [gs:0x00] ‘1’”是以gs为段基址寄存器,以0为偏移地址起始的内存中,写入大小为1byte大小的字符为”1”的ASCII码,当然,如果你对ACSII码十分熟悉,也可以写成“mov ?byte [gs:0x00] 0x31”。
???????? 而第二行则是字符的属性,具体参数可以参照上文中所提及的。
?????????代码编写完成后,我们保存一下代码(本文保存文件名为A.S),并且使用nasm对代码进行编译:
nasm ?–o ?A.bin ?A.S
????????此时,我们就可以开始运行调试了,我们需要用到之前写过的一篇文章(【操作系统】Bochs安装和配置)里面的两个东西:
? ? ? ? 我们首先将生成的A.bin文件写入到空白镜像中:
dd ?if=./A.bin ?of=./test.img ?bs=512 ?count=1 ?conv=notrunc
????????上述代码的具体参数可以自行百度,不再次赘述,将代码写入到镜像后,我们再将镜像文件加入到Bochs的模拟硬件环境配置文件中,根据文章中所描述的,我们直接将新生成的镜像写入配置文件的以下位置即可:
? ? ? ? 保存一下修改后的配置文件,我们开始运行Bochs模拟器进行模拟操作:
./Bochs ?–f ? boch.disk(你自己的硬件配置文件名)
?????????运行成功后,会显示以下信息,并且默认为【6】:
? ? ? ? 此时我们再按一次回车,即可开始模拟:
? ? ? ? 我们在控制台中输入“c”(具体含义请查看上面所说的文章),继续往下运行,就能看到弹出的窗口中出现了我们所要的字符串: