《Linux内核设计与实现》补充Linux操作系统知识系列(二)之系统调用

2021/04/12 Operating_System 共 1382 字,约 4 分钟

本篇将会介绍Linux用户进程通过内核和底层硬件交互的方式——系统调用

与内核通信

内核线程与用户线程

  • 我们都知道Linux系统中将内核划分出了两个部分,一个是内核空间,一个是用户空间;在内核空间中运行的就是内核线程,用户空间运行的就是用户线程
  • intel核心将指令的等级划分为4个等级,分别是ring0,ring1,ring2,ring3。其中linux操作系统只是用了ring0和ring3,并且内核线程拥有的权限是ring0,最高等级。用户拥有的权限是ring3

权限划分的意义

  • 在linux系统中,将用户权限和内核权限分开是有意义的,这样可以防止用户线程在计算机内为所欲为

与硬件交互的中间层

  • 在用户空间中,用户进程想要对底层硬件读写是有一个中间层来负责的,这个中间层提供各种方法的接口,这样用户进程就可以不用理会底层硬件的形式而正确的访问底层

API、POSIX、C库

  • 实际上,很多用户进程访问底层硬件的时候并不是直接使用的系统调用,因为不同的操作系统,其提供的系统调用也不同,为了解决这个问题,人们提供了一套统一的编程接口来给予用户进程使用,这些接口并不一定是和系统调用一一对应的,有些接口可能调用了数个系统调用

image

  • 在Unix系统中,最流行的编程接口是POSIX标准的接口,在绝大多数的Unix系统中都有一套POSIX接口,这些接口往往对应着操作系统的某些系统调用

系统调用基础知识

系统调用号

  • 在操作系统的世界里,每一个系统调用都被赋予了一个系统调用号,如果进程想要调用系统调用的话,那么是通过系统调用号来指定系统调用的,用户进程不会提及系统调用的名称。这些系统调用号都会被存入一个叫做系统调用表的结构中去,方便获取
  • 系统调用相当的重要,一个被分配了的系统调用号一旦被废弃,这个系统调用号是无法被回收的,因为如果重新分配系统调用号的话会让已经编译好的程序崩溃

系统调用的性能

  • 当发起系统调用的时候会发生非常多的事情,包括上下文切换,现场保护等等,所以按照道理来说效率应该是很低的,但是值得庆幸的是,Linux的系统调用实现的非常优雅,效率较之其他操作系统的系统调用也非常的优秀

系统调用的处理程序

发起系统调用的流程

  • 我们都知道,用户空间的权限较之内核空间的权限非常的低,用户空间的非常多操作都是其自身没有权限实现的,为了解决达到用户进程的目的,用户进程就必须要通知内核自己想要调用的函数,让内核线程来帮自己调用
  • 系统调用是通过中断处理来实现的,用户进程通过发起一个软中断让内核来处理这个异常。此时的异常处理程序其实就是系统调用的处理程序。在X86的系统中这个软中断的编号其实是128号,也就是int $0X80 指令来发起中断,这条指令会出发异常并且让内核来执行第128号异常处理程序,这个异常处理程序其实就是系统调用处理程序,这个异常处理程序的名字很有意思,就叫做sys_call()

指定恰当的系统调用

  • Linux中有非常多的系统调用,那么如何让操作系统知道使用哪一个系统调用呢?这里采用的是指定系统调用号的方式
  • 用户进程会在寄存器 eax 中放置一个值,这个值就是用户进程想要调用的系统调用号。我们知道,调用函数往往少不了参数,那么如何向内核传输参数呢?其实也非常简单,就是在寄存器中依次放入参数,这些寄存器按顺序分别是ebx、ecx、edx、esi、edi,通过这样的方式就可以向系统调用传入参数了

文档信息

Search

    Table of Contents