分析system_call中断处理过程
分析system_call中断处理过程
上周我们使用gcc内嵌汇编调用系统调用,这次我们具体分析下过程。
将getpid嵌入menuos
代码从github下载,步骤如下:
1. 增加一个函数,getpid
2. 在main中添加MenuConfig("getpid","Show Pid", Getpid);
3. 重新编译 make roofs
4. 此时启动 执行getpid就可以看到打印出pid为1
见下面两张图:
menuos的原理
其实这个很简单,在上上周我们分析过linux内核的启动过程,1号进程,就是init,它的执行逻辑是/sbin/bin,所以这里的menuos就是编写的init。
这里注意,linux内核源码不包含/sbin/bin,一般的发行版使用的是FreeBSD的版本。
这里的menuos就是自己制作init,然后嵌入linux内核编译出的镜像。
所以在menuos中执行getpid,得到的pid为1,见上图。
中断处理
中断分为两种,一种是外中断,由外部的IO设备产生,另一种是内中断,也称为异常,由CPU内部产生。
这里涉及到一个很重要的概念,叫做中断上下文。
CPU的运行状态,分为以下三种:
1. 内核态,运行于进程上下文,内核代表进程运行于内核空间。
2. 内核态,运行于中断上下文,内核代表硬件运行于内核空间。
3. 用户态,运行于用户空间。
从上面,我们可以看出,中断上下文不与任何的进程相关联,仅仅运行在内核空间,而且一般只访问内核数据。
这里顺便总结下进程上下文:
1. 用户级上下文: 正文、数据、用户堆栈以及共享存储区;
2. 寄存器上下文: 通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP);
3. 系统级上下文: 进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈。
其实就是包含三个内容:用户数据、硬件状态(主要是寄存器)、内核数据。
所以,当发生进程调度时,要将三个上下文全部进行切换。
当进行系统调用时,仅仅需要切换寄存器上下文。
相比进程上下文,中断上下文仅仅包含一些寄存器的信息。发生中断时,所谓的保护现场和恢复现场,指的就是这些寄存器信息。
分析system_call
代码如下:
# system call handler stub
ENTRY(system_call)
RING0_INT_FRAME # can't unwind into user space anyway
ASM_CLAC
pushl_cfi %eax # save orig_eax
SAVE_ALL # 保存系统寄存器信息
GET_THREAD_INFO(%ebp) # 获取thread_info结构的信息
# system call tracing in operation / emulation
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) # 测试是否有系统跟踪
jnz syscall_trace_entry # 如果有系统跟踪,先执行,然后再回来
cmpl $(NR_syscalls), %eax # 比较eax中的系统调用号和最大syscall,超过则无效
jae syscall_badsys # 无效的系统调用 直接返回
syscall_call:
call *sys_call_table(,%eax,4) # 调用实际的系统调用程序
syscall_after_call:
movl %eax,PT_EAX(%esp) # 将系统调用的返回值eax存储在栈中
syscall_exit:
LOCKDEP_SYS_EXIT
DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
# setting need_resched or sigpending
# between sampling and the iret
TRACE_IRQS_OFF
movl TI_flags(%ebp), %ecx
testl $_TIF_ALLWORK_MASK, %ecx # 检测是否所有工作已完成
jne syscall_exit_work # 未完成,则去执行这些任务
restore_all:
TRACE_IRQS_IRET # iret 从系统调用返回
这段代码的逻辑主要就是:
1. 保存寄存器上下文,
2. 检查系统调用号是否合法
3. 执行系统调用
4. 检查是否还有别的工作需要完成
5. 退出系统调用,返回到用户态
我们继续跟踪里面的syscall_exit_work,它用来处理系统调用之后,未完成的工作
syscall_exit_work:
testl $_TIF_WORK_SYSCALL_EXIT, %ecx # 测试syscall的工作完成
jz work_pending
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call
# schedule() instead
movl %esp, %eax
call syscall_trace_leave
jmp resume_userspace
END(syscall_exit_work)
这一段的主要作用还是进入work_pending
work_pending代码:
work_pending:
testb $_TIF_NEED_RESCHED, %cl # 判断是否需要调度
jz work_notifysig # 不需要则跳转到work_notifysig
work_resched:
call schedule # 调度进程
LOCKDEP_SYS_EXIT
DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
# setting need_resched or sigpending
# between sampling and the iret
TRACE_IRQS_OFF
movl TI_flags(%ebp), %ecx
andl $_TIF_WORK_MASK, %ecx # 是否所有工作都已经做完
jz restore_all # 是则退出
testb $_TIF_NEED_RESCHED, %cl # 测试是否需要调度
jnz work_resched # 重新执行调度代码
这段的逻辑很清楚
1. 先检查是否需要调度,
2. 如果是,则进行进程调度,之后再次判断。
3. 如果不需要调度,那么去执行work_notifysig,处理信号
work_notifysig代码:
work_notifysig: # 投递信号
#ifdef CONFIG_VM86
testl $X86_EFLAGS_VM, PT_EFLAGS(%esp) # 判断8086虚模式,也就是保护模式
movl %esp, %eax
jne work_notifysig_v86 # 返回到内核空间
1:
#else
movl %esp, %eax
#endif
TRACE_IRQS_ON
ENABLE_INTERRUPTS(CLBR_NONE)
movb PT_CS(%esp), %bl
andb $SEGMENT_RPL_MASK, %bl
cmpb $USER_RPL, %bl
jb resume_kernel
xorl %edx, %edx
call do_notify_resume # 将信号投递到进程
jmp resume_userspace # 恢复用户空间
#ifdef CONFIG_VM86 # 如果是VM86模式,需要保存状态信息
ALIGN
work_notifysig_v86:
pushl_cfi %ecx # save ti_flags for do_notify_resume
call save_v86_state # 保存虚模式下的状态
popl_cfi %ecx
movl %eax, %esp
jmp 1b # 跳转到上面的代码,执行do_notify_resume
#endif
END(work_pending)
这段代码主要是处理信号:
1. 先检查是否是8086保护模式
2. 如果是,那么需要先保存虚模式下的状态信息
3. 然后跳转到之前的代码继续执行
4. 将信号投递到进程
5. 恢复用户空间
之后就是返回系统调用
流程图总结
如图:
总结
系统调用中断,本质上也是一个保存状态、进行处理、返回并恢复状态的过程。
署名信息
郭春阳 原创作品转载请注明出处 :《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000
分析system_call中断处理过程的更多相关文章
- 20135202闫佳歆--week5 分析system_call中断处理过程--实验及总结
week 5 实验:分析system_call中断处理过程 一.使用gdb跟踪分析一个系统调用内核函数(上周选择那一个系统调用)--getpid 复习视频: 如何实现? - 更新menu代码到最新版 ...
- 作业五:分析system_call中断处理过程
分析system_call中断处理过程 一.MesuSO增加getpid和getpid-asm 二.使用GDB跟踪系统调用内核函数sys_getpid 分析system_call中断处理过程 使用gd ...
- 《Linux内核分析》第五周:分析system_call中断处理过程
实验 分析system_call中断处理过程 使用gdb跟踪分析一个系统调用内核函数(您上周选择那一个系统调用),系统调用列表参见http://codelab.shiyanlou.com/xref/l ...
- Linux内核分析-分析system_call中断处理过程
姓名:江军 ID:fuchen1994 分析system_call中断处理过程 使用gdb跟踪分析一个系统调用内核函数(您上周选择那一个系统调用),系统调用列表参见http://codelab.shi ...
- Linux内核分析第五周学习总结——分析system_call中断处理过程
Linux内核分析第五周学习总结--分析system_call中断处理过程 zl + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...
- 通过分析system_call中断处理过程来深入理解系统调用
通过分析system_call中断处理过程来深入理解系统调用 前言说明 本篇为网易云课堂Linux内核分析课程的第五周作业,上一次作业中我以2个系统调用(getpid, open)作为分析实例来分析系 ...
- 实验五:分析system_call中断处理过程
原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 如果我写的不好或者有误的地方请留言 ...
- 实验五分析system_call中断处理过程
一.实验要求: 1.使用gdb跟踪分析一个系统调用内核函数 2.根据本周所学知识分析系统调用的过程,从system_call开始到iret结束之间的整个过程,并画出简要准确的流程图 二.实验步骤: 1 ...
- Linux内核设计第五周学习总结 分析system_call中断处理过程
陈巧然原创作品 转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 使用gdb跟踪分析一 ...
随机推荐
- lstm
http://colah.github.io/posts/2015-08-Understanding-LSTMs/ 这里介绍lstm写的很不错,尤其是按照不同的part进行解析,感觉很好,很清晰.
- Java web 之表单验证
按照软件工程师的定位来讲,表单验证应该要好好练习的 html javascript
- jQuery实现无缝滚动条
很多时候只看别人的代码时很难看懂.有很多原因,有时候可能是没有耐心,这时候看一下实现的原理就很快明白代码的内容,所以要加些注释,让自己让别人都能看明白:有的时候就是因为知识有限就是不懂,哪怕代码很简单 ...
- Java中的转义字符
1.转义字符 1.八进制转义序列:\ + 1到3位5数字:范围'\000'~'\377' \0:空字符 2.Unicode转义字符:\u + 四个十六进制数字:0~65535 \u ...
- iOS改变NavigationBar的返回键和标题颜色、大小
UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom]; [UIPubic initHeadViewBackImgWithBt ...
- 用Backbone.js创建一个联系人管理系统(二)
欢迎大家回来继续这一教程,第一部分我们学习了model,collection和view在Backbone中的 基本用法,还有怎么样用主视图去绑定collection去渲染出每个Contact. 这部分 ...
- SQL语言和DML相关操作以及相应的运算符
SQL 1.结构化查询语言 2.特点 a.第四代编程语言,更接近自然语言 b必须有数据库系统解释执行 c.对象名,关键字不区分大小写 d.字符串必须要用单引号引起来,不能用双引号 e.每条语句最后用分 ...
- 2287: 【POJ Challenge】消失之物
Description ftiasch 有 N 个物品, 体积分别是 W1, W2, ..., WN. 由于她的疏忽, 第 i 个物品丢失了. "要使用剩下的 N - 1 物品装满容积为 x ...
- 在Linux中让打印带颜色的字
echo显示带颜色,需要使用参数-e 格式如下: echo -e "\033[字背景颜色;文字颜色m字符串\033[0m" 例如: echo -e "\033[41;37 ...
- 深入浅出话VC++(1)——Windows程序内部运行机制
一.引言 要想熟练掌握Windows应用程序的开发,首先需要理解Windows平台下程序运行的内部机制,然而在.NET平台下,创建一个Windows桌面程序,只需要简单地选择Windows窗体应用程序 ...