30天自制操作系统 第9天日志

一、实验主要内容

1、 内容1:整理源文件

程序太长了,将程序整理一下
在这里插入图片描述
在Makefile文件中的OBJS_BOOTPACK=里,要将keyboard.obj和mouse.obj也要补进去。

2、 内容2:内存容量检查(1)

内存容量检查:
我们在内存管理之前,第一步要做的就是检查内存的容量。我们可以调用BIOS的相关函数来查询,但是因为调用方法等原因过于麻烦。
所以我们采用的方法是:先令高速缓存无效(如果有的话),然后向一个地址写入数据,如果该数据能成功从该地址中读取出来,那么就证明我们的地址是可用的。
内存检查时关闭缓存的原因:
如果缓存可用,那么我们的写入和读取操作就可能是在缓存中进行的,也就是说我们根本没有对内存进行操作,所以要先关闭缓存。
EFLAGS寄存器
最初对EFLAGS进行的处理,是检查CPU是486以上还是386。如果是486以上,EFLAGS寄存器的第18位应该是所谓的AC标志位;如果CPU是386,那么就没有这个标志位,第18位一直是0。这里,我们有意识地把1写人到这一位,然后再读出EFLAGS的值,继而检查AC标志位是否仍为1。最后,将AC标志位重置为0。
memtest函数解析:
在这里插入图片描述
在禁用和恢复高速缓存的时候,我们用到了CR0控制寄存器:
在这里插入图片描述
通过代码可以看到,禁用高速缓存,将CR0寄存器的第29、30位都置为了1,对第30位很容易理解,它是标志着是否使用缓存。但是对于第29位,我没有查到相关信息,所以我也不知道设置它是不是必要的。
加载和设置cr0寄存器的函数只能通过汇编代码来写:

在这里插入图片描述
memtest_sub函数解析:
在这里插入图片描述
make run
在这里插入图片描述

3、 内容3:内存容量检查(2)

在之前的内存检查中检查到内存容量为3072MB,而不是32MB,这是因为C编译器的bug,它自动将我们的程序进行了修改以达到它所谓的最优程序。
首先用make –r bootpack.nas来运行,先确认bootpack.c被编译成了什么样的机器语言。
在这里插入图片描述
C编译器的过程:
首先将内存的内容保存到old里,然后写入part0的值,再反转,最后跟pat1进行比较。在编译器的思路中,这是一定相等的,因而就将其删掉,接下来是比较*p和pat0是否相等,在它觉得,这也是一定相等的,因而为了提升速度,将这一部分也删去,因此,之前的c程序就变为了:
在这里插入图片描述
再接着,反转再反转,最终还是回到初始的状态,因而这些处理也可以删去,因此程序就变成了下述情况
在这里插入图片描述
再接着,p=pat0,本来就没有意义,要将old的值赋给p,因此程序变为了:
在这里插入图片描述
在这里,*p并没有写入什么内容,并且,地址变量p虽然计算了地址,但其实一次也没有用掉,编译器便将这些全部舍弃。
最终编译器优化后的代码如下:
在这里插入图片描述
并不是一开始所设计的程序的意思了,因此需要进行修改。如果更改编译选项,是可以停止最优化处理的,但是之后还有其他的部分需要用到编译器的最优化处理,因此,决定将memtest_sub也用汇编来描写。
在这里插入图片描述
编写完后,将bootpack.c中的memtest_sub函数删去,再运行。
运行结果:
在这里插入图片描述

4、内容4:挑战内存管理

内存的分配:假设有128MB内存,即0x8000000个字节
方法1:以4KB为单位进行管理,维持一个数组,数组的值标记对应的4kb是否为空。
举例:以4kb为单位,即分为0x800000/0x1000=32768个区域

在这里插入图片描述
需要多少空间,就算出来需要连续的区域的个数,即连续的标记为0的个数的区域。
在这里插入图片描述
然后再将这些区域标记为1,表示已经被使用:
在这里插入图片描述
(可以看出来,这种方法都是将我们想要存储的东西连续储存,也就是需要连续的地址)
额外空间开销:地址被分为几个区域就需要几个字节来储存,额外的空间占容量的0.02%。
方法2:用一个bit来存储区域是否被使用,这样空间开销是容量的0.003%。
方法3:列表管理,用一个结构体来表示一个连续区域的可用状况,有开始地址以及大小,用一个结构体进行内存管理,描述可用的连续区域的个数以及每个连续区域的可用状况。
在这里插入图片描述
需要一个空间,就扫描这些可用区域的size大小,直到找到一个大小满足要求的区域,然后将size减去即将被使用的部分,开始地址变为新区域的首地址。如果size减为0,那么就将这条信息从结构体中删除。释放内存时,则增加一条可用信息,还要看他们可不可以和前后的空间连在一起。
优点: 1、占用内存小,假如分1000个条目,那么内存管理仅需要1000*8+4=8004个字节。2、处理更快,占用内存时,只需要加法(原地址加上使用的空间)和减法运算(size减去使用的空间)各执行一次,释放空间也比逐一将0写入内存快得多。
缺点: 会造成外部碎片,也就是使用这种方法时间变长,内存就会被分的零零散散。
代码分析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、遇到的问题及解决方法

1、 描述问题1

在memtest_sub函数中,检查是否写入到内存时,为什么要先将写入的数据反转在检查比较?
解决方法:需要写入数据再反转是因为有些机型由于芯片组和主板电路等原因,如果不做这种检查就会直接读出写入的数据,所以要反转一下。

2、 描述问题2

一次只检查4kb内存的最后4个地址,如果不可使用的内存正好处于这4kb之间怎么办?
解决方法:不用担心这个问题,因为在系统启动的时候内存已经被检查过了,像存储了bios这样的我们不能使用的内存都是连续的而且占用比较大,所以我们能使用的部分也是一整块,我们检测的其实就是它的上界和下界。

3、 描述问题3

AC标志位是什么?
AC (Alignment check)——位18,对齐检查。置位该标志和控制寄存器CR0 的AM 标志则启用对内存引用的对齐检查,清除这两个标志则禁用对齐检查。当引用一个没有对齐的操作数时,将会产生一个对齐检查异常,比如在奇地址引用一个字地址或在不是4 的倍数的地址引用一个双字地址。对齐检查异常只在用户态(3 级特权)下产生。默认特权为0 的内存引用,比如段描述符表的装载,并不产生这个异常,尽管同样的操作在用户态会产生异常。对齐检查异常用于检查数据的对齐,当处理器之间交换数据时这很有用,交换数据需要所有的数据对齐。对齐检查异常也可供解释程序使用。让某些指针不对齐就好比做上特殊标记,这样就无需对每个指针都进行检查,只在用到的时候,对这些特殊指针进行处理就可以了。

三、程序设计创新点

1、描述创新点1

在内存的释放函数中,如果不可与前后合并而文件管理列表又满了,作者的做法是暂时不注册要释放的部分,我的将表示最小的的那部分管理列表空出来来保存我们释放的这部分。
在这里插入图片描述

https://download.csdn.net/download/weixin_43979304/15320819?spm=1001.2014.3001.5503

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SIR怀特

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

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

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

打赏作者

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

抵扣说明:

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

余额充值