[MIT6.828] LAB1中VBE图形界面测试总结

2024-03-12 00:38

本文主要是介绍[MIT6.828] LAB1中VBE图形界面测试总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

看到红色的Challenge就想挑战一把,于是搞了下VESA图形模式的编程。

科普知识:

什么是VBE?
VBE的全称是VESA BIOS Extension。

什么是VESA?
VESA的全称是Video Electronics Standards Association即视频电子标准协会,是由代表来自世界各地的、享有投票权利的超过165家成员公司的董事会领导的非盈利国际组织。
VESA致力于开发、制订和促进个人计算机(PC)、工作站以及消费类电子产品的视频接口标准,为显示及显示接口业界提供及时、开放的标准,保证其通用性并鼓励创新和市场发展。
其余更多信息,也有设计到本文内容理解方面的,详见文末参考资料。

既然是BIOS的扩展,那么最方便的还是在实模式下操作,但是我们实模式的代码只有很小一部分,写多了会超过引导区512字节限制,而且实模式下操作范围实现有限,所以要想办法处理。
解决方法有两种:
1、参考VESA开发手册提供的操作步骤,可以指导我们在保护模式下进行对其进行BIOS调用,但是步骤比较繁琐。
2、在实模式下开启图形功能后,把显存地址保存下来,然后在保护模式下操作这个地址从而达到对图形界面进行控制的目的,缺点是不能使用VBE内置的功能调用。

为了方便试验我选择了第二种方法,步骤如下:
1、开启A20地址线(LAB1已有代码)
2、加载GDT(已有代码)
3、获取VBE模式(新增代码)
4、设置VBE模式(新增代码)
5、开启保护模式(已有代码)
6、保护模式下的图形处理(新增代码)
注意,由于qemu的默认显卡bois不支持vesa模式,所以要在GNUmakefile中给QEMUOPTS变量添加额外参数 -vga std 即可。
涉及到代码文件boot/boot.S
在步骤2和步骤5所涉及到的代码中间加入如下代码
sti #enable interrupt call getvideomode call setvideomode cli #disable int
在16位代码区域末端加入如下代码,这里使用了0x4144模式代表了1024*768*32bpp,每32位一个像素点,一个1024*768个像素,三个数乘起来就是可视显存大小。其中videop videox videoy 分别代表显存起始地址,x分辨率,y分辨率,是在代码文件末尾定义的三个变量,在从boot到kernel跳转的过程中可以把这几个变量值押送过去,或者把这几个变量放到指定位置供保护模式下使用,不过我比较懒没有传递这个值,而是直接写到kernel代码中了:
getvideomode: mov $0x4144, %cx #mode 0x4144 1024*768*32bpp mov $0x4f01, %ax #get mode mov $0x8000, %di #mode info block address int $0x10 #VBE int ret setvideomode: movw $0x4144, %bx movw $0x4f02, %ax #set mode movw $0x8000, %di int $0x10 #VBE int movl 40(%di), %eax #get memory address movl %eax, videop movw 18(%di), %ax #get x resolution movw %ax, videox movw 20(%di), %ax #get y resolution movw %ax, videoy ret
在kern\目录下新增video.h文件,内容如下
#ifndef VIDEO_H #define VIDEO_H extern const short vx; //x resolution extern const short vy; //y resolution extern long* const vp; //display memory point int setpixel(short x, short y, int c); //draw a pixel void clear(int c);//clear screen int fillrect(short x, short y, short l, short w, int c);//fill a rectangle int drawbeeline(short x, short y, short l, int c);//draw a beeline int drawline(short fx, short fy, short dx, short dy ,int c); //draw line #endif
在kern\目录下新增video.c文件,内容如下
#include "video.h" #include <inc/math.h> const short vx=1024; const short vy=768; long * const vp=(long *)0xD0000000; const long vl=1024*768; int setpixel(short x, short y, int c) { /*if((x>=vx)||(y>=vy)) return -1; */ *(vp+x+(y*vx)) = c; return 0; } void clear(int c) { int i; for(i=0; i<vl; i++) *(vp+i) = c; } int drawrect(short x, short y, short l, short w, int c) { /*if((x>=vx)||(y>=vy)) return -1; */ for(w=y+w; y<w; ++y) { drawbeeline(x, y, l, c); } return 0; } int drawbeeline(short x, short y, short l, int c) { for(--l; l>=0; --l) *(vp+l+x+y*vx) = c; return 0; } int drawline(short fx, short fy, short dx, short dy ,int c) { float len = sqrtf((dx-fx)*(dx-fx)+(dy-fy)*(dy-fy)); float sin = (dx-fx)/len; float cos = (dy-fy)/len; float i; for(i=0.0; i<len; i+=1) { setpixel(fx+i*sin, fy+i*cos, c); } return 0; }
由于要写花斜线的函数用到了开方,但是目前的内核没有提供数学库,所以就自己从glibc移植了一个sqrtf()函数,故在inc目录下新增math.h文件,内容如下

#ifndef MATH_H #define MATH_H 1 typedef union { float value; unsigned int word; } ieee_float_shape_type; /* Get a 32 bit int from a float. */ #define GET_FLOAT_WORD(i,d) \ do { \ ieee_float_shape_type gf_u; \ gf_u.value = (d); \ (i) = gf_u.word; \ } while (0) /* Set a float from a 32 bit int. */ #define SET_FLOAT_WORD(d,i) \ do { \ ieee_float_shape_type sf_u; \ sf_u.word = (i); \ (d) = sf_u.value; \ } while (0) float sqrtf(float x); #endif

在lib目录下新增math.c文件,内容如下:
#include <inc/math.h> float sqrtf(float x) { static const float one= 1.0, tiny=1.0e-30; float z; int sign = (int)0x80000000; int ix,s,q,m,t,i; unsigned int r; GET_FLOAT_WORD(ix,x); /* take care of Inf and NaN */ if((ix&0x7f800000)==0x7f800000) { return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf sqrt(-inf)=sNaN */ } /* take care of zero */ if(ix<=0) { if((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */ else if(ix<0) return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ } /* normalize x */ m = (ix>>23); if(m==0) { /* subnormal x */ for(i=0;(ix&0x00800000)==0;i++) ix<<=1; m -= i-1; } m -= 127; /* unbias exponent */ ix = (ix&0x007fffff)|0x00800000; if(m&1) /* odd m, double x to make it even */ ix += ix; m >>= 1; /* m = [m/2] */ /* generate sqrt(x) bit by bit */ ix += ix; q = s = 0; /* q = sqrt(x) */ r = 0x01000000; /* r = moving bit from right to left */ while(r!=0) { t = s+r; if(t<=ix) { s = t+r; ix -= t; q += r; } ix += ix; r>>=1; } /* use floating add to find out rounding direction */ if(ix!=0) { z = one-tiny; /* trigger inexact flag */ if (z>=one) { z = one+tiny; if (z>one) q += 2; else q += (q&1); } } ix = (q>>1)+0x3f000000; ix += (m <<23); SET_FLOAT_WORD(z,ix); return z; }

做了以上操作之后,只需要在写个测试用的方法加入到现有的代码文件中就可以了,在kern\monitor.c文件中加入test()函数和一些头文件在如下:
#include "video.h" #include <inc/stdio.h> #include <inc/math.h> struct VbeInfoBlocks vbe_buf; #define INT_MAX 0x7fffffff void test(void) { short x,y,flag,flag1; unsigned char i,j; int z; for(z=0; z<INT_MAX;) { for(y=0,j=0,flag1=1; y<vy; z++,y++,j+=flag1, flag1=((j!=0xff)&&(j!=0)?flag1:-flag1)) { for(x=0,i=0,flag=1; x<vx;x++,i+=flag,flag=((i!=0xff)&&(i!=0)?flag:-flag)) { setpixel(x, y, (0xff0000&z)|(i)|(j<<8)); } } //clear(0xff); //drawline(0,0,100,767,0xff0000); //drawrect(0,0,1024,768,0); } return; }
然后在monitor()函数中加入一句:
test();
即可运行测试函数,运行效果如下,是一个R通道随着时间渐变的图像。

经过两天的鼓捣VESA图形界面,身心疲惫,数学不好连个三角形都填充不了,还有其他的例如圆弧,扇形等API感兴趣的可以自行发挥,欢迎debug和交流。

参考资料:
1、VESA编程——GUI离我们并不遥远 http://matrix7.me/2010/04/vesa%E7%BC%96%E7%A8%8B%E2%80%94%E2%80%94gui%E7%A6%BB%E6%88%91%E4%BB%AC%E5%B9%B6%E4%B8%8D%E9%81%A5%E8%BF%9C/
2、VESA BIOS Extension (VBE) 3.0 http://pdos.csail.mit.edu/6.828/2010/readings/hardware/vbe3.pdf

3、个人博客中的此文: http://blog.csdn.net/davelv/archive/2010/11/04/5988418.aspx

这篇关于[MIT6.828] LAB1中VBE图形界面测试总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/799608

相关文章

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

Nginx Location映射规则总结归纳与最佳实践

《NginxLocation映射规则总结归纳与最佳实践》Nginx的location指令是配置请求路由的核心机制,其匹配规则直接影响请求的处理流程,下面给大家介绍NginxLocation映射规则... 目录一、Location匹配规则与优先级1. 匹配模式2. 优先级顺序3. 匹配示例二、Proxy_pa

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

python多线程并发测试过程

《python多线程并发测试过程》:本文主要介绍python多线程并发测试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、并发与并行?二、同步与异步的概念?三、线程与进程的区别?需求1:多线程执行不同任务需求2:多线程执行相同任务总结一、并发与并行?1、

MySQL基本查询示例总结

《MySQL基本查询示例总结》:本文主要介绍MySQL基本查询示例总结,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Create插入替换Retrieve(读取)select(确定列)where条件(确定行)null查询order by语句li

Linux区分SSD和机械硬盘的方法总结

《Linux区分SSD和机械硬盘的方法总结》在Linux系统管理中,了解存储设备的类型和特性是至关重要的,不同的存储介质(如固态硬盘SSD和机械硬盘HDD)在性能、可靠性和适用场景上有着显著差异,本文... 目录一、lsblk 命令简介基本用法二、识别磁盘类型的关键参数:ROTA查询 ROTA 参数ROTA

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)

Windows Docker端口占用错误及解决方案总结

《WindowsDocker端口占用错误及解决方案总结》在Windows环境下使用Docker容器时,端口占用错误是开发和运维中常见且棘手的问题,本文将深入剖析该问题的成因,介绍如何通过查看端口分配... 目录引言Windows docker 端口占用错误及解决方案汇总端口冲突形成原因解析诊断当前端口情况解

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi