遇到的一些问题

2019-07-19  本文已影响0人  今天不想掉头发

1.流水线刷新问题:CPU按照程序中指令顺序来填充流水线,也就是按照程序计数器PC中的值来装填流水线,在实模式下指令按照16位指令格式进行译码,而实模式进入保护模式的指令是按照16位指令格式进行译码的,而后面的是保护模式下的32位指令,由于流水线把32位指令按照16位译码,所以后面的指令会出错,因此解决的方法就是用无条件跳转指令进行流水线的清空。即使用jmp跳转难道后面的指令中。

流水线刷新问题,实模式打开A20,加载gdt,cro寄存器置位后的保护模式下的操作是32位的,而加载的过程是在实模式下进行的,而流水线技术的存在,使得实模式下会提前对保护模式下的32位指令代码以16位指令的形式进行译码,因此会报错。使用无条件跳转的jmp指令(因为流水线取的根据cs:ip来进行取值,译码,执行的,取的是当前这条指令的下一条指令,所以,如果当前这条指令jmp走了,那么后面的也就都没用了,因此可以清空流水线)来清空流水线。这里使用jmp远转移,因为还要同时更新段描述符缓冲寄存器(之前使用的是20位的,到了保护模式需要更新)

2.因为需要对内存进行申请和释放操作,因此需要操作页目录表和页表,所以需要通过虚拟地址得到页目录表和页表的方式,即解决分页时遇到的如何访问页目录表和页表的问题(第1023个页目录项和页表项存储页目录表和页表的物理地址)

总结:

1.获取页目录表的物理地址,0xfffff000

2.获取页目录项的物理地址,0xfffffxxx,其中xxx表示页目录项的索引*4

3.获取页表的物理地址,高10为0xffc用于获取到页目录表的物理地址,中间10位作为索引,不用乘以4。最后12位作为页表内的偏移地址,用来定位页表项,必须是已经乘以4后的值。

注意:页表是在内存中,CPU对页表的频繁转换是很消耗资源的。

3.打印字符串的时候的滚屏问题,如果打印的字符和光标超出当前屏幕范围,需要滚动屏幕。

因为一共是25*80的文本模式,所以将1-24行移动到0-23行,第24行用空格代替,光标显示在第24行行首,以此来模拟滚屏(缺点是无法缓存上一屏的数据,只能缓存当前屏幕的2000个字符)。但是还有其他的方法可以通过显存来缓存多余的数据。

具体方法是将当前光标值对80求模,确定当前光标在本行中的位置,然后再用当前光标值bx - dx(dx中存储的就是余数),来获得本行的首字符位置(注意不能直接自己减自己,因为bx中存储的是光标的坐标值,自己减去自己就是0了,就是左上角的那个位置了),再将当前光标值加上80,便完成了\r\n的操作。

然后通过movsd+cld+rep的形式将1-24行移动到0-23行

4.中断处理程序返回的时候需要手动跳过错误码


image.png

有些中断产生错误码,有些中断不产生错误码,为了通用,将哪些不产生错误码的中断在执行的时候压入0,进行一个错误码位置的占位,返回的时候都跳过这个错误码,保持通用性。

5.内存管理系统中,开启分页机制下,如何访问页表?(需要构造出能够访问页表的虚拟地址,根据该虚拟地址来访问页表的地址),即访问某个虚拟地址所在的pte,需要构造出这个虚拟地址所在pte的虚拟地址。回环访问页目录表的物理地址,通过偏移量构造虚拟地址。

6.初始化页表的使用需要将页表清零,否则可能会有杂乱的PTE生成(一般系统回收物理页的时候不会清零,因为太低效,而且可能不会被使用到,所以使用的时候要记得清零)

7.维护线程就绪队列时遇到的问题:通过general_tag来维护线程的PCB,通过宏指令将general_tag转换成相应的PCB。即将链表节点类型转换成task_struct类型(涉及地址和类型的转换),即先完成地址转换,再完成类型转换。

通过&(PCB.general_tag) - &PCB = n,让PCB = 0的形式,所以偏移量n = &(PCB.general_tag),即&(((struct_type*)0)->member),然后再用某个结构体成员的地址减去偏移量,就得到了结构体起始地址,再做强转获得结构体类型。

8.特权级通过ired实现,从0特权级的内核线程转到3特权级的用户进程

上一篇 下一篇

猜你喜欢

热点阅读