30天自制操作系统day8
一、实验主要内容
1、 内容1:鼠标解读(1)
前一天已经实现了从鼠标中取得数据,因此这一天就是解读之前取得的数据,让鼠标能够动起来。
首先对HariMain函数进行修改,将读鼠标得到的最初的0xfa舍弃。将之后的鼠标传送的3个字节一组的数据,使其显示在屏幕上。
为什么要舍弃0xfa?
因为鼠标已经激活,不需要这个显示的数据了。
第一个字节和按键有关,第二个字节和左右移动有关,第三个字节和上下移动有关。
在bootpack.c文件的入口函数中,我们还是先检测键盘的缓冲区有没有数据,当键盘中断都处理完了再处理鼠标中断产生的数据
当一组数据的三个字节数据都存到了mouse_phase数组中,就向屏幕输出
运行结果:
运行结果分析: “08”部分的0只会在0-3范围内变化,之移动鼠标,08部分的“8”那一位不会发生任何变化,只有点击鼠标才会变化。上述第二组数据与鼠标的左右移动有关系,第三组数据与鼠标的上下移动有关系。
2、 内容2: 稍事整理
然后通过一个函数对鼠标数据的处理进行整合:
判断三个数据是否都准备好
3、内容3:鼠标解读(2)
①结构体增加变量描述鼠标的移动情况
②增加对第一字节的检查:判断前4位是否在0-3之内,后四位是否在8-F之内
如果这个字节的数据不在以上范围内,它就会被舍去。
0xc8=11001000,前四位可以检测是否0~3范围,如果大于3,则进行与运算后第一位不为0;
后四位可以检测时候8~F范围,如果是,则第一个1与运算后为1,即运算后为0x08
进行检测的原因:
鼠标连线偶尔也会有接触不良、即将断线的可能,这时就会产生不该有的数据丢失,这样一来数据会错开-一个字节。数据一旦错位,就不能顺利解读,后面的数据就都“错位”。而如果添加上对第-字节的检查,就算出了问题,鼠标也只是动作上略有失误,很快就能纠正过来,所以加上了这项检查。
③获取鼠标的按键信息
因为鼠标的按键信息保存在3-0位上,且值在8-F之间,他们的第3位都为1,所以只需要取后三位就可获得鼠标的按键信息。
④在第三阶段对数据进行处理:根据鼠标的移动情况获取鼠标的相对坐标
只是移动鼠标的情况下,后四位无关,所以与0;
0001,0011(1,3)和0x10与,鼠标左移;
0011,0010(2,3)和0x20与,鼠标下移;(本来上移,因后面对y进行取反操作)
结果显示如下:
⑤显示部分:用字母位置把初始的小写l\r\c变成大写L\R\C表示按下鼠标的左\右\中
make run
移动鼠标
点击鼠标
4、内容4:移动鼠标指针
可以得到鼠标的坐标范围在[(0,0),(304,184)]之间,即320-16,200-16。
从代码中可以看出,关于鼠标坐标的计算不是时刻连续的,而计算的是更新之后的坐标。
make run
晃一晃鼠标
鼠标接触到屏幕下方的任务栏,会变成这样
5、 内容5:通往32位模式之路
等同于下面的C程序
主PIC和从PIC的中断关闭了
新指令NOP,让CPU休息一个时钟长的时间。
因为CPU运行的速度远远高于IO设备的运行速度,所以先让CPU休息1个时钟的时间,等待IO操作的完成,不然CPU要一直轮询
如果当CPU进行模式转换时进来了中断信号,就会有麻烦。而且后来还要进行PIC的初始化,初始化时不允许中断。所以最后要把中断全都屏蔽掉。
②
这次输出0xdf要完成的功能是让A20GATE信号线变成ON的状态。这条信号线能使内存的1MB以上的部分变成可使用状态。
③
CR0寄存器:即control register 0,只有操作系统可以使用。
保护模式的段寄存器解释不是16倍而是能够使用GDT。这种模式下应用程序既不能随便更改段的设定,又不能使用操作系统的专用段,操作系统受到CPU的保护。保护模式分带保护的16位模式和带保护的32位模式两种,我们使用带保护的32位模式。
进入保护模式以后,段寄存器的意思也变了(不是×16再加了)除了CS(CS变了会造成混乱)以外所有段寄存器的值都从0x0000变成了0x0008(相当于gdt+1的段)。
④
memcpy函数:将一块内存的数据复制到另一块内存中
memcpy(转送源地址,转送目的地址,转送数据大小(以双字为单位所以数据大小用字节数/4来指定))
意思是从bootpack的地址开始的512kb内容复制到0x00280000号地址,就是将bootpack.hrb复制到0x00280000号地址。
从0x7c00复制512个字节到0x00100000(DSKCAC),就是将启动扇区复制到1MB以后的内存。
将始于0x00008200的磁盘内容,复制到0x00100200。转送数据大小计算:cyls值为10,表示10个柱面;512表示一个扇区容纳的字节数;18表示一个盘面共18个扇区;2表示一个柱面有两个磁头。它需要减去启动扇区的那一部分长度。(为什么是0x8200开始,请看最后我的内存使用整理)
⑤
代码解析:这段代码将执行所必需的数据传送过去。EBX代入的是BOTPAK。JZ是条件跳转指令,根据前-个计算结果是否为0来决定是否跳转。在这里,根据SHR的结果,如果ECX变成了0,就跳转到skjp那里去。在harib05d里, ECX没有变成0,所以不跳转。 最终,memcpy将bootpack.hrb第0x10c8字节开始的0x11a8字节复制到0x00310000号地址去。最后将0x310000代人到ESP里,然后用一个特别的JMP指令,将2*8代人到CS里,同时移动到0x1b号地址。这里的0x1b号地址是指第2个段的0x1b号地址。第2个段的基地址是0x280000,所以实际上是从0x28001b开始执行的。这也就是bootpack.hrb的0x1b号地址。这样就开始执行bootpack.hrb了。
⑥
IN AL,0x64:读端口 0x64 到 AL.
读端口0x64就是读8042的状态寄存器(一个8bit的只读寄存器),bit_1为1时表示输入缓冲器满,为0时表示输入缓冲器空。要向8042写命令(通过0x64端口写入),必须当输入缓冲器为空时才可以。所以当CPU从设备号码读取的倒数第二位是0,键盘控制电路才准备好,如果不为0,就跳到waitbdout不断循坏。
ALIGNB指令:于对指令或者数据的存放地址进行对齐
ALIGNB 16:要求下面的起始地址是16的倍数
“纸娃娃系统”的内存分布图
二、遇到的问题及解决方法
1、 描述问题1
为什么会出现鼠标指针“吃掉”任务栏的现象
因为每次鼠标移动前都要清除掉目前的鼠标,而作者的做法是让背景色即暗浅蓝覆盖指针,所以在上面背景色为暗浅蓝的时候看起来是移动正常的,但是移动到了下面之后,再加上鼠标本身背景色就会让下面鼠标所在的地方变成暗浅蓝。
2、 描述问题2
为什么bootpack的地址就是bootpack.hrb?
可以看到bootpack标签在asmhead.nas的最后面
而bootback.hrb是拼接在asmhead.bin后面的,所以指的就是bootback.hrb的首地址。
三、程序设计创新点
1、描述创新点1
改善鼠标指针“吃掉”任务栏的现象
因为主函数中的for循环每循环一次,就会用一个绿色的方块对上一次鼠标所在的位置进行颜色的恢复,所以我们可以用一个256大小的数组保存上一次鼠标所在的位置的颜色,然后用这个数组去恢复它的值。
在计算完鼠标的左上角的坐标后,在显示鼠标之前,保存下来鼠标将要覆盖的位置的值:
最后需要看我们用来显示鼠标的函数putblock8_8,鼠标的颜色是存到了mcursor数组中,而鼠标的初始化函数将鼠标的背景设置成了绿色,所以应该在鼠标初始化的时候不设置背景颜色。
最后的结果:
2、描述创新点2
改善鼠标指针“吃掉”任务栏的现象
上图会出现黑色方块的原因是没有对我们开辟的数组的256个像素初始化,因该给该数组初始化为当前鼠标该有的背景色,为0x008484.
结果如下所示:
总结一下步骤:
- 开辟一个大小为256的数组,用于保存鼠标下一次显示位置的显存信息;
- 给数组初始化为当前鼠标该有背景色,为0x008484, 256个像素全部初始化
- 恢复当前鼠标位置信息,即将数组数据赋给当前鼠标像素
- 将下一次鼠标显示位置的显存信息保存在数组里,覆盖原来的值
- 显示鼠标下一步的位置
- 重复3,4,5步骤
完善任务栏被吃掉代码:https://download.csdn.net/download/weixin_43979304/15320821?spm=1001.2014.3001.5503