0 源代码

有两个版本的,一个是带中文注释,Intel格式的;一个是不带注释是AT&T格式的。

Linux 0.11 中文注释版
Linux 0.11 源码,基于《Linux内核完全注释》赵炯

1 asm.s 文件

我们先假设该文件处理的中断是无特权过渡的情况(具体是不是暂时不知道)。

我们看一下,当中断发生且被检测到之后,硬件做了什么。

我们可以看到,中断被检测到之后,一些必要的信息被压栈了。

在80386手册中提到,中断发生之后,一些必要的,为了中断程序结束之后返回原程序继续执行的信息,会被压栈,就像最开始那个图看到的内样,这里分成了4种情况,我们只讨论无特权转换的两种情况,分别输有出错码的异常和无处错码的异常。

这个压栈过程是硬件完成的,回顾一下我们之前的知识

在中断发生之后,80386执行了

  1. 保存断点(将EFLAGS,CS,EIP依次压栈)
  2. 识别中断源

至于怎么通过中断号,找到对应的中断服务程序,我们后面说。

2 无处错码中断

源代码在kernel/asm.s文件中

_divide_error:  # int0 除法错中断,中断错误码是0pushl $_do_divide_error  # 用于打印除法错中断的错误信息的函数,在traps.c实现# 中断处理程序的地址入栈
no_error_code:# 保护现场xchgl %eax,(%esp) # eax的值入栈,eax保存中断处理程序地址pushl %ebxpushl %ecxpushl %edxpushl %edipushl %esipushl %ebppush %ds        # 占4字节而非2字节push %espush %fspushl $0     # "error code" 中断有无错误码,是有相关规定的lea 44(%esp),%edxpushl %edx# 设置内核数据段选择符,设置好数据寻址的基址movl $0x10,%edxmov %dx,%dsmov %dx,%esmov %dx,%fscall *%eax  # 执行中断处理程序,C语言函数do_divide_error# 恢复现场addl $8,%esppop %fspop %espop %dspopl %ebppopl %esipopl %edipopl %edxpopl %ecxpopl %ebxpopl %eaxiret # 返回中断处理之前的程序,继续执行后续指令_debug:pushl $_do_int3        # _do_debugjmp no_error_code

我们通过画堆栈内存图的方式分析一下这个过程。

2.1 检测中断后,硬件完成的事情

硬件完成的事情其实就是压栈,压栈之后的内存图是:

2.2 进入中断服务程序

在识别到中断源之后,通过某种方式,CPU获取的中断服务程序的CS:EIP,进入了终端服务程序,我们这里以debug为例子。

注意,所有的无出错号的中断,默认当成出错号是0,会在保护现场的时候入栈,这个其实是配合实际出错号是0的除法错中断,先不管它。

pushl $_do_int3      # _do_debug 中断服务程序主体,中断处理程序
jmp no_error_code

执行完这两条指令,内存分布是:

然后就跳转到了no_error_code

它主要分成三大部分

  1. 保护现场
  2. 执行中断处理程序
  3. 恢复现场和返回原程序

下面是保护现场的部分

# 保护现场xchgl %eax,(%esp) # eax的值入栈,eax保存中断处理程序地址pushl %ebxpushl %ecxpushl %edxpushl %edipushl %esipushl %ebppush %ds       # 占4字节而非2字节push %espush %fspushl $0     # "error code" 中断有无错误码,是有相关规定的lea 44(%esp),%edxpushl %edx

然后是执行中断处理程序的部分,会有数据段选择符是设定,先暂时不管,这个其实就是类似于8086设置ds的值。

 # 设置内核数据段选择符,设置好数据寻址的基址movl $0x10,%edxmov %dx,%dsmov %dx,%esmov %dx,%fscall *%eax    # 执行中断处理程序,C语言函数do_debug

紧接着是恢复现场和返回原程序

# 恢复现场addl $8,%esppop %fspop %espop %dspopl %ebppopl %esipopl %edipopl %edxpopl %ecxpopl %ebxpopl %eaxiret # 返回中断处理之前的程序,继续执行后续指令

这里需要补充

iret的作用

中断门或陷阱门中断服务例程的返回,按照之前入栈的相反顺序将EIP、CS先后出栈;再将EFLAGS标志寄存器出栈,恢复现场(IRET指令)。

简而言之,就是把最开始保存断点的部分依次出栈,从而回到源程序。

我们看一下这个过程的内存分布

其中

  • esp0对应push $0
  • esp1对应pushl %edx
  • esp2对应addl $8,%esp
  • esp3对应popl %eax

还有一个比较值得关心的

call指令执行前后,寄存器的变化

这一点,使用C语言分析一下函数调用,看看前后变化,在学堂在线《Linux内核分析》中科大孟宁老师MOOC讲解很清晰。


后面的内些的无处错码的函数,与上面的例子完全一样

_debug:pushl $_do_int3       # _do_debugjmp no_error_code_nmi:pushl $_do_nmijmp no_error_code_int3:pushl $_do_int3jmp no_error_code_overflow:pushl $_do_overflowjmp no_error_code_bounds:pushl $_do_boundsjmp no_error_code_invalid_op:pushl $_do_invalid_opjmp no_error_code_coprocessor_segment_overrun:pushl $_do_coprocessor_segment_overrunjmp no_error_code_reserved:pushl $_do_reservedjmp no_error_code_irq13:pushl %eaxxorb %al,%aloutb %al,$0xF0movb $0x20,%aloutb %al,$0x20jmp 1f
1:  jmp 1f
1:  outb %al,$0xA0popl %eaxjmp _coprocessor_error

这些都一样,其中比较特别的是,Linux0.11实现了几个用户自定义中断_irq13就是int45

2.2.1 其他细节的说明

这里保存中断号0,以及保存最开始的堆栈地址esp的值,似乎没啥用,以后再说吧。

这里比较奇怪的是,除法零中断,它的错误码是0,使用的是无处错码的处理程序,如果错误码在之前就被压入栈的话,iret指令执行之前,指向的应该是error code 0,而不是eip,除非这个除法零中断的处理比较特殊,不将出错码压栈,与其他无处错码的中断等同对待,才比较合理。以后再看看这个细节,暂时先放放。

3 有出错码中断

结构与无处错码中断基本一致,这里简要说明一下区别。

首先,硬件处理有区别,压栈之后,会把出错码压栈。


然后,在保存现场的处理上,有一些不同。

_double_fault:pushl $_do_double_fault
error_code:xchgl %eax,4(%esp)       # error code <-> %eaxxchgl %ebx,(%esp)        # &function <-> %ebxpushl %ecxpushl %edxpushl %edipushl %esipushl %ebppush %dspush %espush %fspushl %eax          # error codelea 44(%esp),%eax       # offsetpushl %eaxmovl $0x10,%eaxmov %ax,%dsmov %ax,%esmov %ax,%fscall *%ebxaddl $8,%esppop %fspop %espop %dspopl %ebppopl %esipopl %edipopl %edxpopl %ecxpopl %ebxpopl %eaxiret

看最开始的指令

上图是将中断处理函数压栈之后。

然后执行

xchgl %eax,4(%esp)       # error code <-> %eax
xchgl %ebx,(%esp)       # &function <-> %ebx

分别将

  1. eax与栈内的error code交换,eax入栈
  2. ebx保存中断处理函数地址,ebx入栈

然后,在压入错误码的时候,压入的是pushl %eax # error code,这个时候error code就是动态的了,取决于之前硬件压入的错误码是多少,所以,之前的除法零是静态的0,极大概率可能不压入错误码,当成固定机制处理,也可能与兼容性有关。

然后就是调用中断处理函数的时候,执行call *%ebx,因为这次是ebx存放函数地址。

其他的就没有差别了,需要注意的是,error code最开始就被替换下来了,在后面才压栈。

错误码压栈的作用

好吧,看起来错误码压栈之后,好像根本没有使用就略过了啊,肯定不会的,我们看看手册。

某种类型的异常也导致错误码压栈。异常处理器也能够使用错误码帮助检测异常。

这一点说明了

  1. 错误码的功能:帮助检查异常
  2. 某些有错误码的异常会压栈,不是所有的都会把错误码压栈,比如除法零错误,很可能就不压栈

Linux 0.11 内核解析:中断相关(1)asm.s文件中断处理分析相关推荐

  1. Linux 0.11内核分析02:系统启动

    目录 1. 内核镜像的构建 1.1 内核源码结构 1.1.1 boot 1.1.2 fs 1.1.3 include 1.1.4 init 1.1.5 kernel 1.1.6 lib 1.1.7 m ...

  2. Linux 0.11内核分析04:多进程视图

    目录 1 进程概念的引入 1.1 使用CPU的直观想法 1.2 直观用法的缺点 1.3 直观用法的改进 1.4 进程的概念 1.4.1 保存程序执行状态 1.4.2 进程与PCB 1.5 Linux ...

  3. Linux 0.11内核分析01:概述

    目录 1. 什么是操作系统 1.1 计算机硬件组成 1.2 操作系统基本结构 2. 操作系统核心视图 2.1 多进程视图 2.1.1 操作系统的相关演变 2.1.2 核心思想 2.2 文件视图 2.2 ...

  4. Linux 0.11内核分析03:系统调用

    目录 1 概述 1.1 什么是系统调用 1.2 为什么需要系统调用 2 系统调用基础设施 2.1 安装系统门 2.1.1 中断描述符 2.1.2 中断描述符安装函数 2.1.3 安装0x80系统门 2 ...

  5. linux 0.11 内核学习 -- bootsect.s, 万里长征第一步

    呵呵,终于将linux 0.11 下面的boot文件夹下的三个文件读完,下面是相关注释,没有汇编基础的人也是可以读的.废话少说,下面就是linux的源码了. 参考资料 Linux内核完全注释.pdf ...

  6. Eclipse CDT+Qemu调试Linux 0.11内核

    操作系统:CentOS 6.3 for 32bit 需要软件:eclipse-cpp-galileo-SR2-linux-gtk.tar.gz qemu 需要内核文件:linux 0.11(Makef ...

  7. LINUX 0.11内核完全剖析学习笔记-第三章内核编程语言和环境

    一.编译器 linux 0.11 集成了两种汇编器.一种是能产生16位代码的as86汇编器,使用配套的ld86链接器:另一种是GUN汇编器gas,使用GNU ld链接器俩链接产生的目标文件. 1.1 ...

  8. linux 0.11 内核学习路线

    转载至 http://tieba.baidu.com/p/4871637101 当初一开始拿到赵炯的书时是兴奋的,代码几乎每行都有注释,心想这不手到擒来的吗.但是代码看到十几行就看不下去了,没错就是十 ...

  9. linux 0.11 内核学习 -- console.c,控制台

    参考<linux内核完全注释>和网上相关文章 /* * 控制台显示操作 */ /* *  linux/kernel/console.c * *  (C) 1991  Linus Torva ...

最新文章

  1. shell命令之(一) 初探grep
  2. 网络地址和广播地址的作用
  3. android 自定义天气特效,《Android自定义控件》WindMillView,仿华为天气风车效果
  4. (寒假开黑gym)2017-2018 ACM-ICPC German Collegiate Programming Contest (GCPC 2017)
  5. 第二百九十、一、二天 how can I 坚持
  6. 机器学习-分类之支持向量机(SVM)原理及实战
  7. 想要挑战成功的hongjin2
  8. linux shell切割脚本,自动分割日志bash shell脚本
  9. 几个有趣的Javascript Hack
  10. vue的v-html使用
  11. SQL Server实例的十大安全注意事项
  12. Valgrind 使用简单说明-转
  13. matlab实现图片类型的转换
  14. 将当前登录用户去重显示。
  15. latex参考文献编译不成功
  16. Meta 将使用微软 Azure 最新虚拟机 (VM) 系列,多达 5400 个 GPU
  17. 【基金申报】研究目标、内容、方案之间的区别,一文全了解
  18. 唐诗页面爬取 --- 预研阶段
  19. 使用Cplex求解均值方差模型
  20. hud 1560 DNA sequence(IDA* 迭代加深搜索+估值函数)

热门文章

  1. 数据库建表练习(10.11作业)
  2. asp.net+mvc+easyui+sqlite 简单用户系统学习之旅(二)—— easyui的简单实用
  3. (转)会议期刊论文发表介绍(计算机科学领域)
  4. Android Activity类讲解(一)
  5. cocos2dx blender 骨骼动画实现
  6. (ios7) 解决代码布局View, ios7 中 subView 高度增加StatusBar20dp的问题,保证Ios6,ios7代码一致...
  7. 宝元系统u盘使用说明_教你如何使用U盘安装电脑系统
  8. 联想小新air14笔记本黑屏_联想小新air14锐龙版测评,谈谈它的好和坏
  9. python importlib_importlib --- import 的实现 — Python 3.10.0a2 文档
  10. 不属于个人计算机范围的是,计算机应用基础模拟试卷2