30天自制操作系统:第五天 结构体、文字显示与 GDT/IDT初始化

今天的内容相比前几天多了很多,主要是一些东西用代码写出来更难理解,需要更多的时间去琢磨,因此对于一些较为基础的内容不会进行详细的描述。

1.接收启动信息(harib02a)

之前的程序大都是直接使用0xa0000、320、200等数值,而这些值应该从asmhead.nas程序先前保存下来的值中取,如果不这样做,当画面模式改变时,系统就不能正确运行。

这里使用指针来取得这些值。
在这里插入图片描述
binfo是bootinfo的缩写,scrn是screen(画面)的缩写。

这里的0x0ff4之类的数据是从哪里来的呢,其实这些地址仅仅是为了与asmhead.nas保持一致才出现的。

另外这里把显示画面背景的部分独立出来,单独做成了一个函数 init_screen。增强了程序的可读性。
在这里插入图片描述
执行效果:
在这里插入图片描述

2.使用结构体(harib02b)

将一些常用在一块的数据定义成结构体,方便程序的书写,在后续的函数传参中也会释放出应有的威力。
在这里插入图片描述
与之前不同的就是将 cyls、leds、vmode 变量做成了一个结构体。

这里结构体中有一个变量reserve引起了笔者的注意。单词译为:保留,储备。比较这两个程序(上一节与本节),不难发现,reserve这个属性是多余的,应该是为了显现出字节对齐的存在。
在这里插入图片描述
↑结构体内存分布(字节对其)

3.试用箭头记号(harib02c)

本章节内容较为基础,介绍了指针的一种取值方式。
(*p).value = p - > value;
在这里插入图片描述

4.显示字符(harib02d)

这里为了显示一个字符,因为已经进入到32位模式,不能再调用BIOS函数往显卡中写入数据,但是换一种方式,使用8x16的长方形像素点阵来表示一个字符,例如:
在这里插入图片描述
一共占用16个字节(8x16)。写成16进制形式:
在这里插入图片描述

用for循环将画8个像素的程序循环16遍:
在这里插入图片描述
其中参数解释:

  • char* vram,指针变量,保存着Video RAM的地址
  • xize,VRAM每一行的像素点总数,这里是320
  • x,y:写入像素点的起始位置(程序中完成了后面7个位置的填写)
  • c:写入的颜色(这里传入了 COL8_FFFFFF 即 7,将这个像素点设置为白色)
  • font数组,即前面用于描述A字符像素点的数字矩阵,用于判断像素点是否需要设置成c颜色(c:我们设置的颜色)

不难发现上述的程序中含有大量冗余的乘法运算,我们可以优化来减少这些无用功,进而提升程序的运行速度。
在这里插入图片描述
运行效果:
在这里插入图片描述

5.增加字体(harib02e)

在第4节中使用了数字矩阵表示出来字母A,这很麻烦,因此第五节中作者引入了一种字体文档:
在这里插入图片描述
文档是这么安排内容的:含有256个字符,A的字符编码是0x41,所以A的字体数据,放在"hankaku + 0x41 * 16"开始的16字节中。

将程序改造成一下就可以输出不一样的内容了:
在这里插入图片描述
运行效果:
在这里插入图片描述

6.显示字符串(harib02f)

第五节中,光显示几个字符就用了这么多行代码,看起来不是个滋味:
在这里插入图片描述
因为是一样的内容,所以可以封装成函数:
在这里插入图片描述
参数与之前的类似,函数中的s表示一个我们传入其中的字符串,C语言中,字符串都是以0x00结尾的,所以函数的结束就是以读取到的内容为0时。

函数调用:
在这里插入图片描述
整理后的HariMain函数
在这里插入图片描述
这里为什么对同意字符串调用了两次 putfonts8_asc函数?
不着急解释,我们将其中的一个调用去掉后
在这里插入图片描述
观察运行效果:
在这里插入图片描述
是这样的,再把注释掉的代码还原,运行:
在这里插入图片描述
这下子应该就清楚很多了,原来这个是为了调出黑色阴影而特意调用两次的呀。(注意调用的传入参数有所不同,是为了构造出黑色像素点“多写一个像素点”的效果)

7.显示变量值(harib02g)

这里是为了完成类似debugger显示出一些变量的值,
在这里插入图片描述
↑有关sprintf函数

sprintf函数的使用跟C语言中的printf函数非常相似,如:
在这里插入图片描述
内容较为基础,这里截自原书的解释:
在这里插入图片描述
在这里插入图片描述

运行效果:(变量成功显示在了界面上)
在这里插入图片描述

8.显示鼠标指针(harib02h)

在这里插入图片描述
对于程序中的for循环做一点解释:
应为显卡中描述像素点的方式为:
在这里插入图片描述
如果将坐标系类比成一个二维矩阵,那么y轴对应的就是数组的行方向,x轴对应的就是数组的列方向。这里是逐行遍历。对了,bc指的是back-color,背景色。
在这里插入图片描述
函数参数解释:vram和vxsize是关于VRAM的信息,它们的值分别是0xa0000和320;
pxsize和pysize是想要显示的图形(picture)的大小,鼠标指针的大小为16x16,所以这两个值都是16.
px0和py0指定图形在画面上的显示位置。
最后的buf和bxsize分别指定图形的存放地址和每一行含有的像素数。
在这里插入图片描述
运行效果:
在这里插入图片描述

9.GDT与IDT的初始化(harib02i)

这里为了实现鼠标的可移动作者对GDT和IDT做了详细的介绍。

GDT也好,IDT也好,它们都是与CPU有关的设定。为了让操作系统能够使用32位模式,需要对CPU做各种设定。不过,asmhead.nas里写的程序有点偷工减料,只是随意进行了一些设定。如果这样原封不动的话,就无法做出使用鼠标指针所需要的设定,所以我们要好好重新设置一下。

这里的内容如果没有操作系统的基础会变得较为复杂,主要讲解了为什么成需要分段。

在这里插入图片描述
在这里插入图片描述

按照上述的分段方法,为了表示一个段,需要有以下信息:

  • 段的大小是多少
  • 段的起始地址在哪里
  • 段的管理属性(禁止写入,禁止执行,系统专用等)

后续的内容还是以作者的解释为主:


在这里插入图片描述
在这里插入图片描述

程序部分:
结构体定义

struct SEGMENT_DESCRIPTOR {
	short limit_low, base_low;
	char base_mid, access_right;
	char limit_high, base_high;
};

struct GATE_DESCRIPTOR {
	short offset_low, selector;
	char dw_count, access_right;
	short offset_high;
};

在这里插入图片描述
程序解释起来还是很麻烦的,这里牵涉到的移位与运算需要一定的C语言基础,段基址base被分为了三个部分:base_low、base_mid、base_high,其中base_low为字型数据,base_mid、base_high均为字节型数据,在set_segmdesc程序中:
在这里插入图片描述
获取base低位通过base & 0xffff 运算,取得低16位数据:sd->limit_low = limit & 0xffff;
获取base中位需要先对base进行右移运算:(base >> 16),右移去除掉低16位数据,然后再位与上 0xff ,就获得了中间8位数据,同理,base高8位通过右移24位,剩下的8位数据也是通过位与0xff获得。

注意程序中指针变量的+1是以指针数据类型大小作为步长的,举个例子:

char* p;
p ++; 相当于 p += sizeof(char);

double* p;
p++; 相当于 p += sizeof(double);

感受

今天由于课程的缘故,没有时间仔细完成博客, 因此需要抽出时间对本章内容再次深入阅读,本篇博客也需要补充一些笔者的理解。今天就先这样了,晚安

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nepu_bin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值