自制操作系统Antz(3)——进入保护模式 (中) 直接操作显存

Antz系统更新地址: https://www.cnblogs.com/LexMoon/category/1262287.html

Linux内核源码分析地址:https://www.cnblogs.com/LexMoon/category/1267413.html

  目前已经完成了MBR的雏形,虽然有些简陋,比如我们的屏幕显示还是使用的BIOS中断,而在BIOS中断向量表只有在实模式下存在,

我们要进入保护模式之后就无法使用了。此次我们要完成直接操作显存来进行屏幕显示。

0.  关于显存

  如果要说显存,那必须先说说显卡,其实BIOS的中断关于屏幕操作底层也是通过操作显卡实现的,封装成显存只是为了我们操作方便。既然要完成屏幕打印,那么就要在显示器和CPU之间建立链接,也就是IO接口,也叫做适配器,显卡就是显示适配器,连接了CPU和显示器,显卡也有自己的CPU,叫做GPU,显存是由显卡提供的,是显卡内部的一块内存。显示器会将显存里面的数据显示出来,而对于显示器而言,它不会去管这些数据是文本还是图像,对于它来说,一切都是图像,一切都是下像素的位置和像素颜色的信息。

  如同计算机的内存一样,显存是用来存储要处理的图形信息的部件。我们在显示屏上看到的画面是由一个个的像素点构成的,而每个像素点都以4至32甚至64位的数据来控制它的亮度和色彩,这些数据必须通过显存来保存,再交由显示芯片和CPU调配,最后把运算结果转化为图形输出到显示器上。

  显存和主板内存一样,执行存贮的功能,但它存贮的对像是显卡输出到显示器上的每个像素的信息。显存是显卡非常重要的组成部分,显示芯片处理完数据后会将数据保存到显存中,然后由RAMDAC(数模转换器)从显存中读取出数据并将数字信号转换为模拟信号,最后由屏幕显示出来。在高级的图形加速卡中,显存不仅用来存储图形数据,而且还被显示芯片用来进行3D函数运算。在nVIDIA等高级显示芯片中,已发展出和CPU平行的“GPU”(图形处理单元)。“T&L”(变形和照明)等高密度运算由GPU在显卡上完成,由此更加重了对显存的依赖。由于显存在显卡上所起的作用,显然显存的速度和带宽直接影响到显卡的整体速度。显存作为存贮器也和主板内存一样经历了多个发展阶段,甚至可以说显存的发展比主板内存更为活跃,并有着更多的品种和类型。被广泛使用的显存类型是SDRAM和SGRAM,性能更加优异的DDR内存首先被应用到显卡上,促进了显卡整体性能的提高。DDR以在显卡上的成功为先导,全面发展到了主板系统,一个DDR“独领风骚三两年”的时代即将呈现在世人面前。

  显卡的工作原理是:在显卡开始工作(图形渲染建模)前,通常是把所需要的材质和纹理数据传送到显存里面。开始工作时候(进行建模渲染),这些数据通过AGP总线进行传输,显示芯片将通过AGP总线提取存储在显存里面的数据,除了建模渲染数据外还有大量的顶点数据和工作指令流需要进行交换,这些数据通过RAMDAC转换为模拟信号输出到显示端,最终就是我们看见的图像。显示芯片性能的日益提高,其数据处理能力越来越强,使得显存数据传输量和传输率也要求越来越高,显卡对显存的要求也更高。载体,这时显存的交换量的大小,速度的快慢对于显卡核心的效能发挥都是至关重要的,而如何有效地提高显存的效能也就成了提高整个显示卡效能的关键。

  关于显存的字符编码规则是符合ASCII的,这点略过。

  显存地址分配是很主要的一点,它规定了哪些位置是彩色显示,哪些位置是黑白显示,哪些位置是文本模式显示。

起始 结束 大小 用途
C0000 C7FFF 32KB 显示适配器BIOS
B8000 BFFFF 32KB 用于文本模式显示适配器
B0000 B7FFF 32KB 用于黑白显示适配器
A0000 AFFFF 64KB 用于彩色显示适配器

1.  如何在文本模式下写入字符

  需要注意的就是B8000到BFFFF这段文本模式显示适配器的地址了,因为Linux终端模式就是类似的。

  而且要明白这段地址不是主板上内存条上的内存地址,内存条只是地址总线可以达到的范围中的一小部分,指令需要什么数据,地址总线会帮我们去找。地址只是数字,地址总线把地址拿到后,用此数字指向哪个存储介质,此地址就指向了那个介质上的存储单元中,所以一个地址的数字到底是指向哪里,是由地址总线说了算的。

  从B8000到BFFFF这32KB大小的内存中输出的字符会直接落到显存中,显存有了数据,显卡自然就会把它搬到显示器上。

  显卡的文本模式也分很多种模式的,用行列来表示,也就是80*25,40*25,80*43这些,他们的乘积表示屏幕上可以容纳的字符数,在显卡开始工作时,默认就是80*25,也就是一个屏幕可以打印2000个字符。虽说是文本模式,但不代表不可以打印彩色字符,当然,如果要打印彩色字符,一个字符一个字节就没办法了,ASCII码都是一个字节大小,即使标准的ASCII也是用7位编码,剩下的一位只能表示黑白了,所以我们需要两个字节来表示一个字符。一个屏幕2000个字符,一个字符2个字节,也就是一个屏幕需要4000字节,文本模式拥有32KB显存,所以32KB/4000B大约是八个屏幕大小(你应该想到Linux的tty切换了吧)。

  既然确定了每个字符所用的字节大小,那么这两个字节如何分配呢?

  屏幕上每个字符的低字节是字符的ASCII码,高字节是字符的属性信息。高字节中低四位是字符的前景色,高四位是背景色,都是RGB三色调和,对于每四位来说,RGB占据了三位,那么还有一位呢? 每四位的最高一位是用来表示亮色或者暗色。具体分配如下:

         bit

  K(控制是否闪烁) 15

  R      14

  G      13

  B       12

  I(亮度位)      11

  R         10

  G       9

  B       8

  字符ASCII码   0 ~ 7

2.  直接操作显存

  新的代码只要把之前的BIOS中断部分换掉就可以了,在0xB800H处写入数据即可

 SECTION MBR vstart=0x7c00
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00
mov ax,0xb800
mov gs,ax mov ax,0x600
mov bx,0x700
mov cx,
mov dx,0x1010
int 0x10 mov byte [gs:0x00],'A'
mov byte [gs:0x01],0xA4 mov byte [gs:0x02],'n'
mov byte [gs:0x03],0x13 mov byte [gs:0x04],'t'
mov byte [gs:0x05],0x52 mov byte [gs:0x06],'z'
mov byte [gs:0x07],0xB1 mov byte [gs:0x08],' '
mov byte [gs:0x09],0xCC mov byte [gs:0x0A],'U'
mov byte [gs:0x0B],0x2B mov byte [gs:0x0C],'h'
mov byte [gs:0x0D],0x6D mov byte [gs:0x0E],'l'
mov byte [gs:0x0F],0x7E mov byte [gs:0x10],' '
mov byte [gs:0x11],0x49 mov byte [gs:0x12],'K'
mov byte [gs:0x13],0xE5 mov byte [gs:0x14],'o'
mov byte [gs:0x15],0x8A mov byte [gs:0x16],'n'
mov byte [gs:0x17],0x96 mov byte [gs:0x18],'e'
mov byte [gs:0x19],0x68
jmp $ times -($-$$) db
db 0x55,0xaa

保存为antz.asm , 然后使用NASM生成为IMG文件,使用虚拟机打开镜像效果如下。

自制操作系统Antz(3)——进入保护模式 (中) 直接操作显存

  

  好了,现在我们可以在保护模式没有中断向量表的情况下,直接操作显存来显示字符了。

    

上一篇:js对重复数组去重


下一篇:Unity3D热更新全书-脚本(五) NGUI