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

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

操作系统实验日志学号20160810520姓名甘昆禄专业年级班级智能1601实验日期2018.10.31实验项目第6天:分段编译与中断处理一、实验主要内容1、分割源文件分割文件的优劣:优劣(1)按照处理内容进行分类,如果分的好的话,将来进行修改时,容易找到地方。(5)源文件数量增加。(2)如果Makefile写的好,只需要编译修改过的文件,就可以提高make的速度。(就不用重新编译全部的源文件)(6)分类分得不好的话,修改时不容易找到地方。(3)单个源文件都不长,多个小文件比大文件好处理。(4)更简洁规范Bootpack.c的分割:Makefile根据bootpack.c的分割后应增加的功能:2、整理Makefile和头文件Makefile里有很多相似的普通规则,这时候为了更加简洁,我们可以引入一般规则,像下面这样:make.exe会首先寻找普通的生成规则如果没有找到,就尝试用一般规则。普通生成规则要优于一般规则。将c文件里重复的声明添加到.h头文件中,然后在其余.c文件中增加#include“bootpack.h”表示告诉编译器,这里要替换成指定的内容,然后进行编译。头文件名用(”“)表示该头文件与源文件位于同一个文件夹里,而尖括号()则表示该头文件位于编译器所提供的文件夹里。3、设定GDT这个函数用来将指定的段上限(limit)和地址赋值给名为GDTR的48位寄存器。给GDTR赋值唯一的办法是指定一个内存地址,从指定的地址读取6个字节(48位),然后赋值给GDTR寄存器,完成这一任务的就是LGDT。该寄存器的低16位(即内存的最初2个字节)是段上限,它等于“GDT的有效字节数-1”。今后我们还会偶尔用到上限这个词,意思都是表示量的大小,一般为“字节数-1”剩下的高32位(即剩余的4个字节),代表GDT的开始地址。DWORD[ESP+4]里存放段上限(0x0000ffff),DWORD[ESP+8]里存放地址(0x00270000)。若是按字节写出来就成了FFFF000000270000。用图来描述栈就美滋滋:为了执行LGDT,作者希望把它们排列成[FFFF00270000]的样子。所以就先”MOVAX,[ESP+4]”读取最初的0xffff,然后再写到[ESP+6]里。结果就成了[FFFFFFFF00270000],如果从[ESP+6]开启读6个字节的话正好是想要的结果,即如下图:然后讲set_segmdesc函数:这个函数是按照CPU的规格要求,将段的信息归结成8个字节写入内存。填入内容在前一章已经提到过。首先是段的地址。地址用32位表示,称为段的基址(base)。在这里分为low(2字节),mid(1字节)和high(1字节)3段,合起来32位。是为了与80286时代的程序兼容才分为三段。段上限最大4GB,但只能使用20位,指定到1MB为止。为了扩大指定段的大小,段属性里设置了一个标志位Gbit。当这个标志位位1时,limit的单位不解释成字节(BYTE),而解释成页(page,有4KB)。这样4KBx1M=4GB。20位的段上限分别写到limit_low和limit_high里。段属性,又称为“段的访问控制权属性”,在程序中用变量名access_right或ar来表示。因为12位段属性中的高4位放在limit_high的高4位里,所以程序里有意把ar当做如下的16位构成来处理:xxxx0000xxxxxxxx(其中x是1或1)ar的高四位被称为“扩展访问权”GD00Gbit指段模式1指32位模式0指16位模式除运行80286程序外,通常都使用D=1ar的低8位:00000000(0x00)未使用的记录表(descriptiontable)10010010(0x92)系统专用,可读写的段。不可执行。Ring0系统模式10011010(0x9a)系统专用,可执行的段。可读不可写。11110010(0xf2)应用程序专用,可读写的段。不可执行。Ring3应用模式11111010(0xfa)应用程序专用,可执行的段。可读不可写。CPU到底是处于系统模式还是应用模式取决于执行中的应用程序是位于访问权为0x9a的段,还是位于访问权为0xfa的段。前者为系统模式。4、初始化PIC要使用鼠标必须使用中断,将GDT和IDT正确无误地初始化。同时还要初始化PIC(programmableinterruptcontroller),“可编程中断控制器”。PIC是将8个中断信号集合成一个中断信号的装置。与CPU直接相连的PIC称为主PIC(masterPIC),与主PIC相连的PIC称为从PIC(slavePIC)。主PIC负责处理第0到第7号中断信号,从PIC负责8到15.PIC的初始化:int.c的主要内容:#includebootpack.hvoidinit_pic(void)/*PIC的初始化*/{io_out8(PIC0_IMR,0xff);/*禁止所有中断*/io_out8(PIC1_IMR,0xff);/*禁止所有中断*/io_out8(PIC0_ICW1,0x11);/*边沿触发模式(edgetriggermode)*/io_out8(PIC0_ICW2,0x20);/*IRQ0-7由INT20-27接收*/io_out8(PIC0_ICW3,12);/*PIC1由IRQ2连接*/io_out8(PIC0_ICW4,0x01);/*无缓冲区模式*/io_out8(PIC1_ICW1,0x11);/*边沿触发模式(edgetriggermode)*/io_out8(PIC1_ICW2,0x28);/*IRQ0-15由INT28-2f接收*/io_out8(PIC1_ICW3,2);/*PIC1由IRQ2连接*/io_out8(PIC1_ICW4,0x01);/*无缓冲区模式*/io_out8(PIC0_IMR,0xfb);/*11111011PIC1以外全部中断*/io_out8(PIC1_IMR,0xff);/*11111111禁止所有中断*/return;}从CPU角度来看,PIC是外部设备,CPU使用OUT指令进行操作。程序中的PIC0和PIC1,分别指主PIC和从PIC。PIC的寄存器都是8位寄存器,IMR是“interruptmaskregister”的缩写,意思是“中断屏蔽寄存器”。8位分别对应8路IRQ信号。ICW是“initialcontrolword”的缩写,意为“初始化控制数据”。只有在电脑CPU里,word这个词才是16位的意思,在别的设备上有时指8位有时也指32位。ICW有4个,分别编号为1~4,共有4个字节的数据。ICW1和ICW4与IPC主板配线方式、中断信号的电气特性有关。ICW3是有关主-从连接的设定,对主PIC而言,第几号IRQ与从PIC相连,使用8位来设定的。如果把这些位全部设为1,那么主PIC就能驱动8个从PIC。因此不同的操作系统可以进行独特设定的就只有ICW2了、这个ICW2,决定了IRQ以哪一号中断通知CPU。5、中断处理程序的制作鼠标是IRQ12,键盘是IRQ1,所以我们编写用了INT0x2c和INT0x21的中断处理程序,即中断发生时所要调用的程序。voidinthandler21(int*esp)/*来自PS/2键盘的中断*/{structBOOTINFO*binfo=(structBOOTINFO*)ADR_BOOTINFO;boxfill8(binfo-vram,binfo-scrnx,0,0,COL8_FFFFFF,*INT21(IRQ-1):PS/2kwyboard*);for(;;){io_hlt();}}这个函数就是产生21号中断(键盘中断)时程序跳往的地方,也就是在屏幕的开头输出*INT21(IRQ-1):PS/2kwyboard*这段文字。Inthandle21接收了esp指针的值,但函数中没有使用。中断处理完成后要返回原程序,不能执行“return”但必须执行IRSTD指令,这个指令还是得用nas写。EXTERN_inthandler21,_inthandler27,_inthandler2c_asm_inthandler21:PUSHESPUSHDSPUSHADMOVEAX,ESPPUSHEAXMOVAX,SSMOVDS,AXMOVES,AXCALL_inthandler21POPEAXPOPADPOPDSPOPESIRETD数据结构的时候我们详细的讲过栈这个数据类型,这里作者讲了缓冲区分类。栈属于缓冲区。缓冲区有两种:一种是将信息从上面逐渐加入进来,需要时再从下面一个个取出。最先加入的信息也最先取出,所以这种缓冲区是“先进先出”,简称FIFO。还有一种缓冲区是信息从上加入,也从最上面开始取。所以这种缓冲区是“先进后出”,简称FILO。栈正是FILO型的缓冲区,PUSH将数据压入栈顶,POP将数据从栈顶取出。PUSHEAX这个指令相当于:ADDESP,-4MOV[SS:ESP],EAXPOPEAX指令相当于:MOVEAX,[SS:ESP]ADDESP,4还有一个不常见的指令PUSHAD相当于:PUSHEAXPUSHECXPUSHEDXPUSHEBXPUSHESPPUSHEBPPUSHESIPUSHEDI反过来POPAD指令同上相反顺序。函数_asm_inthandler21的目的是保存中断现场的值,然后将该函数注册到IDT中去。/*IDT的设定*/set_gatedesc(idt+0x21,(int)asm_inthandler21,2*8,AR_INTGATE32);set_gatedesc(idt+0x27,(int)asm_inthandler27,2*8,AR_INTGATE32);set_gatedesc(idt+0x2c,(int)asm_inthandler2c,2*8,AR_INTGATE32);asm_inthandler注册在idt的第0x21号,2*8表示的是asm_inthandler的属于哪一个段,即段号是2,乘以8是因为低3位有着别的意思,所以低三位必须是0。所以“2*8”也可以写成“23”或者16。号码为2的段:set_segmdesc(gdt+2,LIMIT_BOTPAK,ADR_BOTPAK,AR_CODE32_ER);这个语句说明这个段正好涵盖了整个bootpack.hrb。最后的AR_INTGATE32将IDT的属性设定为0x008e,表示这是用于中断处理的有效设定。二、遇到的问题及解决方法1、set_segmdesc函数中关于limit/=0x1000的理解;我们看到段上限是20位,这样段最大也只能指定到1MB,所以才有设置标志位Gbit为1,使limit的单位为页,而不是字节,那么具体如何实现呢?就是要让相应数字除以一页的字节数。所以这个也就好理解了。Limit没超过0xffff时就用字节为单位,超过就使用页为单位,并将单位换算,也就是进行limit/=0x1000的处理。2、键盘中断是怎么实现的;首先就是我们进行了一个PIC初始化的工作(上面有代码),将原来设置电脑时设置好的对应中断和中断号对应了起来。初始化成功后,程序就能接收到外部的中断的信号了,只是还没弄好对应的中断程序和中断序列表而已了。然后我们进行idt的初始化,然后将中断函数的初始地址等信息放入到idt即中断序列表中。当电脑接收到相应的键盘信号后,就会寻找相应的idt序号,并跳转到相应的程序执行。这里就是事实上跳转到这里后CPU就停止在键盘中断函数里了。三、程序设计创新点1、这次学了中断,然后上次的动态条就可以改变停止方式了。程序运行结果:这次在主函数加上上次一个实现动态等待条的代码即可,键盘中断后CPU进入挂起的状态。动态条停止。等待条代码(函数dtiao())和上次实现时的相同,也是while(1),处于等待中断的状态。四、实验心得体会这次实验的内容是真的难,,,也可能是上次把一些知识遗到这次了。从讲分段开始就很专业,

1 / 12
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功