现代操作系统都是采用虚拟存储器,对32位操作系统而言,它的虚拟地址空间为4G(2的32次方)。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操作系统将虚拟空间划分为两部分:内核空间和用户空间。
Linux操作系统的体系架构分为用户态和内核态(用户空间和内核空间),这种分层的架构极大地提高了资源管理的可扩展性和灵活性,而且方便用户对资源的调用和集中式的管理,带来一定的安全性。Linux中,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。
内核是操作系统的核心,本质上是一种软件—控制计算机的硬件资源,并提供上层应用程序运行的环境,有权访问受保护的内存空间和底层硬件设备。
虚拟地址空间有关知识戳这里:https://blog.csdn.net/IT_10/article/details/89818738
用户态即上层应用程序的活动空间,应用程序的执行必须依托于内核提供的资源,包括CPU资源、存储资源、I/O资源等。为了使上层应用能够访问到这些资源,内核必须为上层应用提供访问的接口:即系统调用。
系统调用是操作系统的最小功能单位,可以看成不能再简化的操作,各种版本的Unix实现都提供了不同数量的系统调用。一个应用程序的完成,必须用到很多系统调用,库函数实现了对系统调用的封装,提供给程序员接口,从而使程序员不必关系底层复杂的实现细节。
用户态的应用程序可以通过三种方式来访问内核态的资源:系统调用、库函数、Shell脚本。
用户态和内核态的切换
运行于用户态的进程可以执行的操作和访问的资源都会受到极大的限制,而运行在内核态的进程则可以执行任何操作并且在资源的使用上没有限制。因此,运行于用户态的进程需要访问具有内核权限才能访问的资源时,就会从用户态切换到内核态,如最常用的printf(),调用的是wirte()系统调用最终输出数据。
一般地,从用户态切换到内核态,有以下三种情况:
1.权限不够(进程主动触发):处于用户态的程序需要访问具有内核权限才能访问的资源
2.异常事件(被动):当CPU正在执行运行在用户态的程序时,突然发生某些预先不可知的异常事件,这个时候就会触发从当前用户态执行的进程转向内核态执行相关的异常事件,典型的如缺页异常。
3.外围设备的中断(被动):当外围设备完成用户的请求操作后,会向CPU发出中断信号,此时,CPU就会暂停执行下一条即将要执行的指令,转而去执行中断信号对应的处理程序,如果先前执行的指令是在用户态下,则自然就发生从用户态到内核态的转换。
参考:https://www.cnblogs.com/bakari/p/5520860.html