Linux Kernel作为一种操作系统有别与一般的用户程序,即所谓的kernel mode和user mode。Kernel mode下运行的程序能够访问所有的memory,能够处理interrupt;而user mode的程序只能访问有限的memory,不能直接处理中断。那么kernel mode和user mode的这些差别是由谁来决定的呢?归根结底,所有的程序都是CPU的指令,同样的指令有的时候能做某件事,有的时候不能,这都是由指令执行时CPU的Mode决定的。简而言之就是说,执行Kernel指令的时候,CPU处于特权模式,可以访问所有Memory;执行user program的指令时,CPU处于user mode,读写memory受限制;而当Interrupt发生时,因为要操作硬件,所以CPU会从原来工作的Mode切换到特权模式来执行Interrupt handler。下面将详细阐述Linux操作系统是怎样在ARM architecture上运转的。
-
ARM的Processor Mode
ARM有以下7种Processor Mode,当前处于的模式有程序状态寄存器Current Program Status Register (CPSR)的bit4:0决定:
-
User: 用户模式User Mode
-
FIQ : 快速中断Fast Interrupt Request
-
IRQ: 普通中断Normal Interrupt Request
-
SVC: 管理模式Supervisor Mode
-
Abort: 异常模式 Abort Mode
-
Undefined: 未定义模式 Undefined Mode
-
System: 系统模式
其中User Mode是一种受限制的模式,其他6种都是特权模式(Privilege Mode)。
这些模式间可以相互切换,切换方法可以归结为以下两种:
第一种:由CPU本身硬件完成切换
CPU本身主动进行模式切换是因为在执行指令的时候发生了某种“意外“,这种”意外“就是Exception。一旦Exception发生,CPU就要立即切换到这种Exception相对应的模式去处理该Exception。所有Exception都在Privilege Mode下处理。ARM CPU共有6种Exception,他们发生的条件和发生后进入的CPU模式如下:
Exception |
触发条件 |
进入CPU模式 |
Reset |
CPU的Reset pin被Assert (CPU Power on时,Reset pin会被Assert) |
SVC |
Undefined Instruction: |
企图执行一条不认识的指令 |
Undefined |
Software Interrupt (SWI) |
执行指令SWI |
SVC |
Prefetch Abort |
获取指令失败 |
Abort |
Data Abort |
获取数据失败 |
Abort |
IRQ |
普通中断发生,CPU的IRQ pin被Assert |
IRQ |
FIQ |
快速中断发生,CPU的FIQ pin被Assert |
FIQ |
请注意Exception和CPU模式中都有IRQ和FIQ,但他们的意义是不同的。前者指一个Exception的事件,后者指一种CPU运行的模式。
第二种:程序修改CPSR
某些指令是可以修改CPSR的,在程序中执行这些指令就能切换CPU的模式。但是这些模式两两之间并不是都可以通过修改CPSR来实现切换的,如User Mode下不可以修改CPSR切换到其他Mode。通常从Exception中返回时要修改CPSR,从而恢复到Exception发生时的CPU Mode继续执行。
-
Linux的Kernel mode和User mode
Linux Kernel工作在Privilege mode下,它需要处理所有在privilege mode下完成的工作。如IRQ,FIQ Exception发生时,进入相应的Privilege Mode,由Kernel来处理相应的IRQ, FIQ事件。也就是说,Kernel 对应CPU的6中Privilege Mode。正是因为privilege mode可以对系统资源“特权“的访问,所以kernel能够控制所有的软硬件资源,因而被称为”操作系统“。
User mode运行在CPU的User processor mode下,所以在访问memory等方面都有限制,用户的各种Application都运行在User Mode下。User Mode下的程序想要访问只有Privilege Mode才能访问的资源就必须使用系统调用(System Call),进入Kernel Mode来处理。从User Mode进入Priviledge mode的唯一方式是swi指令,这条指令执行会触发Software Interrupt Exception, 从而进入SVC模式。所以System call的实质就是通过swi指令进入Kernel Mode。在kernel中处理完毕后,kernel会将CPU切回到User Mode继续执行,同时将调用结果返回到User Mode。
下表说明了CPU Mode与Linux Mode之间的对应关系:
|
User |
FIQ |
IRQ |
Supervisor |
Abort |
Undefined |
System |
Kernel Mode |
|
√ |
√ |
√ |
√ |
√ |
√ |
User Mode |
√ |
|
|
|
|
|
|
-
CPU Mode切换的场合在Linux中的实现
如 前所述,所有CPU privilege模式下的工作都对应于OS的Kernel mode,那么所谓Linux Kernel mode和User mode之间的切换映射到CPU层面来说就是CPU的User mode怎样切换到其他6种mode,每种privilege mode又怎样切换到User mode的。同时,6中Privilege Mode之间当Exception发生时也会切换。下面我们将对照Linux kernel 2.6.33的代码来逐一分析每种Exception发生时Linux Kernel是怎样处理的。
在ARM Architecture中,Exception发生时指令将从固定的地址开始执行。所以必须在这些地址上放置正确的代码来处理相应的Exception。这些固定的地址也称向量,由CP15 Reg1中的V bit控制,可以在虚拟内存的底部或顶部。注意是虚拟内存,也就是说这些向量的固定地址是虚拟地址,是要经过MMU转换的。各Exception对应的向量地址(虚拟地址)如下:
Low Vector |
High Vector |
|
Reset |
0 |
0xFFFF0000 |
Undefined Instruction: |
0x04 |
0xFFFF0004 |
Software Interrupt (SWI) |
0x08 |
0xFFFF0008 |
Prefetch Abort |
0x0C |
0xFFFF000C |
Data Abort |
0x10 |
0xFFFF0010 |
IRQ |
0x18 |
0xFFFF0018 |
FIQ |
0x1C |
0xFFFF001C |
在Linux kernel中向量位于高地址,由CONFIG_VECTORS_BASE控制,Default为0xFFFF0000,在__arm926_setup中将CP15 control register 1的V bit置为1(High Vector)。向量表在源代码里位于entry-armv.S中,从__vector_start开始,在FIQ, IRQ等被enable前,必须要copy到0xFFFF0000开始的高地址。Copy的时点在start_kernel ()->setup_arch()->early_trap_init()中。在setup_arch()之后的local_irq_enable()才是真正clear CPSR的I-bit,至此,IRQ才Enable了。
下面逐一讲述各Exception Handler的实现。
-
Reset
CPU Power on后即触发Reset Exception。Reset发生后,CPU进入SVC Mode, PC被设置为0,即从内存地址0开始执行代码。这是系统启动的开端。对应arm Linux中,arch/arm/kernel/head.S中的“__HEAD"开始即是系统执行的Kernel的第一行代码(2.6.33中是设置CPSR,disable FIQ, IRQ)。用objdump vmlinux也可以看到此行代码是Kernel的第一条指令。详细Linux启动的过程在”Linux Kernel的启动过程“一文中阐述。
在向量表中Reset Exception的向量处是执行swi SYS_ERROR0,这条指令将触发SWI Exception,在vector_swi中通过判断参数,最终将执行到die(),系统停止运行。也就是说,Linux在运行过程中发生Reset Exception,将被认为是系统错误而停止。
-
发生IRQ
IRQ Exception发生时将从__vector_irq开始执行。这部分代码稍显晦涩。源代码中__vector_irq这个符号是由__vector_stub这个宏产生的。__vector_stub这个宏实现了IRQ和Abort Exception的共用部分,主要是保存SPSR,然后根据发生Exception时 的Program Mode跳转到相应的处理分支上。处理分支的table是紧跟在_vector_stub之后,可以看到每一种Program mode下发生IRQ对应于table中的一个entry。SVC下发生IRQ的时候就进入__irq_svc,User Mode下发生IRQ的时候就进入__irq_user。关于__irq_usr和__irq_svc中具体是怎样处理IRQ的,详见“Linux中IRQ的处理“一文。
-
发生Prefetch Abort
与IRQ一样,发生Prefrech Abort时将跳转到__pabt_usr和_pabt_svc的分支上处理。
-
发生Data Abort
相关推荐
arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu 是由 CodeSourcery 公司基于...arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2.7z交叉编译器必须安装在32为主机上,才能编译目标代码。
arm-none-linux-gnueabi-gcc-4.8.3 已验证可用,请放心使用。arm-none-linux-gnueabi-gcc是 Codesourcery ...可用于交叉编译ARM系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
- **缓存一致性**:讲解了Linux内核如何确保缓存在内存中的数据与其在持久存储设备上的副本保持一致。 - **脏页管理**:分析了脏页(已修改但未同步回磁盘的数据页)的管理机制。 - **同步策略**:讨论了不同的数据...
gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf 是由 Linaro 公司基于GCC推出的的ARM交叉编译工具...gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf交叉编译器必须安装在64为主机上,才能编译目标代码。
gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。...gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf交叉编译器必须安装在64为主机上,才能编译目标代码。
gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。...gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf交叉编译器必须安装在64为主机上,才能编译目标代码。
gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.tar是由 Linaro 公司基于GCC推出的的...gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.tar交叉编译器必须安装在64为主机上,才能编译目标代码。
《Professional Linux Kernel Architecture》是一本全面深入地介绍Linux内核架构的专业书籍,由Wolfgang Mauerer编写,Wiley Publishing, Inc.出版。本书不仅适合对Linux内核感兴趣的开发者,也适合希望深入了解操作...
《Linux Kernel Architecture + Understanding Linux Kernel》是一套深入探讨Linux内核和系统编程的资源,适合对操作系统原理感兴趣的读者,特别是那些计划开发Linux设备驱动程序的人。这套资料包含三本书:...
gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf.tar.xz是由 Linaro 公司基于GCC推出的的ARM...gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf.tar.xz交叉编译器必须安装在64为主机上,才能编译目标代码。
Find an introduction to the architecture, concepts and algorithms of the Linux kernel in Professional Linux Kernel Architecture , a guide to the kernel sources and large number of connections among ...
- **书籍介绍**:本书《Professional Linux Kernel Architecture》是一本深入剖析Linux内核架构的专业书籍,由Wolfgang Mauerer撰写,并于2008年由Wiley Publishing Inc.出版。全书共有1368页,涵盖了Linux内核的...
### Linux内核设计与实现——Linux Kernel Development 第三版 #### 书籍简介 《Linux Kernel Development》第三版是一本经典的Linux内核开发指南,由Robert Love编写,Pearson Education出版。该书作为Developer's...
buildroot2020编译的uclibc编译器,cortex-A7,EABIHF,NEON/VFPv4,Thumb2 linux kernel4.19,gcc是9.x,编译环境是ubuntu16.04,也可以兼容ubuntu18.04等环境。
Linux kernel本地权限提升漏洞(CVE-2022-0847)漏洞补丁及相关依赖包1Linux kernel本地权限提升漏洞(CVE-2022-0847)漏洞补丁及相关依赖包1Linux kernel本地权限提升漏洞(CVE-2022-0847)漏洞补丁及相关依赖包1Linux ...
gcc-linaro-arm-linux-gnueabihf-4.8是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译32-bit Armv7 Cortex-A...gcc-linaro-7.4.1-2019.02-i686_arm-linux-gnueabihf交叉编译器建议安装在32位的主机上。
gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf是由 Linaro 公司基于GCC推出的的ARM交叉...gcc-linaro-7.4.1-2019.02-x86_64_arm-linux-gnueabihf.tar.xz交叉编译器必须安装在64为主机上,才能编译目标代码。
《arm-linux-uboot》是针对嵌入式系统开发者的一本实用教程,主要聚焦于U-Boot(统一的bootloader)在ARM架构Linux系统中的移植与应用。这本书以实践为导向,旨在帮助读者深入理解U-Boot的工作原理,并掌握在实际...
《Professional Linux Kernel Architecture》这本书是Linux内核架构的权威指南,深入探讨了Linux操作系统的核心机制。作为一本面向专业IT人员的书籍,它涵盖了从进程管理、内存管理到设备驱动等多方面的内容,对于想...