Linux内核完全注释之Linux内核体系结构(续)

2.6 Linux 内核对内存的使用方法

在Linux 0.11 内核中,为了有效地使用机器中的物理内存,内存被划分成几个功能区域,见下图 2-9 所示。
在这里插入图片描述其中,Linux 内核程序占据在物理内存的开始部分,接下来是用于供硬盘或软盘等块设备使用的高速缓冲区部分。当一个进程需要读取块设备中的数据时,系统会首先将数据读到高速缓冲区中;当有数据需要写到块设备上去时,系统也是先将数据放到高速缓冲区中,然后由块设备驱动程序写到设备上。 后部分是供所有程序可以随时申请使用的主内存区部分。内核程序在使用主内存区时,也同样要首先向内核的内存管理模块提出申请,在申请成功后方能使用。对于含有 RAM 虚拟盘的系统,主内存区头 部还要划去一部分,供虚拟盘存放数据。
在 Linux 0.11 内核中,在进行地址映射时,我们需要首先分清 3 种地址以及它们之间的变换概念:a. 程序(进程)的逻辑地址;b. CPU 的线性地址;c. 实际物理内存地址。
逻辑地址(Logical Address)是指有程序产生的与段相关的偏移地址部分。在 Intel 保护模式下即是指程序执行代码段限长内的偏移地址(假定代码段、数据段完全一样)。应用程序员仅需与逻辑地址打交道,而分段和分页机制对他来说是完全透明的,仅由系统编程人员涉及。
线性地址(Linear Address)是逻辑地址到物理地址变换之间的中间层。程序代码会产生逻辑地址,或者说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。如果启用了分页机制,那么线性地址可以再经变换以产生一个物理地址。若没有启用分页机制,那么线性地址直接就是物理地址。Intel 80386的线性地址空间容量为4G。
物理地址(Physical Address)是指出现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的终结果地址。如果启用了分页机制,那么线性地址会使用页目录和页表中的项变换成物理地址。如果没有启用分页机制,那么线性地址就直接成为物理地址了。
有时我们也把逻辑地址称为虚拟地址。因为与虚拟内存空间的概念类似,逻辑地址也是与实际物理内存容量无关的。
在内存分段系统中,一个程序的逻辑地址是通过分段机制自动地映射(变换)到中间层的线性地址上。每次对内存的引用都是对内存段中内存的引用。当一个程序引用一个内存地址时,通过把相应的段 基址加到程序员看得见的逻辑地址上就形成了一个对应的线性地址。此时若没有启用分页机制,则该线性地址就被送到 CPU 的外部地址总线上,用于直接寻址对应的物理内存。
若采用了分页机制,则此时线性地址只是一个中间结果,还需要使用分页机制进行变换,再终映射到实际物理内存地址上。与分段机制类似,分页机制允许我们重新定向(变换)每次内存引用,以适应我们的特殊要求。使用分页机制普遍的场合是当系统内存实际上被分成很多凌乱的块时,它可以建立一个大而连续的内存空间的映象,好让程序不用操心和管理这些分散的内存块。分页机制增强了分段机制 的性能。页地址变换是建立在段变换基础之上的。任何分页机制的保护措施并不会取代段变换的保护措施而只是进行更进一步的检查操 作。
Intel CPU 使用段(Segment)的概念来对程序进行寻址。每个段定义了内存中的某个区域以及访问 的优先级等信息。而每个程序都可有若干个内存段组成。程序的逻辑地址(或称为虚拟地址)即是用于 寻址这些段和段中具体地址位置。在 Linux 0.11 中,程序逻辑地址到线性地址的变换过程使用了 CPU 的全局段描述符表GDT和局部段描述符表LDT。由 LDT 映射的地址空间称为全局地址空间,由LDT映射的地址空间则称为局部地址空间,而这两者构成了虚拟地址的空间。具体的使用方式见图 2-10 所示。
在这里插入图片描述

2.8 Linux 内核源代码的目录结构

当我们使用 tar 命令将 linux-0.11.tar.gz 解开时,内核源代码文件被放到了 linux/目录中。其中的目录结构见图 2-15 所示:
在这里插入图片描述

2.9 内核系统与用户程序的关系

在 Linux 系统中,内核为应用程序提供了两方面的接口。其一是系统调用接口(在第 5 章中说明), 也即中断调用 int 0x80;另一方面是通过内核库函数(在第 12 章中说明)与内核进行信息交流。内核库 函数是基本C函数库libc的组成部分。许多系统调用是作为基本 C 语言函数库的一部分实现的。系统调用主要是提供给系统软件直接使用或用于库函数的实现。而一般用户开发的程序则是通过调用象libc等库中的函数来访问内核资源。通过调用这些库中的程序,应用程序代码能够完成各种常用工作,例如,打开和关闭对文件或设备的访问、进行科学计算、出错处理以及访问组和用户标识号ID等系统信息。

2.10 linux/Makefile 文件

Makefile 文件相当于程序编译过程中的批处理文件。是工具程序 make 运行时的输入数据文件。只 要在含有 Makefile 的当前目录中键入 make 命令,它就会依据 Makefile 文件中的设置对源程序或目标代 码文件进行编译、连接或进行安装等活动。
make工具程序能自动地确定一个大程序系统中那些程序文件需要被重新编译,并发出命令对这些程 序文件进行编译。在使用make之前,需要编写 Makefile 信息文件,该文件描述了整个程序包中各程序之间的关系,并针对每个需要更新的文件给出具体的控制命令。通常,执行程序是根据其目标文件进行更新的,而这些目标文件则是由编译程序创建的。一旦编写好一个合适的 Makefile 文件,那么在你每次修改过程序系统中的某些源代码文件后,执行 make 命令就能进行所有必要的重新编译工作。
Makefile 文件的主要作用是指示make程序终使用独立编译连接成的 tools/目录中的 build 执 行程序将所有内核编译代码连接和合并成一个可运行的内核映像文件 image。具体是对 boot/中的bootsect.s、setup.s使用8086汇编器进行编译,分别生成各自的执行模块。再对源代码中的其它所有程序 使用 GNU 的编译器 gcc/gas进行编译,并连接成模块 system。再用 build工具将这三块组合成一个内核映象文件image. 基本编译连接/组合结构如图 2-20 所示。
在这里插入图片描述make 的执行过程分为两个不同的阶段。在第一个阶段,它读取所有的 makefile 文件以及包含的 makefile 文件等,记录所有的变量及其值、隐式的或显式的规则,并构造出所有目标对象及其先决条件的一幅全景图。在第二阶段期间,make 就使用这些内部结构来确定哪个目标对象需要被重建,并且使用 相应的规则来操作。
当 make 重新编译程序时,每个修改过的 C 代码文件必须被重新编译。如果一个头文件被修改过了, 那么为了确保正确,每一个包含该头文件的 C 代码程序都将被重新编译。每次编译操作都产生一个与源程序对应的目标文件(object file)。如果任何源代码文件被编译过了,那么所有的目标文件不管是 刚编译完的还是以前就编译好的必须连接在一起以生成新的可执行文件。
简单的 makefile 文件含有一些规则,这些规则具有如下的形式:
在这里插入图片描述其中’目标’对象通常是程序生成的一个文件的名称;例如是一个可执行文件或目标文件。目标也可以 是所要采取活动的名字,比如’清除’(‘clean’)。'先决条件’是一个或多个文件名,是用作产生目标的输入条 件。通常一个目标依赖几个文件。而’命令’是 make 需要执行的操作。一个规则可以有多个命令,每一个命令自成一行。

小结

本章概述了Linux 早期操作系统的内核模式和体系结构。给出了 Linux 0.11 内核源代码的目录结构形式,并详细地介绍了各个子目录中代码文件的基本功能和层次关系。后从 Linux 内核主目录下的 makefile 文件着手,开始对内核源代码进行注释。

猜你喜欢

转载自blog.csdn.net/weixin_43255133/article/details/84133490