第5章  系统调用的三层机制(下)

1  给MenuOS增加命令

        首先进入LinuxKernel目录下,用rm -rf menu强制删除当前的menu目录,然后用git clone重新克隆一个新版本的menu,如下图所示:

       

新版本的menu中已经将上一章做的两个系统调用添加进去了,在test.c里我们看到添加的两个系统调用,如下图所示:

可以看到在test.c里的main()函数增加了增加了两行代码,一个是MenuConfig("time"),另一个是MenuConfig("time-asm"),从这里看出如果要给MenuOS增加新的命令,只需要使用MenuConfig命令,并增加对应的函数即可。

接下来进入menu目录下,运行make rootfs脚本就可以自动编译并自动生成根文件系统,这时打开了menu镜像,如下图所示:

在MenuOS菜单中输入help命令可以看到新增了 两条命令,输入time命令和time-asm命令可以看到运行结果,如下图所示:

2  使用gdb跟踪系统调用内核函数sys_time 

        用“qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S”命令先把内核启动一下,可以看到被冻结起来了,代码没有被运行,如下图所示:

        

再另外打开一个shell窗口,用Ctrl+Shift+O实现水平分割

启动gdb,把内核加载进来,建立连接。这里用到的代码为:

 file linux-3.18./vmlinux
target remote:

在这个地方可以看到出现了一个问题:在输入target remote:1234命令时,显示连接超时,这是因为我关掉了另一个Shell打开的MenuOS菜单,重新输入qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S命令打开之后,显示的是连接成功。

接下来就可以设置断点了,在这里用break start_kernel设置一个断点,在此之前内核一直是stop状态,如果按“c”则继续执行,系统开始启动,并启动到start_kernel函数的位置停在断点处,如下图所示:

time系统调用是13号系统调用对应的内核处理函数,即sys_time。接下来在这里用break sys_time设置一个断点,按“c”继续执行,启动MenuOS后执行time命令,程序会停到sys_time这个函数的位置,time命令执行到一半将卡在那里,如下图所示:

通过list命令列出sys_time对应的代码如下图所示:

使用s命令单步执行进入get_seconds(),然后用gdb的finish命令把这个函数全部执行完,再单步执行,一直到return i,获得的就是当前系统时间time的数值。

当执行int 0x80时,CPU会自动跳转到system_call函数,所以我们把断点设置到system_call,并继续执行,如下图所示:

可以看到在MenuOS中执行time-asm命令时,还是停在了原先设定的sys_time这个位置,在system_call这个位置并不能停下。sys_call是一段特殊的汇编代码,只能调试系统调用的内核函数和其他内核函数的处理过程,且system_call还有一个函数原型声明,但它并不是一个普通的函数,,只是一段汇编代码的起点,且内部没有严格遵守函数调用堆栈机制,所以gdb不能完成跟踪执行过程的任务。

3  系统调用在内核代码中的处理过程

3.1  中断向量0x80和system_call中断服务程序入口的关系

      

      在用户态中有一个系统调用xyz(),xyz()系统调用库函数里面用了SYSCALL(在这里即为int 0x80)来触发系统调用,其中中断向量0x80对应system_call中断服务程序入口。

在start_kernel函数里调用的trap_init函数中有一段代码如下:

#ifdef CONFIG_x86_32
set_system_trap_gate(SYSCALL_VECTOR, &system_call);
set_bit(SYSCALL_VECTOR, used_vectors);
#endif

这里通过set_system_trap_gate函数绑定了中断向量0x80(这里的SYSCALL_VECTOR是系统调用的中断向量0x80)和system_call中断服务程序入口后,一旦执行int 0x80,CPU就直接跳转到system_call这个位置来执行,即系统调用的工作机制在start_kernel里初始化好之后,CPU一旦执行到Int 0x80指令就会立即跳转到system_call的位置。

3.2  在system_call汇编代码中的系统调用内核处理函数

system_call这一段代码就是系统调用的处理过程,系统调用是一个特殊一点的中断(或称之为软中断),这一段代码中也有保存现场SAVE_ALL和恢复现场restore_all的过程。同时,system_call_table是一个系统调用的表,EAX寄存器传递的系统调用号,使用者在调用它时会根据EAX寄存器来调用对应的系统调用内核处理函数。

简化后的system_call代码为:

ENTRY(system_call)
RING0_INT_FRAME
ASM_CLAC
pushl_cfi %eax #保存系统调用号
SAVE_ALL #保存现场,将用到的所有CPU寄存器保存到栈中
GET_THREAD_INFO(%ebp) #ebp用于存放当前进程thread_info结构的地址
testl $_TIF_WORK_SYSCALL_ENTRY, TI_flags(%ebp)
jnz syscall_trace_entry
cmpl $(nr_syscalls), %eax #检查系统调用号(系统调用号应小于NR_syscalls)
jae syscall_badsys #不合法,跳入异常处理
syscall_call:
call *sys_call_table(,%eax,) #通过系统调用号在系统调用表中找到相应的系统调用内核处理函数,比如sys_time
movl %eax, PT_EAX(%esp) #保存返回值到栈中
syscall_exit:
testl $_TIF_ALLWORK_MASK, %ecx #检查是否有任务需要处理
jne syscall_exit_work #需要,进入syscall_exit_work,这里是最常见的进程调度时机
restore_all:
TRACE_IRQS_TRET #恢复现场
irq_return:
INTERRUPT_RETURN #iret

从entry(system_call)开始看这段代码,根据系统调用号来查sys_call_table表中的位置,调用系统调用对应的处理函数,在syscall_exit里面判断当前的任务是否需要处理syscall_exit_work,进入syscall_exit_work,这是最常见的进度调度时机点。

sys_call_table(,%eax,4)中每个表项占4个字节,所以先把系统调用号(EAX寄存器)乘以4,再加上sys_call_table分派表的起始地址,即得到系统调用号对应的系统调用内核处理函数的指针。sys_call_table分派表是由一段脚本根据linux-3.18.6/arch/x86/syscalls/syscall_32.tbl来自动生成的。

3.3  整体上理解系统调用的内核处理过程

         system_call流程如下图所示:

         

总结一下:从系统调用处理过程的入口开始,可以看到SAVE_ALL保存现场,然后找到syscall_call和sys_call_table。call *sys_call_table(,%eax,4)就是调用了系统调用的内核处理函数,之后restore_all和最后有一个INTERRUPT_RETURN(iret)用于恢复现场并返回系统调用到用户态结束。在这个过程当中可能会执行syscall_exit_work,里面有work_pending,其中的work_notifysig是处理信号的。work_pending里还有可能调用schedule,这是一个非常关键的部分。

4  总结

在第四章的基础上,这一章进一步深入内核系统调用处理过程:在用户态下的xyz()就是一个API函数,是系统调用对应的API,其中封装了一个系统调用,这个系统调用 SYSCALL(即为int 0x80汇编语句)来触发中断,对应system_call内核代码的起点,即中断向量0x80对应的中断服务程序入口。从system_call内核代码的起点开始,先是SAVE_ALL保存现场,再是检查EAX寄存器中保存的系统调用号的正确性,接着根据系统调用号在sys_call_table这个分派表查找相对应的系统调用内核处理函数sys_xyz()的入口,得到这个函数的返回值保存到栈中,然后在syscall_exit里面判断当前的任务是否需要处理syscall_exit_work,进入sys_exit_work,进行进程调度,调度完之后就会跳转到restore_all,恢复现场返回系统调用到用户态。

    

2019-2020-6 20199317《Linux内核原理与分析》第六周作业的更多相关文章

  1. 2019-2020-1 20199329《Linux内核原理与分析》第九周作业

    <Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...

  2. 2019-2020-1 20199329《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...

  3. 20169212《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...

  4. 20169210《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...

  5. 2018-2019-1 20189221 《Linux内核原理与分析》第九周作业

    2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...

  6. 2017-2018-1 20179215《Linux内核原理与分析》第二周作业

    20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...

  7. 2019-2020-1 20209313《Linux内核原理与分析》第二周作业

    2019-2020-1 20209313<Linux内核原理与分析>第二周作业 零.总结 阐明自己对"计算机是如何工作的"理解. 一.myod 步骤 复习c文件处理内容 ...

  8. 2018-2019-1 20189221《Linux内核原理与分析》第一周作业

    Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...

  9. 《Linux内核原理与分析》第一周作业 20189210

    实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...

  10. 2018-2019-1 20189221《Linux内核原理与分析》第二周作业

    读书报告 <庖丁解牛Linux内核分析> 第 1 章 计算工作原理 1.1 存储程序计算机工作模型 1.2 x86-32汇编基础 1.3汇编一个简单的C语言程序并分析其汇编指令执行过程 因 ...

随机推荐

  1. 关于生成器generator

    generator:个人认为是产生值的,和列表生成式类似,但是比列表生成式更加节省空间 我们平常自己构造的函数中,一般返回值时都会使用return,在generator中,我们使用的是yield yi ...

  2. 我对C++开发人员有偏见

    前言 我确实对C++开发人员有一些偏见,我也知道对一类人有偏见是不正确的行为:但,在我所处的三线城市的环境中,我对C++开发有偏见并非是一件不正确的事,因为C++开发都是变态这件事,根本就是客观事实. ...

  3. 在线热备份数据库之innobackupex 增量备份InnoDB

    在线热备份数据库之innobackupex 增量备份InnoDB 什么是增量备份?其原理是什么? 增量备份是基于上一次备份后对新增加的内容进行备份,优点相较于完整备份而言备份内容少时间短,能够节省磁盘 ...

  4. [考试反思]1019csp-s模拟测试80(a):天遣

    A组题,所以把榜粘全了. 第6名,被卡在刚好正中间. 我最近干什么伤天害理的事了?(例如说没有在skyh去上厕所的时候捶他) 上来看T1,非常贴心出题人直接把递推式子给你了,然后就和斐波数的递推一样了 ...

  5. 1.基础篇之vue入门

    为了建立高效团队,很多公司会采用全栈工程师,虽然利弊兼有,对于成本优先的创业团队,肯定是首选,特别是对.net生态圈,大部分都是小公司,就更加重要了.这里记录的是对vue的学习点滴,希望对你有所助力. ...

  6. mount 和 /etc/fstab关系。

    mount  -a 自动按照格式执行/etc/fstab里面的文件. /etc/fstab 文件格式: device        mount-point      type      options ...

  7. nyoj 268-荷兰国旗问题 (count)

    268-荷兰国旗问题 内存限制:64MB 时间限制:3000ms 特判: No 通过数:15 提交数:20 难度:1 题目描述: 荷兰国旗有三横条块构成,自上到下的三条块颜色依次为红.白.蓝.现有若干 ...

  8. 什么是TCP, UDP, HTTP, HTTPS协议?

    TCP 传输控制协议是一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC793定义. TCP主要特点: 1. 面向连接: (1)应用程序在使用TCP协议之前,必须先建立TCP连接. ...

  9. opencv 2 Opencv数据结构与基本绘图

    基础图像容器Mat Mat 是一个类,又两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法不同,矩阵可以是不同的维数)的指针.矩阵头的尺 ...

  10. 软件测试的原则,软件测试计划:5W1H

    1.测试应该尽早介入.        2.所有的测试都应追溯到用户需求.        3.程序员应该避免检查自己的程序.除了单元测试.因为程序员对于自己的作品,思维具有局限性.无法保证测试质量.交给 ...