Linux系统调用之一——概述导论

看了不少的书籍和博客都有讲系统调用,也很简单,即内核提供了用户进程和内核交互的一组接口;做过Linux开发的人应该也清楚系统调用的流程:应用->陷入内核、系统调用->驱动->硬件;然后也有不少人讲到0x80的中断。
但系统调用的讲解有些片面,原理并不清晰,细节更是一笔带过,看了并不能让人耳目一新,大都新瓶旧酒,比如0x80中断是怎么创建,又是怎么识别的等,后面会介绍。所以,我想分享一些自己的学习,以及自己的理解。不足之处还望评论区批评指正。
Linux系统调用之一——概述导论_第1张图片
为了清晰说明,打算用图来说明,然后分别对每部分进行介绍。

1 Linux开机概述

不是说系统调用吗,怎么讲Linux开机呢?
我是想从和系统调用相关的部分,侧面去介绍下,另外标题也有说是导论,简单介绍,并不会太深入,另外博主也不是很熟悉。跟着图示,按照我的思路往下看,并有相关解释,保证有所收获。

  • 电脑组成几个部分:内存、CPU、io设备(磁盘、网卡等)等
  • 开机流程: 依次加载BIOS、MBR及引导程序,最后根据引导城区,从磁盘中将内核加载到内存中,并接管CPU。

我们来看这下几部分功能作用和储存位置,其中:

  • BIOS—基本输出输入系统(Basic Input Output System),功能:负责系统硬件各种参数设定;存放位置:BIOS芯片,实际上是一块ROM。详细参考 :BIOS到底是什么
  • MBR—主引导记录(Master Boot Record)功能 :记录了启动引导程序和磁盘的分区表;存储位置:硬盘的 0 磁道。参考:主引导目录(MBR)结构及作用详解
  • 引导程序—加载操作系统的内核
    以上都三部分都都是按顺序加载,并未和磁盘交互(虽然引导程序储存再0磁道)
  • kernel—引导程序引导加载的操作系统
    直到kernel(操作系统,也是一段程序,实际上也是一个进程)加载,接管了CPU。

之后根据用户需要,开启JVM(java虚拟机,也是一段程序,一个进程。(当然用户空间也可以起其他进程,这里只是举例)

至此Linux开机完成。

2内存地址管理

为什么又讲到了内存地址管理呢?
我们都知道在Linux中,操作系统和驱动程序运行在内核空间,应用程序运行在用户空间。
就像Linux很少像windows一样发生蓝屏(宕机),这里内存地址的管理是其中很重要的因素之一。在Linux kernel接管CPU之后,就开启了CPU 保护模式,即将CPU权限分为ring0-ring3(Linux中内核ring0,用户空间ring3),将内存段的限制信息放在一个叫做全局描述符表(GDT),由此将内存分开,也就是我们常说的,用户空间和内核空间。为了保证用户空间不会影响到内核空间,用户指令也就无法直接访问内核空间。

我们都知道硬件设备通过各类管脚和CPU连接,然后通过硬中断(一般也称为中断)信号,和进行CPU交互。此时普通用户进程怎么办呢?如何与CPU交互?怎么通过读取磁盘文件呢?这能难得倒人类?

如果用户空间指令要访问内核空间就需要通过态的切换和系统调用,也就是常说的陷入内核的方式进行访问,也就是软中断的一种。

比如此时我们的JVM要读取磁盘文件,就可以通过这种方式。

其实,这里出现了一个矛盾:段机制使得内核处于保护模式下,用户空间读取指令无法访问用户空间,但是可以通过软中断的方式进行间接访问磁盘。

那JVM是如何读取磁盘文件的呢?肯定有人觉得我在卖弄,谁不知道,通过0x80中断实现的呢!确实图上也有说明,但是为什么会在这里触发该中断呢?

是因为在代码编译时,编译器发现当有访问内核的代码时,加入0x80软中断,当运行到这里时,将陷入内核,访问驱动读写接口,完成指令。这一点估计很多人都不知道,大家都是知道0x80软中断触发系统调用。在这里编译器起到关键作用。(有兴趣编译下看看,提示因为需要系统调用,调用内核接口,最好使用makefile,编译出汇编)

所以这也就是我要在这里说这个的原因了。
另外,这里提到了一些专业名词:
保护模式,相对实模式而言,可参考:CPU的实模式和保护模式)
关于内核空间用户空间介绍,可参看:内核空间和用户空间简介

3系统调用

到这里才进入这篇博客正题,什么时系统调用?我的理解如下:
计算机,即软件工程学。内核管理硬件,通过对进程提供方法调用程序,不需要重复造轮子,即硬件的使用方法被内核封装,也就是说在程序开发时,不需要自己实现,只需要调用内核即可内核将硬件描述成文件,并提供接口给进程调用。

实际上开始只是介绍了,为什么要系统调用,Linux又是怎么实现系统调用。

  • 1、由于CPU的保护模式,进程是不能访问内核的,它不能直接访问内核所占内存空间也不能调用内核函数。
  • 2、为了和用户空间上运行的进程进行交互,内核提供了一组接口。透过该接口,应用程序可以访问硬件设备和其他操作系统资源。系统调用都是通过软件中断实现的,x86系统上的软件中断由int $0x80指令产生,在程序编译是由编译器实现该中断。

我们已经知道Linux下的系统调用是通过0x80实现的,但是我们知道操作系统会有多个系统调用(Linux下有300多个系统调用), 而对于 同一个中断号是如何处理多个不同的系统调用的? 最简单的方式是对于不同的系统调用采用不同的中断号,但是中断号明显是一种稀缺资源,Linux显然不会这么做;还有一个问题就是 系统调用是需要提供参数,并且具有返回值的,这些参数又是怎么传递的? 实际上我们应该都看过系统调用的函数,Linux系统通过下面两点来实现:

  • 1、函数名称转换。
  • 2、调用的参数传递。

看了一些博客,一般大而全,让初学者看的有点艰涩,可能望而却步,我想通过自己的理解写一些让初学者一目了然的博客,这篇概述就暂时到这,后续将继续介绍——系统调用。

深入学习请移步:Linux系统调用之二——调用机制

你可能感兴趣的:(C,内核,linux,内核,操作系统)