1、Linux操作系统体系结构

(1)操作系统可以分为两个层次:内核空间和用户空间。内核和用户空间使用不同的保护地址空间,内核不能将用户空间传递的地址进行直接的操作,需要先转换;
(2)系统调用:内核空间管理设备资源,应用程序通过内核提供的内核调用接口来申请资源;
(3)频繁的系统调用会影响操作系统性能,于是标准C库(glibc)对内核的系统调用进行了封装,glibc最终也是通过系统调用访问内核,但是增加了缓冲区,可以减少
系统调用的次数;

2、内核体系结构

体系结构和总体架构的区别 体系结构和系统结构_系统调用

(1)系统调用接口(SCI):提供某些机制实现用户空间到内核空间的函数调用;这些接口是依赖于体系结构的,在kernel目录中可以找到SCI的实现,并在arch目录中找到依赖于体系结构的部分;
(2)进程管理:程序在操作系统中是以进程/线程为单位运行的,内核要负责进程/线程的调度、进程/线程间通信和同步;
(3)内存管理:内存是很重要的资源,程序都要在内存中运行。内存按照内存页的方式进行管理,内核要负责数据再内存中的换进/换出,内存的分配和释放,以及物理地址和虚拟地址的映射;
(4)虚拟文件系统(VFS):
<1>文件系统有多种格式(ext2、ext3、fat等),是用来管理存储设备的。在存储设备中,存储的数据都是二进制的数,有了文件系统,当我们去访问存储设备的数据时,就可以按照文件名和文件路径的方式去访问;
<2>虚拟文件系统是文件系统的抽象层,虽然底层有各种文件系统,但是这些差异对上层来说是被屏蔽掉的。你在用open、write函数时,并不关心是何种文件系统;
<3>将内核中一些重要的数据结构抽象成文件,这样程序员就可以像读写文件一样去方便的修改和读取内核的数据;
(5)网络协议栈:网络协议栈在设计上采用分层的思想,从上到下分为:系统调用接口层、协议无关接口层(socker层)、网络协议层、设备无关层、设备驱动层;
补充:上面介绍的是通用的,CPU体系结构、设备驱动是和硬件驱动和具体硬件有依赖关系;

3、内核目录结构

体系结构和总体架构的区别 体系结构和系统结构_linux_02

参考博客:《Linux内核的目录结构》;

4、内核配置与编译体系

4.1、交叉编译配置

//默认配置
ARCH	?= arm
CROSS_COMPILE	?= /opt/CodeSourcery/Sourcery_G++_Lite/bin/arm-none-linux-gnueabi-

//交叉编译工具链
AS		= $(CROSS_COMPILE)as
LD		= $(CROSS_COMPILE)ld
CC		= $(CROSS_COMPILE)gcc
CPP		= $(CC) -E
AR		= $(CROSS_COMPILE)ar
NM		= $(CROSS_COMPILE)nm
STRIP		= $(CROSS_COMPILE)strip
OBJCOPY		= $(CROSS_COMPILE)objcopy
OBJDUMP		= $(CROSS_COMPILE)objdump

(1)ARCH:指明CPU的架构,就是此次编译的内核要在何种结构的CPU上运行;
(2)CROSS_COMPILE:指定交叉编译工具链,前提是当前的环境中已经安装了对应的交叉编译工具链;
参考博客:《交叉编译工具链的安装以及介绍》;

4.2、加载默认配置

(1)内核是高度可配置的,在编译前要先配置,也就是在顶层目录生成.config文件,.config文件是由/arch/xxx/configs/xxx拷贝而来;
(2)make ARCH=arm x210ii_qt_defconfig:这个操作效果等同于将缸ch/arm/configs 目录下的x210ii_qt_defconfig文件复制为顶层目录的 .config;

4.3、调整默认配置

(1)内核的配置项是很多的,于是内核开发者提供了界面化的配置选项,在顶层Makefile中支持"make menuconfig"进入配置界面,在此界面可以针对单个配置进行调整,也就是修改.config文件;

4.4、编译内核

root@ubuntu:~/dai_zhi_xin/kernel/jiuding_kernel/kernel# make zImage           
  CHK     include/linux/version.h
  CHK     include/generated/utsrelease.h
make[1]: `include/generated/mach-types.h' is up to date.
  CALL    scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  Kernel: arch/arm/boot/Image is ready
  SHIPPED arch/arm/boot/compressed/lib1funcs.S
  AS      arch/arm/boot/compressed/lib1funcs.o
  LD      arch/arm/boot/compressed/vmlinux
  OBJCOPY arch/arm/boot/zImage
  Kernel: arch/arm/boot/zImage is ready
root@ubuntu:~/dai_zhi_xin/kernel/jiuding_kernel/kernel#

(1)编译内核的前提是先配置内核,必须先生成对应的.config文件;
(2)生成的内核在arch/xxx/boot/目录下;
(3)make zImage:生成zImage;
(4)make uImage:生成uImage;
(5)make bzImage:生成bzImage;
(6)make modules:编译模块,也就是ko文件;

4.5、内核配置体系

(1)首先在命令行通过命令载入默认配置文件,在顶层目录生成.config文件;
(2)通过"make menuconfig"命令进入界面化配置,这里对配置文件进行微调;
(3)参考博客:《Linux内核配置——menuconfig》、《Linux内核配置——Kconfig文件》、
《Linux内核配置和编译原理 & menuconfig、Makefile、.config三者之间的关系》;

4.6、内核的Makefile

4.6.1、目标定义

比如:
	obj-$(CONFIG_RTC_ORV_S3C) += rtc-s3c.o

(1)当配置文件中CONFIG_RTC_ORV_S3C=y时,则将rtc_s3c.c文件编译进内核;
(2)当配置文件中CONFIG_RTC_ORV_S3C=n时,则不编译rtc_s3c.c文件;
(3)当配置文件中CONFIG_RTC_ORV_S3C=m时,则将rtc_s3c.c文件单独编译成ko文件;

4.6.2、多文件模块定义

//构造的模块名字是module.ko
obj-m	+= module.o	
module-objs :=file1.o file2.o	#模块依赖file1.o和file2.o两个源文件

(1)要生成的模块名字时module,将来生成模块就是module.ko;
(2)要生成module.ko依赖file1.c和file2.c这两个文件;

4.6.3、目录层次迭代

obj-$(CONFIG_EXT3_FS) += ext3

当 CONFIG_EXT3_FS 的值为 y 或 m 时,内核构建系统会将 ext3 目录列入向下迭代的目标中,具体 ext3 目录下的文件是要作为模块编译,还是链入内核,由 ext3目录下的 Makefile 决定 。

4.7、在内核中添加代码

(1)编写的源代码复制到Linux 内核源代码的相应目录;
(2)目录的 Kconfig 文件中增加新源代码对应项目的编译配置选项;
(3)在目录的 Makefile 文件中增加对新源代码的编译条目;
补充:如果不知道怎么修改Kconfig和Makefile文件,可以参考别人已经添加好的文件时如何修改的;