ARM Linux内核移植

一、内核结构

1.1 Linux系统组成

  • Linux内核主要由五个子系统组成:(1)进程调度、(2)内存管理、(3)虚拟文件系统、(4)网络接口、(5)进程间通信。
    在这里插入图片描述
  • 1、进程调度(SCHED)
  • 进程调度控制进程对CPU的访问,当需要选择下一个进程运行时,进程调度程序选择最值得运行的进程,而在Linux系统中使用的是基于优先级的进程调度散发选择新的进程。
  • 2、内存管理(MM)
  • Linux系统允许多个进程共享主内存区域,它的内存管理支持虚拟内存。内存管理从逻辑上分为硬件无关部分与硬件有关部分,其中硬件无关部分提供过了进程映射和逻辑内存的对换;硬件有关部分为内存管理硬件提供了虚拟接口。
  • 3、虚拟文件系统(Virtual File System,VFS)
  • 虚拟文件隐藏了各种硬件的具体细节,为所有设备提供统一的接口。虚拟文件系统分为逻辑文件系统与设备驱动程序,其中逻辑文件系统指Linux所支持的文件系统;设备驱动程序指为每一种硬件控制器所编写的设备驱动程序。
  • 4、网络接口(NET)
  • 网络接口提供了各种网络标准的存取以及网络硬件的支持系统,网络接口可分为网络协议与网络设备驱动程序,其中网络协议部分负责各种可能的网络传输协议;网络设备驱动程序负责与硬件设备通信。
  • 5、进程间通信(IPC)
  • 进程间通信支持进程之间的各种通信机制,它所有其他子系统的工作基础。当一个进程等待硬件操作完成时,它被挂起来;而当操作完成后,进程恢复执行。
  • 6、Linux系统各个子系统之间的关系
  • Linux系统组成及各子系统之间的关系如下所示:
    在这里插入图片描述
  • (1)进程调度与内存管理的关系:在多通道任务环境下,运行程序必须为他们建立进程,而建立进程的首要任务就是将程序与数据载入内存。
  • (2)进程间通信与内存管理的关系:进程间通信需要内存管理的支持共享内存通信机制,这种机制允许两个进程除了拥有私有空间外,还可以存取共同的内存区域。
  • (3)虚拟文件系统与网络接口之间的关系:虚拟文件系统利用网络接口支持网络文件系统(NFS),也利用内存管理支持RAMDISK设备。
  • (4)内存管理与虚拟文件系统之间的关系:内存管理利用虚拟文件系统支持交换,交换进程(swapd)定时由调度程序调度。当一个进程存取的内存映射被换出后,内存管理向文件系统发出请求,同时挂起正在运行的进程。

1.2 Linux内核代码目录结构

  • Linux 内核源代码目录结构如下表所示:
目录内容
arch包含所有和体系结构相关的核心代码,它下面的每个子目录都代表一种Linux支持的体系结构。比如,i386则表示Intel CPU及与之兼容的体系结构的子目录。在arch目录下,存放的是各个体系结构对Linux 内核进程调度、内存管理、中断等的支持,以及每个具体的SoC 和电路板的板级支持代码。
documentation包含一些对每个目录作用的具体说明的文档
drivers包含系统中所有的设备驱动程序
fs包含Linux支持的文件系统代码
include包含编译内核所需要的大部分头文件
init包含内核的初始化代码
ipc包含黑河进程间的通信代码
kernel包含内核管理的核心代码,包括进程调度、定时器等;而与处理器结构相关的代码存放在arch/*/kernel 目录下
lib包含内核的库代码,但是与处理器结构相关的库代码则存放在arch/*/lib/目录下
mm包含所有的内存管理代码,其中与具体硬件体系结构相关的内存管理代码则存放在arch/*/mm目录下
modules包含已经创建好的可动态加载的模块
net包含核心的网络部分代码,其中每个子目录对应于网络的一方面内容
scripts包含用于配置核心的脚本文件

二、内核启动流程

2.1 vmlinux-arm.lds.in与head-armv.S

  • 想要指导ARM Linux内核启动流程,就需要首先指导它是从哪个函数开始的,我们从arch/arm/vmlinux-arm.lds.in看起:
/* ld script to make ARM Linux kernel
* taken from the i386 version by Russell King
* Written by Martin Mares<mj@atrey.karlin.mff.cuni.cz>
*/
OUTPUT_ARCH(arm)
ENTRY(stext)
SECTIONS
{
	...
}
  • 由以上代码可以看出,内核的入口点是ENTRY(stext)。经查询,ENTRY(stext)存在于文件arch/arm/kernel/head-armv.S中。该文件是用汇编代码完成的,是内核最先执行的一个文件,它的主要功能是检查CPU id、architecture number,并初始化页表、CPU、BBS等操作,进而跳转到start_kernel()函数,具体的流程图如下所示:
    在这里插入图片描述
  • 下面对上图进行简要解释:
  • (1)通过r0寄存器设置为SVC模式,允许中断与快速中断:
mov r0,#F_BIT|I_BIT|MODE_SVC @make sure svc mode.
  • (2)查询处理器的类型:bl_lookup_processor_type
  • 在ARM协处理器中由一个只读寄存器,存放处理器的信息,__lookup_processor_type将返回如下结构:
__arm920_proc_info:
.long 0x41009200 @CPU id
.long 0xff00fff0 @cpu mask
.long 0x00000cle @mmuflags
b __arm920_setup
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
.long cpu_arm920_info
.long arm920_processor_functions
  • 上述代码的第一项是CPU id,将与协处理器中读出的id作比较,其余的都是与处理器相关的信息,供后面的初始化过程使用。
  • (3)跳转到判断体系类型:bl_lookup_architecture_type
  • 查看r1寄存器的architecture number值是否支持。
  • (4)创建临时内核页表,以便设置MMU:bl_create_page_tables
  • 查询了处理器类型与系统内存映像后,就需要进行初始化中的关键步骤:设置MMU,但是在此之前设置一个临时内核页表,映射4M的内存。
  • (5)跳转至__arm920_setup(),初始化CPU:
  • __arm920_setup()函数在arch/arm/mm/proc-arm920.s中,首先关闭i cache与d cache,并清楚write buffer,进而设置页目录地址,设置domain的保护。最后,设置控制寄存器,打开d cache、i cache与MMU。
  • (6)初始化BSS段,全部清零,BSS是全局变量区域。
  • (7)保存系统的相关信息。
  • (8)重新设置堆栈指针,指向init_task的堆栈。
  • (9)通过b SYMBOL_NAME(start_kernel)行跳转到start_kernel()函数。

2.2 start_kernel()函数

  • start_kernel()函数在init/main.c中定义,它调用了一系列初始化函数,以完成内核的设置,start_kernel()中的函数都非常重要,各个函数的名称及作用下表所示:
函数作用
printk(linux_banner)输出Linux版本信息
setup_arch()设置与体系结构相关的环境
parse_options(command_line)分析传入的命令行参数
trap_init()设置系统自陷入口
init_IRQ()初始化系统的中断请求
sched_init()核心进程调度器的初始化
softirq_init()软中断初始化
time_init()时间、定时器初始化
console_init()控制台初始化
init_modules()模块初始化
kmem_cache_init()核心cache初始化
calibrate_delay()延迟校准,获得时钟域CPU主频的延迟
mem_init()内存初始化,设置内存上、下界和页表项初始值
kmem_cache_sizes_init()创建和设置内部及通用cache
pgtable_cache_init()页表cache初始化
fork_init(num_mappedpages)fork初始化
proc_caches_init()proc cache初始化
vfs_caches_init(num_physpages)虚拟文件系统cache初始化
buffer_init块设备读写缓冲区初始化
page_cache_init(num_physpages)创建页cache
signals_init()信号量初始化
proc_root_init()proc文件系统初始化
ipc_init()ipc初始化
check_bugs()检测系统结构漏洞
smp_init()SMP机器其余CPU(除当前引导CPU)初始化
rest_init()启动init或称,创建第一个核心线程,调用init()函数

三、定制Linux内核

  • Linux系统内核管理系统所有的线程、进程、资源与资源分配,与其他操作系统不同的是,Linux操作系统允许用户对内核进行重新设置。为了合理设置内核编译配置选项,从而只编译系统需要的功能的代码,这就是所谓的Linux系统内核定制,它主要包括内核裁剪、配置与编译内核三个方面,定制Linux系统内核通常出于以下四个方面的考虑:
  • (1)定制编译的内核运行速度更快;
  • (2)由于内核部分将不会被交换到虚拟内存中,系统将拥有更多的内存;
  • (3)由于减少了编译不需要的功能,因此页减少了系统的漏洞;
  • (4)可以将某些功能编译为模块,使得系统更加灵活。

3.1 裁剪、配置内核

  • 基于2.x的内核为用户提供了四种基本的内核配置编译器:
  • (1)config:服务于Linux系统内核配置的命令行界面;
  • (2)oldconfig:一个文本模式的界面;
  • (3)menuconfig:一个基于光标控制库的中断导向编辑器,它可以提供文本模式的图形用户界面;
  • (4)xconfig:基于X-Window系统的同行内核设置编辑器。
  • 因此,可以根据需要选择以下四种进行内核配置:
    -(1)基于文本的最传统的配置界面,不推荐使用:
make ARCH=arm CROSS_COMPILE=arm-linux-config
  • (2)如果只想在内核上作小的修改,可以使用以下内核配置指令:
make ARCH=arm CROSS_COMPILE=arm-linux-oldconfig e
  • (3)在字符端情况下,推荐使用以下文本选项的内核配置界面:
make ARCH=arm CROSS_COMPILE=arm-linux=menuconfig
  • (4)在X Window下推荐使用,基于图形窗口模式的内核配置界面:
make ARCH=arm CROSS_COMPILE=arm-linux-xconfig
  • 在编译内核的过程中,最繁杂的任务就是配置工作。在实际配置中,选择配置参数的原则是:(1)将与内核其他部分关系不大且不经常使用的部分功能代码编译为可加载模块,这样作可以缩短内核长度,减小内存开销;(2)不需要的功能就不选择;(3)与内核紧密而且经常使用的功能代码直接编译到内核中。嵌入式开发中常用的选项如下表所示:
选项含义
Code maturity level options代码成熟等级
Loadable module support对模块的支持
System Type系统类型
Processor type and featuresCPU类型及特性
General setup对最普通的一些属性进行设置
Math emulation协处理器仿真
Parallel port support并口支持
Memory Technology Device (MTD)MTD设备支持
Plug and Play Configuration即插即用支持
Block devices块设备支持
Networking options网络选项
Network device support网络设备支持
Ethernet以太网支持
Serial drivers串口驱动支持
File systems文件系统支持
Network File Systems网络文件系统支持
Partition Types分区类型
Kernel hacking内核调试支持
  • 总的来说,所有内核配置都是为了生成Linux目录下的.config文件。在配置过程中,一方面对内核进行裁剪,选取需要的模块,去掉不需要的模块;另一方面,增加一些与内核修改有关的宏定义,以便区分一致内核过程中所作的工作。

3.2 编译内核

  • 剪裁、配置完内核后,编译内核就非常简单了,命令如下所示:
make ARCH=arm CROSS_COMPILE=arm-linux-dep
make ARCH=arm CROSS_COMPILE=arm-linux-zImage
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值