实验5――中断异常系统调用_第1页
实验5――中断异常系统调用_第2页
实验5――中断异常系统调用_第3页
实验5――中断异常系统调用_第4页
实验5――中断异常系统调用_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、实验5:中断/异常/系统调用姓名:学号:要求(对于系统调用:1、Linux的系统调用利用了x86的哪种硬件机制?系统调用是作为一种异常类型实现的。它将执行相应的机器代码指令来产生异常信号。产生中断或异常的重要效果是系统自动将用户模式切换为内核模式来对它进行处理。这就是说,执行系统调用的异常指令时,将自动地将系统切换为内核模式,并安排异常处理程序的执行。它知道如何处理这一调用。在LINUX中实现系统调用异常的实际指令是:int $0x80这一指令使用中断/异常向量号128(即16进制的80将控制权转移给内核。为达到在系统调用时不必用机器指令编程,在标准的C语言库中为每一个系统调用提供了一段短的子

2、程序,完成机器代码的编程工作。事实上,机器代码非常短。它要做的工作只是将送给系统调用的参数值加载到CPU寄存器中,接着执行int $0x80指令。然后运行系统调用,系统调用的返回值将送入CPU的一个寄存器中,标准的库子程序取得这一返回值,并将它送回给你的程序。为了使系统调用执行成为一项简单的任务,LINUX中提供了一组预处理宏指令。它们可以用在程序中。这些宏指令取一定的参数,然后扩展为调用指定的系统调用的函数。2、说明Linux是如何组织系统调用的?在Linux中,每个系统调用被赋予一个系统调用号。这样,通过这个独一无二的号就可以关联系统调用。当用户空间的进程执行一个系统调用的时候,这个系统调

3、用号就被用来指明到底是要执行哪个系统调用。进程不会提及系统调用的名称。系统调用号相当关键,一旦分配就不能再有任何变更,否则编译好的应用程序就会崩溃。Linux有一个“未实现”系统调用sys_ni_syscall(,它除了返回一ENOSYS外不做任何其他工作,这个错误号就是专门针对无效的系统调用而设的。因为所有的系统调用陷入内核的方式都一样,所以仅仅是陷入内核空间是不够的。因此必须把系统调用号一并传给内核。在x86上,系统调用号是通过eax寄存器传递给内核的。在陷人内核之前,用户空间就把相应系统调用所对应的号放入eax中了。这样系统调用处理程序一旦运行,就可以从eax中得到数据。其他体系结构上的

4、实现也都类似。内核记录了系统调用表中的所有已注册过的系统调用的列表,存储在sys_call_table中。它与体系结构有关,一般在entry.s中定义。这个表中为每一个有效的系统调用指定了惟一的系统调用号。sys_call_table是一张由指向实现各种系统调用的内核函数的函数指针组成的表:ENTRY(sys_call_table.long SYMBOL_NAME(sys_ni_syscall /* 0-old "setup(" system call*/.long SYMBOL_NAME(sys_exit.long SYMBOL_NAME(sys_fork.long SY

5、MBOL_NAME(sys_read.long SYMBOL_NAME(sys_write.long SYMBOL_NAME(sys_open /* 5 */.long SYMBOL_NAME(sys_close.long SYMBOL_NAME(sys_waitpid.long SYMBOL_NAME(sys_capget.long SYMBOL_NAME(sys_capset/* 185 */.long SYMBOL_NAME(sys_sigaltstack.long SYMBOL_NAME(sys_sendfile.long SYMBOL_NAME(sys_ni_syscall /* s

6、treams1 */.long SYMBOL_NAME(sys_ni_syscall /* streams2 */.long SYMBOL_NAME(sys_vfork/* 190 */system_call(函数通过将给定的系统调用号与NR_syscalls做比较来检查其有效性。如果它大于或者等于NR syscalls,该函数就返回一ENOSYS。否则,就执行相应的系统调用。call *sys_ call-table(,%eax, 4由于系统调用表中的表项是以32位(4字节类型存放的,所以内核需要将给定的系统调用号乘以4,然后用所得的结果在该表中查询其位置3、说明一个用户态的程序是如何进入系

7、统调用中执行的?用户空间的程序无法直接执行内核代码。它们不能直接调用内核空间中的函数,因为内核驻留在受保护的地址空间上。如果进程可以直接在内核的地址空间上读写的话,系统安全就会失去控制。所以,应用程序应该以某种方式通知系统,告诉内核自己需要执行一个系统调用,希望系统切换到内核态,这样内核就可以代表应用程序来执行该系统调用了。通知内核的机制是靠软件中断实现的。首先,用户程序为系统调用设置参数。其中一个参数是系统调用编号。参数设置完成后,程序执行“系统调用”指令。x86系统上的软中断由int产生。这个指令会导致一个异常:产生一个事件,这个事件会致使处理器切换到内核态并跳转到一个新的地址,并开始执行

8、那里的异常处理程序。此时的异常处理程序实际上就是系统调用处理程序。它与硬件体系结构紧密相关。新地址的指令会保存程序的状态,计算出应该调用哪个系统调用,调用内核中实现那个系统调用的函数,恢复用户程序状态,然后将控制权返还给用户程序。系统调用是设备驱动程序中定义的函数最终被调用的一种方式。4、以某个系统调用为例,从用户激活系统调用开始,分析系统调用在Linux中是如何一步一步执行的系统调用实例分析:sys_exit当用户发出一个退出系统命令的时候,Linux就调用系统调用sys_exit。系统调用sys_exit 的主要作用是终止当前正在运行的所有用户的应用程序,保存当前帐号的各种信息,逐步退出支

9、撑Linux操作系统运行的系统子模块和子系统。这些系统子模块和子系统是:1.删除当前任务的实定时器。2. 删除信号队列(destroye semaphore arrays,释放信号撤消结构(free semaphores undo structures3. 清空当前任务的kerneld队列。4. 退出内存管理。5. 关闭打开的文件。6. 退出文件系统。7. 释放当前任务的所有信号(signal。8. 退出线程(thread。系统调用sys_exit的处理函数定义在文件kernel/exit.c中。sys_exit的函数体很简单,只是调用了函数do_exit:do_exit(error_code

10、&0xff<<(error_code&0xff<<8的作用就是将error_code的低8位移到高8位中,低8位用0填补,此数将作为参数传给函数do_exit。下面来看看函数do_exit是怎样做的。首先,do_exit判断表示是否有正在处理的中断服务全局变量intr_count是否为1,如果为1,表明当前还有中断正在处理,执行intr_count=0,停止处理中断。接着,do_exit要为关闭系统,逐步退出一些运行操作系统所必须的模块。1.执行函数acct_process(。(该函数定义在kernel/sys.c中再该函数中,保存当前帐号的各种状态。2

11、. 把当前任务的标记记为退出:current->flags |= PF_EXITING;向所有的进程宣布,现在系统要退出了,以便一些调度处理函数得知这一消息(通过检测该标记。3. 删除当前的实定时器:del_timer(¤t->real_timer;4. 删除信号队列(destroye semaphore arrays,释放信号撤消结构(free semaphores undo structuresSem_exit(;(定义在ipc/sem.c文件中在该函数中,增加调整值(semval给信号,再释放撤消结构(free undo structures。由于某些信号(sema

12、phore可能已经过时或无效了,直到信号数组(semaphore array被删除了以后,撤消结构(undo structures才被释放。具体做法如下:a.如果当前进程正在睡眠状况(需要一信号(semaphore来唤醒,将进程当前指向所需信号(semaphore的指针置空。b.在当前的信号撤消链表(struct sem_undo里查找a中提到的那信号(semaphore,找到以后,调整该信号(已在信号撤消链表中注册过的的内容。c.由于有可能有一个队列的进程在等该信号,故须更新整个操作系统的数组。5. 清空当前任务的kerneld队列:kerneld_exit(;6. 退出内存管理系统:_ex

13、it_mm(current;(函数定义在kernel/exit.c文件中具体做法如下:a.将cache,tlb,page里的内容全部回写。b.退出内存影射。c.释放页表(page table。7. 把当前任务所打开的文件都关闭,释放文件指针。_exit_files(current;8. 退出文件系统:_exit_fs(current;9. 释放当前任务的所有信号(signal:_exit_sighand(current;10.释放当前线程数据:_exit_thread(;11. 向外广播退出:exit_notify(;先将当前任务的状态(state设为TASK_ZOMBIE,退出码为code(

14、即传进来的参数。再调用exit_notify(函数。在exit_notify(中,作为我们执行上述过程后,退出系统的结果,我们的进程组们应该变成孤立的了。如果它们已经停止工作了,给它们发"SIGHUP"和"SIGCONT"信号。接着,通知它们的父进程,本进程已经被kill了。接下去是一循环,该循环主要做以下两件事:使初始进程(init继承所有子进程。检查是否有遗漏:还有进程组不是孤立的。若有,处理方法同上。最后,调用函数disassciate_ctty(int(定义在drivers/char/tty_io.c中。只有当参数是1时,才是被exit_noti

15、fy(调用的。在该函数中,将当前tty进程组kill掉,所有进程对应的tty成员赋NULL。12.将当前任务的用户数目减一:(*current->exec_domain->use_count-;(*current->binfmt->use_count-;13.继续调度:schedule(;在调用完sys_exit后,先判断返回值_res是否为非负数。若是,则说明该次调用是成功的,返回_res即可。若_res为负数,则说明该次调用过程中存在着一个或一些错误,将错误值赋给一全局变量errno:errno = -_res;再返回-1,指明有错误存在,可以让专门处理这些错误的函

16、数根据errno的值知道这次调用到底出错在什么地方,是哪种类型的错,以便进行错误处理。5、自己编写一个系统调用,并编写用户态程序,从这个用户态程序中调用这个系统调用如果用户在Linux中添加新的系统调用,应该遵循几个步骤才能添加成功,下面几个步骤详细说明了添加系统调用的相关内容。(1添加源代码第一个任务是编写加到内核中的源程序,即将要加到一个内核文件中去的一个函数,该函数的名称应该是新的系统调用名称前面加上sys_标志。假设新加的系统调用为mycall(int number,在/usr/src/linux/kernel/sys.c文件中添加源代码,如下所示:asmlinkage int sys

17、_mycall(int numberreturn number;作为一个最简单的例子,我们新加的系统调用仅仅返回一个整型值。(2连接新的系统调用添加新的系统调用后,下一个任务是使Linux内核的其余部分知道该程序的存在。为了从已有的内核程序中增加到新的函数的连接,需要编辑两个文件。第一个要修改的文件是:/usr/src/linux/include/asm-i386/unistd.h该文件中包含了系统调用清单,用来给每个系统调用分配一个唯一的号码。文件中每一行的格式如下:#define _NR_name NNN其中,name用系统调用名称代替,而NNN则是该系统调用对应的号码。应该将新的系统调用

18、名称加到清单的最后,并给它分配号码序列中下一个可用的系统调用号。我们的系统调用如下:#define _NR_mycall 191系统调用号为191,之所以系统调用号是191,是因为Linux-2.2内核自身的系统调用号码已经用到190。第二个要修改的文件是:/usr/src/linux/arch/i386/kernel/entry.S该文件中有类似如下的清单:.long SYMBOL_NAME(该清单用来对sys_call_table数组进行初始化。该数组包含指向内核中每个系统调用的指针。这样就在数组中增加了新的内核函数的指针。我们在清单最后添加一行: .long SYMBOL_NAME(sy

19、s_mycall(3重建新的Linux内核为使新的系统调用生效,需要重建Linux的内核。这需要以超级用户身份登录。#pwd/usr/src/linux#超级用户在当前工作目录(/usr/src/linux下,才可以重建内核。#make config#make dep#make clearn#make bzImage编译完毕后,系统生成一可用于安装的、压缩的内核映象文件:/usr/src/linux/arch/i386/boot/bzImage(4用新的内核启动系统要使用新的系统调用,需要用重建的新内核重新引导系统。为此,需要修改/etc/lilo.conf 文件,在我们的系统中,该文件内容如

20、下:boot=/dev/hdamap=/boot/mapinstall=/boot/boot.bprompttimeout=50image=/boot/vmlinuz-2.2.5-15label=linuxroot=/dev/hdb1read-onlyother=/dev/hda1label=dostable=/dev/had首先编辑该文件,添加新的引导内核: image=/boot/bzImage-new label=linux-new root=/dev/hdb1 read-only 添加完毕,该文件内容如下所示: boot=/dev/hda map=/boot/map install=/boot/boot.b prompt timeout=50 image=/boot/bzImag

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论