内核是操作系统中最为关键的部分。内核是负责接触底层的,因此大部分都是用C语言写的,有的甚至用汇编。IOS的核心是XNU内核,先从一些内核基本知识谈起。
目录
- 内核基础
- 硬件
- 任务
- 并发
- 安全
- 内核架构
- 巨内核
- 微内核
- 混合内核
- XNU
- 用户态与内核态
- 用户态与内核态转换机制
- 系统调用处理
内核基础
4个角度来说明内核的作用及必要性。
硬件
所有现代操作系统都包含内核组件,内核向开发者提供各种服务。如果没有内核,我们编写开发程序就会陷入编写硬件接口和操作环境的泥潭,做饭还需要自己种水稻,钻木取火,那多麻烦啊。好了,现在我们拥有了内核,一些底层的东西我们不需要关心,我们只要使用内核API就能达成我们的目的。
任务
现代操作系统都是抢占式的多任务,允许多个任务并发执行。因此内核要满足任务的调度要求,能够判断任务运行在哪一个处理器上。
并发
如果有多任务,就要考虑并发问题,内核得知道哪些设备能够同时访问,哪些不能同时访问,需要提供某些措施来防止并发问题。
安全
内核还得提供安全服务,保证系统中各种资源的完整性、隐私性。任何敏感操作都是需要内核的安全审核来确保该操作的合法性。
内核架构
内核架构分为三种:巨内核、微内核、混合内核。后面单独说XNU内核。
1.巨内核
巨内核顾名思义,就是包含所有的服务,上至内存管理,下至设备驱动,应有尽有。这是一种很流行的架构,Linux与UNIX都是采用这种架构。这种方式的内核功能实现都在同一个地址空间,同时将这段地址空间映射到每一个进程的内存中。例如在Linux中,32位操作系统可寻址的(可使用)内存空间为4GB,其中1/4都是内核。Linux程序的实例在体现为进程,每一个程序都会映射成一个或者多个进程。而每一个进程中,都有一份内核内存的拷贝。我们从用户层面切换到内核层面的开销就会十分小,也就是一次线程切换的开销。
2.微内核
微内核把巨内核精简,只包括最核心的功能(硬件访问、调度、虚拟内存管理)。既然微内核存在,那么必有可取之处。相比巨内核,微内核有如下优点:
- 正确性(代码少)
- 健壮性(崩溃少)
- 灵活性
虽然它有这么多优点,那为什么现在基本没有操作系统的内核架构选用微内核呢?这主要是因为它有一个致命的性能缺点。微内核的服务程序之间通信采用消息传递机制(发送-排队-执行),而在内核中,消息传递需要通过内存复制操作以及数次上下文切换操作来实现,这对性能是一种拖累。
3.混合内核
混合内核试图包含前两种内核好处。混合内核的核心部分支持底层服务,就像微内核一样,而其他服务虽然不在该核心的“微内核”中,但是也包含在该核心中,其他服务可以调用该核心的“微内核”。混合内核相比于其他内核架构,牺牲了微内核的健壮性换来巨内核一样的运行效率。
4.XNU内核
如图所示XNU内核是一个混合内核,它的核心是一个叫Mach的微内核,Mach中也是消息传递机制,但是它使用的是指针形式传递,因为大部分服务都在XNU内核中,所以Mach没有昂贵的复制操作,只用指针就可以完成消息传递。
用户态与内核态
内核控制着操作系统最核心的部分,为了防止应用程序崩溃而导致的内核崩溃,内核与应用程序之间需要进行严格的分离。基于软件的分离会产生巨大的开销,因此现代的操作系统都是依靠硬件来分离。分离的结果就是用户态与内核态。
与电脑的inter处理器不一样,iphone手机上的处理器为ARM处理器。在ARM处理器中,提供了一个特殊的寄存器--当前程序状态寄存器(CPSR),通过修改CPSR来改变ARM的模式。下表是ARM处理器模式:
模式 | 用途 |
---|---|
USR | 用户模式 |
SVC | 内核模式 |
SYS | 系统模式 |
FIQ | 快速中断请求 |
IRQ | 普通中断请求 |
ABT | 中止模式 |
UND | 未定义模式 |
上述一共有7种模式,除了第一种用户模式以外,其余6种都可以通过修改CPSR来切换模式。
内核态/用户态转换机制
用户态转换成内核态转换机制有两种类型:
- 自愿转换:当应用程序需要调用内核服务的时候,应用程序可以通过一个预定义的硬件指令开始进入内核态的切换,换句话说这就是系统调用。
- 非自愿转换:当发生执行异常的时候,代码就会挂起并保留案发现场。控制权被转交给预定义的内核态错误处理程序或者中断服务程序。
在ARM中,任何非用户态都是通过一个异常或者中断进入的。因此系统调用是利用SVC指令通过模拟的中断完成的。当这条指令执行的时候,CPU自动将控制权转交给机器的陷阱向量,在陷阱向量中有一个预定义的内核指令正在等待通常是分之跳转到某个具体处理程序的指令。
系统调用的处理
当用户态的程序需要内核服务的时候,会发出一个系统调用,系统调用将控制权转交给内核。在XNU中,系统调用有四种类别:
- BSD系统调用
- Mach陷阱
- 机器相关调用
- 诊断调用
四种类型的调用都差不多,它们的函数原型接受一个指向状态快照的指针,其中状态快照包含了处理器中所有寄存器的导出值。