让我们先来了解一下历史:

VGA起源:

VGA 由IBM在1987年提出。 它有一些列的新功能,同时也兼容它的那些前辈如CGA跟EGA的所有功能:

1. 文本模式(80x25,字体小一下的话也可以支持80x50)

2. 16色模式(640x480,四位色)

3. 256色模式(320x240, 8位色)

4. 也支持用户自定义一些操作,例如双重扫描或者分屏操作

 

VGA 具有了256K的内存,这个内存可通过位于0xa0000的内存地址访问。不支持同时访问所有内存,你需要利用bank寄存器来映射你想访问的内存块,然后访问这片内存。

所有由QEMU仿真的VGA 都支持以上功能

超级VGA, SVGA

在90年代初期,生产厂商开始推出不同种类的加强版VGA卡,它们一般叫做超级VGA, 也简称SVGA。 由qemu仿真的cirrus VGA就是一种典型的SVGA. 这种卡增加了如下新功能:

1. 更多的视频内存

2. 更好的分辨率,如256色

3. 更多的色彩度(64K,16位像素)

4. 甚至更多的像素(16M,每像素24 或32 位)

5. 线性framebuffer,这样就可以同时访问所有内存而不需要如上的寄存器转换

6 2D加速(cirrus blitter)

 

qemu中的SVGA

qemu中除了cirrus以外的所有SVGA都支持boche的显示接口。这个接口一开始由boche开发实现,这也是它为什么叫boche显示接口。我们在QEMU 中也实现了它。它也是QEMU中标准ga的第一接口。virtio-vga,qxl-vga 以及vmvga只有在vga兼容模式下才支持boche显示接口。vga兼容模式一般是显卡在刚开始启动系统还没有加载显示驱动的时候

boche显示接口是一种半虚拟化接口,在虚拟显示设备里只仿真了一些必须的物理资源,例如并没有仿真像时钟速率或者其他时间相关的寄存器。

一般来说,boche显示接口使用0x1ce(寄存器索引)以及0x1cf(寄存器数据)两个IO接口, 因为这两个寄存器都是16位的并且数据寄存器也没有排列,所有它们不能应用在非x86的系统,所以0x1d0也可以用作数据接口

 

现代虚拟机所使用的图形

让我们先来看一下现代虚拟机在图形领域的使用:

1. 基本上只使用32位的色彩模式, 只有一个例外就是真16位色,偶尔还会在一些资源有限的地方使用,例如树莓派

2. 2D加速已死, 现在或者使用软件渲染或直接使用3D引擎来2D渲染

3. 文本模式除了BIOS外也很少被使用了,即便是这样也只有在boot中加载KMS驱动以前使用,而UEFI则直接进入了图形模式

4. 显存转映射模式也不存在了,文本模式仍然使用0x0000窗口,不是文本模式的缓存太小了也用不上bank切换

 

所以我们其实有很多其实由复杂代码实现的仿真功能并没有真正派上用场,而且这些代码也有很多的安全隐患

 

所以,我们能简化一下事情么?

答案是肯定的。 QEMU1.3已经开始这样的工作了。 我们给stdvga设置了一个MMIO bar, 然后通过这个bar 来访问vga寄存器一个bochs显示接口寄存器

OVMF(UEFI对qemu的实现) 也在使用MMIO bar模式。 bochs-drm.ko 驱动也是使用了MMIO的方式。 

所以,虚拟端其实已经忽略了vga方针。

 

引入 -device bochs-display

一种在QEMU3.0中引入的新的显示设备:

1. 不再兼容VGA。 我们使用 display/other 替代 display/vga来表示 PCI class

2. 它有一个 stdvga样式的MMIO bar, 当然vga寄存器已经不存在了

3.  下一步将不在同VGA共享代码, 这样也大大的减少了代码的数量级

4. 不再需要IO接口, 可以直接在PCIe槽中插拔

5. OVMF已经支持这种设备

6. bochs-drm.ko 驱动也支持它

 

所以,对于UEFI的用户来说,你可以从stdvga中直接切换到bochs-display

 

但是,BIOS跟文本模式该怎么办呢?

 

直接访问VGA硬件进入文本模式在今天已经很少见了。 一般seabios跟linux的加载器会通过调用vgabios函数来实现文本渲染,所以我们可以劫持以下这些函数来支持文本模式,而不是真的使用硬件来支持。 sgabios使用了一种类似的方法,直接把vga文本输出到了串口

幸运的是我们不是第一个面对这些问题的人。 coreboot可以初始化图形硬件,设置一个具有原始显示像素的framebuffer。 如果适应seabios的话仍然需要文本模式,引文coreboot还是不太普遍,仍有很多问题。 所以coreboot是有一个vgabios的变量来渲染文本到framebuffer中

 

如果只是修改以下程序的初始化代码而不是像coreboot那样写framebuffer的话,我们其实已经准备好了。 seabios启动信息已经可以在bochs-display的famebuffer中显示了。

qemu 3.1 将完全支持这个功能。 vgabiso虽然已经在QEMu3.0中,但是因为一些bug问题,并没有被设置成默认选项,需要手动设置来使它工作。

 

当然它也存在以下缺点,当然因为是一些很少遇见的情况,可能不会对你造成困扰:

1 linux 的 vgacon 不能使用, 因为我们并不是真正的访问硬件。 所以你需要使用vesafb或者只是忽略这些早期启动信息。一旦bochs-drm驱动加载了 fbcon会恢复正常使用

2. vgabios使用了1024x768的固定分辨率,并且初始化后不支持模式切换,这是因为初始化代码是在实模式中运行的。当然你可以使用小一些的分辨率,画面会在左上角对齐。

 

以上就是全部了,希望你能喜欢这个新的vga设备

 

https://www.kraxel.org/blog/2018/10/qemu-vga-emulation-and-bochs-display/