嵌入式面试真题——Linux内核空间与用户空间

本文以32位系统为例介绍内核空间(kernel space)和用户空间(user space)

    32 位操作系统而言,它的寻址空间(虚拟地址空间,或叫线性地址空间)为4G232

方)。也就是说一个进程的最大地址空间为 4G。操作系统的核心是内核(kernel),它独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证内核的安全,现在的操作系统一般都强制用户进程不能直接操作内核。具体的实现方式基本都是由操作系统将虚拟地址空间划分为两部分,一部分为内核空间,另一部分为用户空间。针对 Linux 操作系统而言,最高的 1G 字节(从虚拟地址 0xC0000000 0xFFFFFFFF)由内核使用,称为内核空间。而较低的 3G 字节(从虚拟地址0x00000000 0xBFFFFFFF)由各个进程使用,称为用户空间。

    对上面这段内容我们可以这样理解:

    每个进程的 4G 地址空间中,最高 1G 都是一样的,即内核空间。只有剩余的 3G 才归进程自己使用。换句话说就是, 最高 1G 的内核空间是被所有进程共享的

    为什么需要区分内核空间与用户空间

 CPU的所有指令中,有些指令是非常危险的,如果错用,将导致系统崩溃,比如清内存、设置时钟等。如果允许所有的程序都可以使用这些指令,那么系统崩溃的概率将大大增加。

    所以,CPU将指令分为特权指令和非特权指令,对于那些危险的指令,只允许操作系统及其相关模块使用,普通应用程序只能使用那些不会造成灾难的指令。比如IntelCPU将特权等级分为4个级别:Ring0~Ring3。其实Linux系统只使用了 Ring0 Ring3两个运行级别(Windows系统也是一样的)。当进程运行在Ring3 级别时被称为运行在用户态,而运行在 Ring0 级别时被称为运行在内核态。

    内核态与用户态

    好了我们现在需要再解释一下什么是内核态、用户态:

    当进程运行在内核空间时就处于内核态,而进程运行在用户空间时则处于用户态 在内核态下,进程运行在内核地址空间中,此时 CPU 可以执行任何指令。运行的代码也不受任何的限制,可以自由地访问任何有效地址,也可以直接进行端口的访问。

    在用户态下,进程运行在用户地址空间中,被执行的代码要受到CPU的诸多检查,它们只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址,且只能对任务状态段(TSS)I/O 许可位图(I/O Permission Bitmap)中规定的可访问端口进行直接访问。

    对于 Linux 来说,通过区分内核空间和用户空间的设计,隔离了操作系统代码(操作系统的代码要比应用程序的代码健壮很多)应用程序代码。即便是单个应用程序出现错误也不会影响到操作系统的稳定性,这样其它的程序还可以正常的运行(Linux 可是个多任务系统啊!)。所以,区分内核空间和用户空间本质上是要提高操作系统的稳定性及可用性

    有几种方法实现用户态切换到内核态:

[1]一种是系统调用,例如用户空间的read(),write(),ioctl()等。linux通过80中断或者汇编指令进入内核态。

        <1>32-bit x86架构:使用 int 0x80 指令

<2>64-bit x86_64架构:使用 syscall 指令

<3>ARM 架构:使用 svc 指令

在陷入系统调用时在离开用户态需要进行以下操作:

1.将调用的参数保存到寄存器中以便传递给内核态,最多6个参数

2.根据调用的方法来获取系统调用号,因为在系统调用程序时需要通过系统调用表(操作系统初始化时确定的)来决定调用具体哪一个方法。将系统调用号通过寄存器传递给内核态

3.触发80中断,此时pc的值指向系统调用中断服务程序的基地址。

[2]另一种就是中断,分为软件中断和硬中断。它会打断正在执行的程序,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序(如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换,因为中断处理程序默认是需要运行在内核态的。)将控制权转移到内核空间的中断处理程序(interrupt handler)。中断可以由设备(如硬件中断)或软件(如系统调用)触发。

    [3]再一种就是异常,当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到内核态的异常处理相关的程序中,也就是转到了内核态,比如缺页异常,除0异常。

    从触发方式上看,可以认为纯在前述3种不同的类型,但是从最终实际完成由用户态到内核态的切换操作上来说,涉及的关键步骤是完全一致的,没有任何区别,都相当于执行了一个中断响应的过程,因为系统调用实际上最终是中断机制实现的,而异常和中断的处理机制基本上也是一致的。

你可能感兴趣的:(嵌入式面试真题,linux,c语言,嵌入式硬件,面试,单片机)