【问题标题】:How to draw a pixel on the screen in protected mode in x86 assembly?如何在 x86 汇编中以保护模式在屏幕上绘制像素?
【发布时间】:2013-01-19 21:28:44
【问题描述】:

我正在创建一个小引导加载程序+内核,直到现在我设法读取磁盘、加载第二个扇区、加载 GDT、打开 A20 并启用 pmode。

我跳到了 32 位函数,它在屏幕上显示一个字符,将视频内存用于文本内容 (0x000B0000 - 0x000B7777)

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

现在,我想更进一步,在屏幕上绘制一个像素。正如我在某些网站上所读到的,如果我想使用 VGA 的图形模式,我必须在位置 0x000A0000 处写入我的像素。对吗?

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

【问题讨论】:

标签: memory video assembly x86 pixel


【解决方案1】:

不幸的是,它有点远。

写入显存的规则取决于图形模式。在传统的视频模式中,VGA 模式 320x200 (8bpp) 是唯一一种视频内存表现得像普通类型内存的模式:您将一个与您想要的像素相对应的字节写入视频缓冲区,从 0xA000:0000(或线性 0xA0000)开始,仅此而已。

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

有SVGA模式(800x600x8bpp开头);您可以使用VESA Video Bios Extensions 以独立于硬件的方式切换到它们。在这些模式下,视频内存的行为再次像内存一样,每个像素有 1、2、3 或 4 个字节,并且没有类似 VGA 的 8 像素组,您可以使用一个字节访问。问题是实模式视频缓冲区不够大,无法处理整个屏幕。

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

VESA VBE 2.0 添加了平面帧缓冲区,可在保护模式下的某个高地址处使用(也在unreal mode 中)。因此,进入视频模式需要调用 VBE BIOS,而不是绘制像素。

VESA VBE 3.0 可能还不够便携,它提供了一种在保护模式下调用 VBE 函数的方法。 (我没有机会尝试它,在我的“组装操作系统”时代还没有它)。

无论如何,你必须先切换到图形模式。这样做有几种变体:

  • 最简单的方法是在进入保护模式之前使用 BIOS 调用。使用 VBE 2.0,您将不需要视频内存窗口调整调用。
  • 另一种方法是创建一个对 BIOS 来说足够好的 V8086 模式环境。最困难的部分是将中断转发到实模式中断处理程序。这并不容易,但完成后,您将能够在 PM 中切换视频模式并使用其他一些 BIOS 功能(例如磁盘 I/O)。
  • 还有一种方法是使用 VESA VBE 3.0 保护模式接口。不知道它可能是多么容易或复杂。
  • 真正的绝地方法是挖掘特定视频卡上的信息,通过设置其寄存器来切换模式。去过那里,过去为一些 Cirrus 卡做过 - 在 PM 中获得大的普通帧缓冲区并不太复杂。它不可移植,但如果目标是了解机器的内部结构,它也许正是您所需要的。

【讨论】:

  • 一些 VBE 2/3 BIOS 不支持 LFB。早在 2001 年,我就在一些结合了内存控制器和视频设备的英特尔芯片上发现了这一点。
【解决方案2】:

这取决于使用的图形模式,并且有很多差异。 BIOS VGA 视频模式13h (320x200 at 8 bits/pixel) 可能是最容易上手的(它是唯一具有 256 色的 BIOS VGA 视频模式,但是您可以通过直接写入显卡):在 BIOS 视频模式 13h 中,映射到屏幕的显存从 0x0A0000 开始,每个像素连续运行 1 个字节,并且只有 1 个位平面,因此每个坐标的内存地址为 0x0A000 + 320*y + x

在实模式下更改为 BIOS 视频模式 13h(320 x 200,8 位/像素):

mov ax,0x13
int 0x10

在保护模式下在左上角(视频模式 13h)绘制一个像素:

mov edi,0x0A0000
mov al,0x0F      ; the color of the pixel
mov [edi],al

【讨论】:

  • 是的,当然。 mov ax,13h, int 10h 这样做(在实模式下)。
  • 不,在保护模式下稍微复杂一点,我觉得你必须定义一个调色板,当然,你不能在pmode中使用中断。
  • 我只是想知道像素的格式。所以,这只是它的颜色。谢谢
  • 如果使用 DOS 扩展程序,它通常会挂钩常见中断(例如 10h),这使您可以在保护模式下使用它们。
  • 对于具有 8、15、16、24、32 位颜色的视频模式,像素的格式取决于视频模式使用的每个像素的位数。但是水平扫描线可能更长,因为水平分辨率有一部分在可见视图之外。示例 für 800x600x8 扫描线可能是 1024 字节,每个水平扫描线的可见视图之外有 224 字节。通过 VBE 功能 4F01h 我们可以获得这些模式信息。我们可以在 vesa.org 的公共免费文档“vbe3.pdf”中找到有关 VBE-Bios 的所有信息(需要注册/登录)。
【解决方案3】:
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

【讨论】:

  • DOS .com 可执行文件不在保护模式下运行,它们在 vm86 或实际实模式下运行。 (有一个 16 位保护模式,但 AFAIK 你不能使用int 10h BIOS 调用它。)所以我认为这根本不能回答这个问题。如果我错了,请添加文字来解释。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-14
  • 1970-01-01
  • 1970-01-01
  • 2020-03-11
  • 2023-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多