内核态(Kernel Mode)与用户态(User Mode)
内核态: CPU可以访问内存所有数据, 包括外围设备, 例如硬盘, 网卡. CPU也可以将自己从一个程序切换到另一个程序
用户态: 只能受限的访问内存, 且不允许访问外围设备. 占用CPU的能力被剥夺, CPU资源可以被其他程序获取
由于需要限制不同的程序之间的访问能力, 防止他们获取别的程序的内存数据, 或者获取外围设备的数据, 并发送到网络, CPU划分出两个权限等级 -- 用户态 和 内核态
所有用户程序都是运行在用户态的, 但是有时候程序确实需要做一些内核态的事情, 例如从硬盘读取数据, 或者从键盘获取输入等. 而唯一可以做这些事情的就是操作系统, 所以此时程序就需要先操作系统请求以程序的名义来执行这些操作.
这时需要一个这样的机制: 用户态程序切换到内核态, 但是不能控制在内核态中执行的指令
这种机制叫系统调用, 在CPU中的实现称之为陷阱指令(Trap Instruction)
他们的工作流程如下:
内核态和用户态区别
当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态。因为中断处理程序将使用当前进程的内核栈。这与处于内核态的进程的状态有些类似。
1、用系统调用时进入核心态。Linux对硬件的操作只能在核心态,这可以通过写驱动程序来控制。在用户态操作硬件会造成core dump.
2、要注意区分系统调用和一般的函数。系统调用由内核提供,如read()、write()、open()等。而一般的函数由软件包中的函数库提供,如sin()、cos()等。在语法上两者没有区别。
3、一般情况:系统调用运行在核心态,函数运行在用户态。但也有一些函数在内部使用了系统调用(如fopen),这样的函数在调用系统调用是进入核心态,其他时候运行在用户态。
大概是 当用户程序调用系统的API时,就产生中断,进入内核态的API,处理完成后,用中断再退出,返回用户态的调用函数。
user api --> interrupt --> kernel api --> interrupt
---------------------------------------------------------------------
简单来讲一个进程由于执行系统调用而开始执行内核代码,我们称该进程处于内核态中. 一个进程执行应用程序自身代码则称该进程处于用户态.
intel x86 架构的 CPU 分为好几个运行级别,从 0--3 , 0 为最高级别, 3 为最低级别
针对不同的级别,有很多的限制,比如说传统的 in ,out 指令,就是端口的输入输出指令,在 0 级下是可以用的,但在 3 级下就不能用,你用就产生陷阱,告诉你出错了,当然限制还有很多了,不只是这一点
操作系统下是利用这个特点,当操作系统自己的代码运行时, CPU 就切成 0 级,当用户的程序运行是就只让它在 3 级运行,这样如果用户的程序想做什么破坏系统的事情的话,也没办法做到
当然,低级别的程序是没法把自己升到高级别的,也就是说 用户程序运行在 3 级,他想把自己变成 0 级自己是做不到的,除非是操作系统帮忙,利用这个特性,操作系统就可以控制所有的程序的运行,确保系统的安全了. 平时把操作系统运行时的级别就叫内核态(因为是操作系统内核运行时的状态),而且普通用户程序运行时的那个级别叫用户态...
当操作系统刚引导时, CPU 处于实模式,这时就相当于是 0 级,于是操作系统就自动得到最高权限,然后切到保护模式时就是 0 级,这时操作系统就占了先机,成为了最高级别的运行者,由于你的程序都是由操作系统来加载的,所以当它把你加载上来后,就把你的运行状态设为 3 级,即最低级,然后才让你运行,所以没办法,你只能在最低级运行了,因为没办法把自己从低级上升到高级, 这就是操作系统在 内核 态可以管理用户程序,杀死用户程序的原因.