Linux 0.11源码阅读笔记-中断过程

是什么中断

中断发生时,计算机会停止当前运行的程序,转而执行中断处理程序,然后再返回原被中断的程序继续运行。中断包括硬件中断和软件中断,硬中断是由外设自动产生的,软中断是程序通过int指令主动调用。中断产生时,会有一个中断号,根据中断号可在中断向量表中选择对应的中断处理程序执行。

中断在linux当中非常重要,是用户态代码与和心态代码相互切换运行的桥梁。进程调度依赖于时钟中断进入内核,系统调用也是依赖int 80软中断进入内核执行。

中断处理过程

以int 80中断为例。system_call过程代码是 int 80中断处理程序,是所有系统调用的入口。位于linux-0.11/kernel/system_call.s文件中。

sytem_call执行过程

  1. 保存运行环境:保存被中断程序的运行环境,包括指令地址(PC)、段等寄存器的值。
  2. 执行系统调用:根据系统调用号,查找系统调用函数地址表,并执行系统调用函数
  3. 执行调度程序:判断进程时间片是否处于不可运行状态(时间片用完或者处于阻塞状态),若不可运行,则执行调度程序。
  4. 进行信号处理:若被中断程序为用户态进程,会先判断信号是否产生,并执行相应的信号处理程序。
  5. 恢复运行环境:恢复被中断程序的运行环境。

system_call代码及注释

### int 0x80 - linux系统调用入口点(调用中断int 0x80,eax 中是调用号)
system_call:
cmpl $nr_system_calls-1,%eax # 调用号如果超出范围的话就在eax中置-1并退出
ja bad_sys_call # 保存原段寄存器值
push %ds
push %es
push %fs # edx、ecx、ebx作为系统调用的参数
pushl %edx
pushl %ecx # push %ebx,%ecx,%edx as parameters
pushl %ebx # to the system call # 设置内核段
movl $0x10,%edx # set up ds,es to kernel space
mov %dx,%ds
mov %dx,%es
# fs指向用户程序的数据段。
movl $0x17,%edx # fs points to local data space
mov %dx,%fs # 调用系统调用号对应的系统调用函数
call sys_call_table(,%eax,4) # 间接调用指定功能C函数
pushl %eax # 把系统调用返回值入栈 # 如果进程时间片(counter)用完或者状态(state)非就绪,则执行调度程序
movl current,%eax # 取当前任务(进程)数据结构地址→eax
cmpl $0,state(%eax) # state
jne reschedule
cmpl $0,counter(%eax) # counter
je reschedule # 中断处理程序后半段,返回被中断程序继续执行。
ret_from_sys_call:
# 若被中断程序为0号进程,直接返回。
movl current,%eax # task[0] cannot have signals
cmpl task,%eax
je 3f # 向前(forward)跳转到标号3处退出中断处理 # 若被中断程序运行在内核态(例如其它可被中断中断程序),则直接返回
cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
jne 3f
cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
jne 3f # 若被中断程序为用户进程,则先处理进程的信号
# 通过信号位图,判断产生的信号,然后调用do_signal执行对应的信号处理程序
movl signal(%eax),%ebx # 取信号位图→ebx,每1位代表1种信号,共32个信号
movl blocked(%eax),%ecx # 取阻塞(屏蔽)信号位图→ecx
notl %ecx # 每位取反
andl %ebx,%ecx # 获得许可信号位图
bsfl %ecx,%ecx # 从低位(位0)开始扫描位图,看是否有1的位,若有,则ecx保留该位的偏移值
je 3f # 如果没有信号则向前跳转退出
btrl %ecx,%ebx # 复位该信号(ebx含有原signal位图)
movl %ebx,signal(%eax) # 重新保存signal位图信息→current->signal.
incl %ecx # 将信号调整为从1开始的数(1-32)
pushl %ecx # 信号值入栈作为调用do_signal的参数之一
call do_signal # 调用C函数信号处理程序(kernel/signal.c)
popl %eax # 弹出入栈的信号值 # 返回被中断程序
3: popl %eax # eax中含有上面入栈系统调用的返回值
popl %ebx
popl %ecx
popl %edx
pop %fs
pop %es
pop %ds
iret # 特权级中断返回指令

用户栈与内核栈之间的切换

特权级发生变化时,会涉及到内核栈和用户栈的切换。linux具有两个特权级,内核态(0)和用户态(3)。int指令可以从用户态转入内核态,iret指令可以从内核态返回用户态。

用户栈到内核栈

中断引起CPU特权级从3级到0级的变化,此时CPU会进行用户栈到内核栈的切换操作。

  1. 获取内核栈内存地址信息。CPU从当前任务状态段TSS(PCB)中取得新栈的段选择符和偏移值,内核栈指针从TSS的ss0(选择符)和esp0字段中获得。
  2. 将用户栈地址信息保存在内核栈中。将用户态栈指针和代码地址信息ss、esp、cs、eip压入内核栈中。
  3. 将ss、esp、cs、eip指向内核栈和代码地址。

内核栈到用户栈

iret指令引起CPU特权级从0级到3级的变化,此时CPU会进行内核栈到用户栈的切换操作。

iret指令将先前压入内核栈的用户进程栈和代码地址信息cs、esp、ss、esp信息从栈里弹出,加载到相应的寄存器中,重新执行用户进程。

进程调度的实现机制

每个用户进程有自己的内核栈,进程调度时,将栈寄存器指向需要运行的进程的内核栈,执行iret指令即可继续运行该进程。

内核栈的切换

进程调度的通过内核栈之间的切换,实现进程之间的切换运行。为什么每个进程都需要一个内核栈?进程需要保存运行状态信息(各种寄存器信息),等待被调度程序选中运行。

进程切换

进程切换的实质在于进程状态(上下文)的切换,即将CPU的当前进程状态替换成新进程的状态。被替换进程的进程状态会保存在其对应的tss数据结构中,等待恢复运行。任务寄存器TR会保存当前任务的TSS指针,TSS数据结构总保存进程的运行状态。

具体过程为:

  1. 当前进程通过中断进入内核,用户态ss、esp、cs、ip寄存器信息保存在内核栈中,切换到内核态运行,使用内核堆栈
  2. schedule调度程序时,将当前进程内核态运行信息保存在当前任务的tss数据结构中,然后切换到新进程的内核运行状态,在内核中运行新的进程。
  3. 新运行的进程通过iret指令从内核态转到用户态运行,用户态的运行状态信息在其内核栈中。

参考

  • Linux 内核完全注释 内核版本0.11 - 赵炯

PS:错漏指出,请大佬指正,在评论区可交流学习。

Linux 0.11源码阅读笔记-中断过程的更多相关文章

  1. Linux 0.11源码阅读笔记-文件管理

    Linux 0.11源码阅读笔记-文件管理 文件系统 生磁盘 未安装文件系统的磁盘称之为生磁盘,生磁盘也可以作为文件读写,linux中一切皆文件. 磁盘分区 生磁盘可以被分区,分区中可以安装文件系统, ...

  2. Linux 0.11源码阅读笔记-总览

    Linux 0.11源码阅读笔记-总览 阅读源码的目的 加深对Linux操作系统的了解,了解Linux操作系统基本架构,熟悉进程管理.内存管理等主要模块知识. 通过阅读教复杂的代码,锻炼自己复杂项目代 ...

  3. Linux 0.11源码阅读笔记-总结

    总结 Linux 0.11主要包含文件管理和进程管理两个部分.进程管理包括内存管理.进程管理.进程间通信模块.文件管理包含磁盘文件系统,打开文件内存数据.磁盘文件系统包括空闲磁盘块管理,文件数据块的管 ...

  4. Linux 0.11源码阅读笔记-块设备驱动程序

    块设备驱动程序 块设备驱动程序负责实现对块设备数据的读写功能.内核代码统一使用缓冲块间接和块设备(如磁盘)交换数据,缓冲区数据通过块设备驱动程序和块设备交换数据. 块设备的管理 块设备表 内核通过一张 ...

  5. Linux 0.11源码阅读笔记-内存管理

    内存管理 Linux内核使用段页式内存管理方式. 内存池 物理页:物理空闲内存被划分为固定大小(4k)的页 内存池:所有空闲物理页组成内存池,以页为单位进行分配回收.并通过位图记录了每个物理页是否空闲 ...

  6. Linux 0.11源码阅读笔记-文件IO流程

    文件IO流程 用户进程read.write在高速缓冲块上读写数据,高速缓冲块和块设备交换数据. 什么时机将磁盘块数据读到缓冲块? 什么时机将缓冲块数据刷到磁盘块? 函数调用关系 read/write( ...

  7. Linux 0.11源码阅读笔记-高速缓冲

    高速缓冲 概念 高速缓冲区是内存中的一块内存,在块设备与内核其它程序之间起着一个桥梁作用.内核程序如果需要访问块设备中的数据,都需要经过高速缓冲区来间接的操作. 高速缓冲区结构 高速缓冲区被划分为1k ...

  8. 【从头到脚品读 Linux 0.11 源码】第一回 最开始的两行代码

    从这一篇开始,您就将跟着我一起进入这操作系统的梦幻之旅! 别担心,每一章的内容会非常的少,而且你也不要抱着很大的负担去学习,只需要像读小说一样,跟着我一章一章读下去就好. 话不多说,直奔主题.当你按下 ...

  9. linux 0.11 源码学习+ IO模型

    http://www.cnblogs.com/Fredric-2013/category/696688.html

随机推荐

  1. Java 替换PDF中的字体

    文档中可通过应用不同的字体来呈现不一样的视觉效果,通过字体来实现文档布局.排版等设计需要.应用字体时,可在创建文档时指定字体,也可以用新字体去替换文档中已有的字体.下面,以Java代码展示如何来替换P ...

  2. 『现学现忘』Docker相关概念 — 4、虚拟化概念

    目录 1.虚拟化的概念 2.为什么出现虚拟化 3.虚拟化技术 1.虚拟化的概念 虚拟化是指通过虚拟化技术将计算机虚拟为多台逻辑计算机.在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操 ...

  3. JZ-038-二叉树的深度

    二叉树的深度 题目描述 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 题目链接: 二叉树的深度 代码 /** * 标题:二叉 ...

  4. LeetCode-009-回文数

    回文数 题目描述:给你一个整数 x ,如果 x 是一个回文整数,返回 true :否则,返回 false . 回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数.例如,121 是回文,而 1 ...

  5. C#实现抢红包算法

    二倍均值法(公平版) 发出一个固定金额的红包,由若干个人来抢,需要满足哪些规则? 1.所有人抢到金额之和等于红包金额,不能超过,也不能少于. 2.每个人至少抢到一分钱. 3.要保证所有人抢到金额的几率 ...

  6. Mysql引擎、隔离机制、存储结构、索引

    目录 数据库常用的两种引擎 两种引擎差异对比 如何选择引擎 两个引擎索引结构 查找mysql数据存储位置方式 MyISAM InnoDB 1. 非独立表空间 2. 独立表空间 3. idb文件存的哪些 ...

  7. Mybatias

    Mybatis 1.简介 1.1丶什么是Mybaties MyBatis 是一款优秀的持久层框架, 它支持自定义 SQL.存储过程以及高级映射. MyBatis 免除了几乎所有的 JDBC 代码以及设 ...

  8. 《Shader入门精要》中MVP变换的Projection矩阵与《GAMES101图形学入门》中的区别

    game101的透视投影的投影矩阵是这样的 正交投影是这样的 而shader入门精要的透视投影矩阵是这样子 正交投影矩阵是这样子 game101的透视投影是这样得到的 而正交投影的时候并没有假设中心点 ...

  9. 道路中心线提取、河道中心线的提取(ArcScan)

    道路中心线的提取,相信大家并不陌生. 道路中心线是道路路线几何设计中的重要特征线,也是道路交通管理中的重要控制线. 街区内的道路应考虑消防车道的通行,道路中心线间的距离不宜大于160米. 今儿个,博主 ...

  10. Hadoop之Mapreduce 程序

    package com.gylhaut.hadoop.senior.mapreduce; import java.io.IOException; import java.util.StringToke ...