一个完整可用的操作系统主要由4部分组成:硬件、操作系统内核、操作系统服务和用户应用程序,见图5-1所示。
用户应用程序是指那些字处理程序、Internet浏览器程序或用户自行编制的各种应用程序;操作系统服务程序是指那些向用户提供的服务被看作是操作系统部分功能的程序。
在Liux操作系统上,这些程序包括X窗口系统、shll命令解释系统以及那些内核编程接口等系统程序;操作系统内核程序即是本书所感兴趣的部分,它主要用于对硬件资源的抽象和访问调度。

LINUX 内核模式

在单内核模式的系统中,操作系统所提供服务的流程为:应用主程序使用指定的参数值执行系统调用指令(intx8O),使CPU从用户态(User Mode)切换到核心态(Kernel Model),然后操作系统根据具体的参数值调用特定的系统调用服务程序,而这些服务程序则根据需要再调用底层的一些支持函数以完成特定的功能。在完成了应用程序所要求的服务后,操作系统又使CPU从核心态切换回用户态,从而返回到应用程序中继续执行后面的指令。因此概要地讲,单内核模式的内核也可粗略地分为三个层次:调用服务的主程序层、执行系统调用的服务层和支持系统调用的底层函数。见图5-2所示。

linux c软件架构 linux程序架构_linux


linux c软件架构 linux程序架构_java_02

linux c软件架构 linux程序架构_linux c软件架构_03

LINUX 内核 内存管理

linux c软件架构 linux程序架构_linux c软件架构_04

内存地址空间概念

linux c软件架构 linux程序架构_堆栈_05


linux c软件架构 linux程序架构_堆栈_06

内存分段机制

linux c软件架构 linux程序架构_堆栈_07


==CPU进行地址变换(映射)的主要目的是为了解决虚拟内存空间到物理内存空间的映射问题。==虚拟内存空间的含义是指一种利用二级或外部存储空间,使程序能不受实际物理内存量限制而使用内存的一种方法。通常虚拟内存空间要比实际物理内存量大得多。

linux c软件架构 linux程序架构_堆栈_08


linux c软件架构 linux程序架构_java_09


linux c软件架构 linux程序架构_java_10


linux c软件架构 linux程序架构_网络_11

内存分页管理

==内存分页管理机制的基本原理是将CPU整个线性内存区域划分成4096字节为1页的内存页面。==程序申请使用内存时,系统就以内存页为单位进行分配。内存分页机制的实现方式与分段机制很相似,但并不如分段机制那么完善。因为分页机制是在分段机制之上实现的,所以其结果是对系统内存具有非常灵活的控制权,并且在分段机制的内存保护上更增加了分页保护机制。为了在80X86保护模式下使用分页机制,需要把控制寄存器CR0的最高比特位(位31)置位。

linux c软件架构 linux程序架构_堆栈_12

CPU多任务和保护方式

linux c软件架构 linux程序架构_网络_13


linux c软件架构 linux程序架构_linux_14

虚拟地址-线性地址-物理地址

linux c软件架构 linux程序架构_linux_15

用户申请内存动态分配

linux c软件架构 linux程序架构_linux c软件架构_16


linux c软件架构 linux程序架构_堆栈_17

LINUX系统中断机制

中断基本原理

linux c软件架构 linux程序架构_linux c软件架构_18

8259A

linux c软件架构 linux程序架构_linux c软件架构_19

中断向量表

linux c软件架构 linux程序架构_网络_20

中断处理

linux c软件架构 linux程序架构_linux_21


linux c软件架构 linux程序架构_java_22

系统调用

系统调用(通常称为syscalls)是Linux内核与上层应用程序进行交互通信的唯一接口,参见图5-4所示。从对中断机制的说明可知,用户程序通过直接或间接(通过库函数)调用中断int 0x80,并在eax寄存器中指定系统调用功能号,即可使用内核资源,包括系统硬件资源。不过通常应用程序都是使用具有标准接口定义的C函数库中的函数间接地使用内核的系统调用,

linux c软件架构 linux程序架构_linux c软件架构_23

系统调用传参方式

关于Liux用户进程向系统中断调用过程传递参数方面,Linux系统使用了通用寄存器传递方法,
例如寄存器ebx、ecx和edx。==这种使用寄存器传递参数方法的一个明显优点就是:当进入系统中断服务程序而保存寄存器值时,这些传递参数的寄存器也被自动地放在了内核态堆栈上,因此用不着再专门对传递参数的寄存器进行特殊处理。==这种方法是Lius当时所知的最简单最快速的参数传递方法。另外还有一种使用Intel CPU提供的系统调用门(System Call gate)的参数传递方法,它在进程用户态堆栈和内核态堆栈自动复制传递的参数。但这种方法使用起来步骤比较复杂。
另外,在每个系统调用处理函数中应该对传递的参数进行验证,以保证所有参数都合法有效。尤其是用户提供的指针,应该进行严格地审查。以保证指针所指的内存区域范围有效,并且具有相应的读写权限。

系统时间与定时

为了让操作系统能自动地准确提供当前时间和日期信息,PC/AT微机系统中提供了用电池供电的实时钟RT(Real Time)电路支持。通常这部分电路与保存系统信息的少量CMOS RAM集成在一个芯片上,因此这部分电路被称为RT/CMOS RAM电路。PC/AT微机或其兼容机中使用了Motorola公司的MC146818芯片。

系统定时

linux c软件架构 linux程序架构_网络_24

进程控制

linux c软件架构 linux程序架构_linux_25

任务数据结构

linux c软件架构 linux程序架构_网络_26

linux c软件架构 linux程序架构_linux c软件架构_27


linux c软件架构 linux程序架构_linux_28

运行状态

linux c软件架构 linux程序架构_java_29


linux c软件架构 linux程序架构_linux_30


当一个进程的运行时间片用完,系统就会使用调度程序强制切换到其他的进程去执行。另外,如果进程在内核态执行时需要等待系统的某个资源,此时该进程就会调用sleep_on()或interruptible_sleep_on()自愿地放弃CPU的使用权,而让调度程序去执行其他进程。进程则进入睡眠状态(TASK UNINTERRUPTIBLE TASK INTERRUPTIBLE)

创建新进程

linux c软件架构 linux程序架构_网络_31

进程调度

内核中的调度程序用于选择系统中下一个要运行的进程。这种选择运行机制是多任务操作系统的基础。调度程序可以看作为在所有处于运行状态的进程之间分配CPU运行时间的管理代码。由前面描述可知,Liux进程是抢占式的,但被抢占的进程仍然处于TASK RUNNING状态,只是暂时没有被CPU运行。进程的抢占发生在进程处于用户态执行阶段,在内核态执行时是不能被抢占的。为了能让进程有效地使用系统资源,又能使进程有较快的响应时间,就需要对进程的切换调度采用一定的调度策略。在Liux0.11中采用了基于优先级排队的调度策略。

调度程序

linux c软件架构 linux程序架构_网络_32

进程切换

linux c软件架构 linux程序架构_java_33


linux c软件架构 linux程序架构_linux c软件架构_34

进程终止

linux c软件架构 linux程序架构_网络_35

堆栈使用

Liuⅸ0.11系统中共使用了四种堆栈。

  • 一种是系统引导初始化时临时使用的堆栈:
  • 一种是进入保护模式之后提供内核程序初始化使用的堆栈,位于内核代码地址空间固定位置处。该堆栈也是后来任务0使用的用户态堆栈:
  • 另一种是每个任务通过系统调用,执行内核程序时使用的堆栈,我们称之为任务的内核态堆栈。每个任务都有自己独立的内核态堆栈;
  • 最后一种是任务在用户态执行的堆栈,位于任务(进程)逻辑地址空间近末端处。
    ==使用多个栈或在不同情况下使用不同栈的主要原因有两个。==首先是由于从实模式进入保护模式,使得CPU对内存寻址访问方式发生了变化,因此需要重新调整设置栈区域。另外,为了解决不同CPU特权级共享使用堆栈带来的保护问题,执行0级的内核代码和执行3级的用户代码需要使用不同的栈。当一个任务进入内核态运行时,就会使用其TSS段中给出的特权级0的堆栈指针tss.ss0、tss.esp0,即内核栈。原用户栈指针会被保存在内核栈中。而当从内核态返回用户态时,就会恢复使用用户态的堆栈。下面分别对它们进行说明。
初始化阶段

linux c软件架构 linux程序架构_linux c软件架构_36

任务堆栈
用户态

linux c软件架构 linux程序架构_linux c软件架构_37

内核态

linux c软件架构 linux程序架构_linux c软件架构_38


linux c软件架构 linux程序架构_网络_39

内核态与用户态堆栈切换

linux c软件架构 linux程序架构_网络_40