如何在x86汇编保护模式下在屏幕上绘制一个像素?

16

我正在创建一个小型的引导程序+内核,到目前为止,我已经成功读取了磁盘,加载了第二个扇区,加载了GDT,打开了A20并启用了保护模式。

我跳转至32位函数,在屏幕上显示字符,使用视频内存来呈现文本内容(0x000B0000 - 0x000B7777)。

pusha
mov edi, 0xB8000
mov bl, '.'
mov dl, bl
mov dh, 63
mov word [edi], dx
popa

现在,我想再进一步,在屏幕上绘制一个像素点。根据我在某个网站上读到的信息,如果要使用VGA的图形模式,则必须将像素写入位置0x000A0000。这是正确的吗?

那么,单个像素的格式是什么?对于单个字符,您需要ASCII代码和属性,但是如果它与文本模式的工作方式相同,那么您需要定义什么来定义像素?


相关链接:http://wiki.osdev.org/How_do_I_set_a_graphics_mode - Ciro Santilli OurBigBook.com
3个回答

22

不幸的是,它比稍微远一点更远了些。

写入视频内存的规则取决于图形模式。在传统视频模式中,VGA 320x200(8bpp)是唯一一个视频内存表现为普通内存类型的模式:你从0xA000:0000(或0xA0000线性)开始向视频缓冲区写入一个对应于所需像素的字节,这就完成了。

对于其他VGA(SVGA之前的)模式,规则更加复杂:当你向视频内存写入一个字节时,你要寻址一组像素,并且一些我早已忘记的VGA寄存器指定了更新哪个像素平面以及如何使用旧值。这不仅仅是内存了。

有SVGA模式(从800x600x8bpp开始);你可以使用VESA Video Bios Extensions以硬件无关的方式切换到它们。在这些模式下,视频内存再次表现为内存,每个像素有1、2、3或4个字节,并且没有VGA式的8像素组,你需要通过一个字节访问来操作。问题在于实模式视频缓冲区不再足以寻址整个屏幕。

VESA VBE 1.2通过提供修改内存窗口基址的函数解决了这个问题:在任何特定时刻,线性地址0xA0000的段正在寻址视频内存的64Kb区域,但你可以控制在此地址可用的整个帧缓冲区中的哪个64Kb(基址调整的最小单位,也称为窗口粒度,取决于硬件,但你可以依靠将N×64Kb偏移映射到0xA0000的能力)。缺点是每次开始使用不同的64Kb块时都需要调用VBE BIOS。

VESA VBE 2.0增加了平面帧缓冲区,在保护模式下(也在非真实模式中)的某些高地址上可用。因此,进入视频模式需要调用VBE BIOS,但绘制像素不需要。

VESA VBE 3.0可能还不够便携,但提供了在保护模式下调用VBE函数的方法。(我没有机会尝试过,因为它在我“汇编语言操作系统”的年代尚未出现)。

无论如何,您必须先切换到图形模式。有几种变体可以实现:

  • 最简单的方法是在进入保护模式之前使用BIOS调用。使用VBE 2.0,您将不需要进行视频存储器窗口调整调用。
  • 另一种方法是创建V8086模式环境,这对于BIOS来说已足够好。最难的部分是将中断转发到实模式中断处理程序。这不容易,但是当完成时,您将能够在PM中切换视频模式并使用其他一些BIOS功能(例如磁盘I / O)。
  • 另一种方式是使用VESA VBE 3.0保护模式接口。对于其易用性或复杂性没有想法。
  • 而一个真正的Jedi方式是挖掘您特定的视频卡信息,通过设置其寄存器来切换模式。曾经做过这样的事情,用于过去某些Cirrus卡片 - 在PM中获得大型平面帧缓冲区并不太复杂。它是不可移植的,但如果目标是了解机器内部工作原理,则可能正是您需要的。

2
有些VBE 2/3的BIOS不支持LFB。我在2001年使用了一款集成了内存控制器和视频设备的英特尔芯片,才发现这个问题。 - Alexey Frunze

6

这取决于使用的图形模式,而且有很多不同之处。BIOS VGA视频模式13h(每个像素8位,分辨率为320x200)可能是最容易入门的(它是唯一具有256种颜色的BIOS VGA视频模式,但您可以通过直接写入视频卡端口来创建自己的模式):在BIOS视频模式13h中,映射到屏幕的视频内存从0x0A0000开始,并连续运行1个字节用于每个像素,仅有1个位平面,因此每个坐标的内存地址为0x0A000 + 320*y + x

在实模式下切换到BIOS视频模式13h(每个像素8位,分辨率为320 x 200):

mov ax,0x13
int 0x10

在保护模式下,在视频模式13h中绘制左上角的像素:
mov edi,0x0A0000
mov al,0x0F      ; the color of the pixel
mov [edi],al

3
当然可以。mov ax,13hint 10h(在实模式下)可以实现这一点。 - nrz
1
不,保护模式下会更加复杂一些,我认为你需要定义一个调色板,当然,在保护模式下你不能使用中断。 - ali
我只是想知道像素的格式。所以,它只是它的颜色。谢谢。 - ali
1
如果使用 DOS 扩展程序,则通常会钩取常见中断(例如 10h),从而使您能够从保护模式下使用它们。 - Michael
1
对于具有8、15、16、24、32位颜色的视频模式,像素的格式取决于使用视频模式的每个像素的位数。但是水平扫描线可能比水平分辨率长,其中一部分在可见视图之外。例如,对于800x600x8,扫描线可能为1024字节,每个水平扫描线外面有224字节。使用VBE函数4F01h,我们可以获取这些模式信息。关于VBE-Bios的所有信息都可以在vesa.org的公共和免费文档“vbe3.pdf”中找到(需要注册/登录)。 - Dirk Wolfgang Glomp

1
org 100h
bits 16
cpu 386

section.text:
START:
mov ax,12h
int 10h
mov al,02h
mov ah,0ch 

pixel.asm
c:\>nasm pixel.asm -f bin -o pixel.com
int 10h

3
DOS的.com可执行文件不能在保护模式下运行,它们在vm86或真实实模式下运行。(虽然存在16位保护模式,但据我所知,您无法从中使用int 10h BIOS调用。)因此,我认为这根本没有回答问题。如果我错了,请添加文本进行说明。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接