【OS】原来应用是这样访问到底层(系统调用)
1、聊一聊
2、OS对硬件的隐蔽
为什么今天介绍系统调用呢?目前大家都在学习研究linux,在学习过程中面对这么大一个操作系统,给大家最大的疑惑就是应用程序是如何把信息传递到底层然后驱动硬件的,也算是对系统的一个整体的把握吧。所以,作者结合之前自己的学习经验只要理解什么叫系统调用就能解开大部分的疑惑了。
大家平时使用的window系统就知道,只要是window应用程序都可以在装有windows系统的不同CPU上运行。有些玩MCU小伙伴又该有疑问了,RTOS不能在任何MCU上运行,需要移植,只能说对于两种OS差距不是一个数量级。OS为用户非常隐蔽的管理好了底层硬件,对于linux而言其抽象出来就是一句话:"一切皆文件",那么下面我们打开用户到OS的第一道门---系统调用。
3、什么是系统调用
系统调用简单一点说就是应用程序访问内核的一套接口,不过我们一般会首先访问库函数,如下图所示:
解析一下:
从作者看来其实linux系统内部大量采用着面向对象的软件设计方法,大家可以把应用程序和OS内核(Kernal)分别看成两个对象,应用程序通过系统调用通知内核提供相应服务,同时内核也会对消息进行检查处理,从而保证系统的安全。
应用程序大部分都是调用的库函数也可以认为就是API接口,像windowsAPI可就多了,对于linux也不例外,比如常用的Open/Read/Write、printf等等,然而这些库函数内部大部分都是由一个或者多个系统调用构成的,如果仅仅只是数值计算的库函数那就不需要调用系统调用了。
进程是不能直接访问kernal的内存或者调用其函数的,这样保证了系统的安全性,同时只需要提供同一套系统调用便可以运行相同应用程序,所以这和单片机中的RTOS还是有很大的区别,RTOS的任务可以访问OS中的几乎任意位置,不过由于单片机的资源有限,这样可以节省更多的中断时间。
3、系统调用过程分析
大家玩过RTOS都知道我们在平时进行任务切换大部分都会通过触发软件中断来进行任务的调度,其实系统调用跟软件中断是非常类似的,只是说系统调用通过触发中断由用户态切换到了内核态。
解析一下:
作者这里简单描述一下该过程:1)应用调用库函数;2)库函数中调用系统调用接口;3)系统调用触发软件中断;4)进入内核态通过判断系统调用号,在系统调用表中找到对应的服务函数入口地址,然后执行对应的系统调用服务函数(不同的调用号对应着不同功能的服务函数).
从用户态切换到内核态为了不破坏之前的应用程序运行需要保存中断现场,同时在中断服务函数结束以后需要恢复现场,这个跟RTOS中的调度过程是一致的。
4、系统调用参数传递
为了确保安全访问,用户态和内核态分别有各自的堆栈,当触发软件中断以后内核态不能直接使用用户态堆栈,也不能直接使用内核态堆栈,因为内核态堆栈并没有用户态传递的数据,那么系统调用如何传递参数的呢?
解析一下:
参数的传递主要是通过寄存器来完成,在用户态依次把所要传递的参数存入寄存器中,同时也包括系统调用号等。
当进入内核态以后把各个寄存器压入内核态堆栈,那么系统调用服务函数便可以根据约定找到对应的参数使用,对于多于寄存器个数的参数可以通过使用寄存器作为地址来进行处理。
5、最后小结
大家应该对应用程序如果通过操作系统到设备底层应该有一个宏观的概念了吧,同时大家也可以自定义系统调用来实现自己需求。
好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地。同时非常感谢各位小伙伴的支持,我们下期精彩见!
推荐好文 点击蓝色字体即可跳转