linux 驱动程式一般工作在核心空间,但也可以工作在使用者空间。下面我们将详细解析,什么是核心空间,什么是使用者空间,以及如何判断他们。
Linux 简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Linux 的虚拟地址空间也为 0~4G 。 Linux 核心将这 4G 位元组的空间分为两部分。将最高的 1G 位元组(从虚拟地址 0xC0000000 到 0xFFFFFFFF),供核心使用,称为 “核心空间” 。而将较低的 3G 位元组(从虚拟地址 0x00000000 到 0xBFFFFFFF),供各个程序使用,称为 “使用者空间)。因为每个程序可以通过系统呼叫进入核心,因此,Linux 核心由系统内的所有程序共享。于是,从具体程序的角度来看,每个程序可以拥有 4G 位元组的虚拟空间。
Linux 使用两级保护机制:0 级供核心使用,3 级供使用者程式使用。从图中可以看出(这里无法表示图),每个程序有各自的私有使用者空间(0~3G),这个空间对系统中的其他程序是不可见的。最高的 1GB 位元组虚拟核心空间则为所有程序以及核心所共享。
核心空间中存放的是核心程式码和资料,而程序的使用者空间中存放的是使用者程式的程式码和资料。不管是核心空间还是使用者空间,它们都处于虚拟空间中。
虽然核心空间占据了每个虚拟空间中的最高 1GB 位元组,但对映到实体内存却总是从最低地址(0x00000000)开始。对核心空间来说,其地址对映是很简单的线性对映,0xC0000000 就是实体地址与线性地址之间的位移量,在 Linux 程式码中就叫做 PAGE_OFFSET 。
核心空间和使用者空间之间如何进行通讯?
核心空间和使用者空间一般通过系统呼叫进行通讯。
如何判断一个驱动是使用者模式驱动还是核心模式驱动? 判断的标准是什么?
使用者空间模式的驱动一般通过系统呼叫来完成对硬体的访问,如通过系统呼叫将驱动的 io 空间对映到使用者空间等。因此,主要的判断依据就是系统呼叫。
核心空间和使用者空间上不同太多了,说不完,比如使用者态的连结串列和核心连结串列不一样;使用者态用 printf,核心态用 printk;使用者态每个应用程式空间是虚拟的,相对独立的,核心态中却不是独立的,所以程式设计要非常小心。等等。
还有使用者态和核心态程式通讯的方法很多,不单单是系统呼叫,实际上系统呼叫是个不好的选择,因为需要系统呼叫号,这个需要统一分配。
可以通过 ioctl 、 sysfs 、 proc 等来完成。
核心态和使用者态
当一个任务(程序)执行系统呼叫而陷入核心程式码中执行时,我们就称程序处于核心执行态(或简称为核心态)。此时处理器处于特权级最高的(0 级)核心程式码中执行。当程序处于核心态时,执行的核心程式码会使用当前程序的核心栈。每个程序都有自己的核心栈。当程序在执行使用者自己的程式码时,则称其处于使用者执行态(使用者态)。即此时处理器在特权级最低的(3 级)使用者程式码中执行。当正在执行使用者程式而突然被中断程式中断时,此时使用者程式也可以象征性地称为处于程序的核心态。因为中断处理程式将使用当前程序的核心栈。这与处于核心态的程序的状态有些类似。
程序上下文和中断上下文
处理器总处于以下状态中的一种:
1 、核心态,执行于程序上下文,核心代表程序执行于核心空间;
2 、核心态,执行于中断上下文,核心代表硬体执行于核心空间;
3 、使用者态,执行于使用者空间。
使用者空间的应用程式,通过系统呼叫,进入核心空间。这个时候使用者空间的程序要传递很多变数、引数的值给核心,核心态执行的时候也要储存使用者程序的一些暂存器值、变数等。所谓的 “程序上下文”,可以看作是使用者程序传递给核心的这些引数以及核心要储存的那一整套的变数和暂存器值和当时的环境等。
硬体通过触发讯号,导致核心呼叫中断处理程式,进入核心空间。这个过程中,硬体的一些变数和引数也要传递给核心,核心通过这些引数进行中断处理。所谓的 “中断上下文”,其实也可以看作就是硬体传递过来的这些引数和核心需要储存的一些其他环境(主要是当前被打断执行的程序环境)。