1 创建内核source sight 工程
1.1 点击 “add all” 添加所有文件,后面再慢慢删去Arch目录和Include目录中与2440芯片没用的文件。
1.2 点击Remove Tree 删除Arch文件夹,再添加与2440相关的硬件核心代码以及其它公用的代码
Arch:包含了平台,处理器相关的代码,并包括boot文件夹。
1.2.1 点击Add Tree添加以下子目录:
linux-2.6.22.6/arch/arm/boot (启动配置文件)
linux-2.6.22.6/arch/arm/common (公共文件)
linux-2.6.22.6/arch/arm/configs (配置文件)
linux-2.6.22.6/arch/arm/kernel (内核文件)
linux-2.6.22.6/arch/arm/lib (固件库)
linux-2.6.22.6/arch/arm/mach-s3c2440 (machine 设备,2440设备库)
linux-2.6.22.6/arch/arm/mach-s3c2410 (2440中部分调用了2410设备库)
linux-2.6.22.6/arch/arm/Mm (内存管理文件)
linux-2.6.22.6/arch/arm/nwfpe
linux-2.6.22.6/arch/arm/oprofile (性能分析工具文件)
linux-2.6.22.6/arch/arm/plat-s3c24xx (s3c24系列平台文件)
linux-2.6.22.6/arch/arm/tools (常用工具文件)
linux-2.6.22.6/arch/arm/vfp (浮点运算文件)
1.3 点击Remove Tree 删除Include文件夹,再添加与2440相关的头文件
Include: 包括了核心的大多数include文件,另外对于每种支持的体系结构分别有一个子目录
1.3.1 点击Add All 添加 linux-2.6.22.6/include/asm-arm目录下文件(不包含子目录所有文件),如下图所示:
1.3.2 点击Add Tree添加以下子目录:
linux-2.6.22.6/include/asm-arm/arch-s3c2410 (2410处理器架构)
linux-2.6.22.6/include/asm-arm/hardware (硬件相关头文件)
linux-2.6.22.6/include/asm-arm/mach (具体的设备文件)
linux-2.6.22.6/include/asm-arm/plat-s3c24xx (s3c24系列平台头文件)
1.3.3返回到 linux-2.6.22.6/include目录下,点击Add Tree添加除了asm-xx开头的其它通用文件:
linux-2.6.22.6/include/acpi (高级配置与电源接口文件)
linux-2.6.22.6/include/config
linux-2.6.22.6/include/crypto
linux-2.6.22.6/include/keys
linux-2.6.22.6/include/linux
linux-2.6.22.6/include/math-emu
linux-2.6.22.6/include/mtd
linux-2.6.22.6/include/net
linux-2.6.22.6/include/pcmcia
linux-2.6.22.6/include/rdma
linux-2.6.22.6/include/rxrpc
linux-2.6.22.6/include/scsi
linux-2.6.22.6/include/sound
linux-2.6.22.6/include/video
1.4 最后点击synchronize files 创建source insight工程
2.内核启动之分析uboot传递参数和链接脚本
2.1 内核在uboot启动之前是进入do_boom_linux函数
(do_boom_linux函数启动内核详解:http://www.cnblogs.com/lifexy/p/7310279.html)
do_boom_linux代码如下:
theKernel = (void (*)(int, int, unsigend int))0x30008000;
// 设置theKernel地址=0x30008000,用于后面启动内核
/*设置atag参数*/
setup_start_tag (void); //从0X30000100地址处开始保存start_tag数据,
setup_memory_tags (void); //保存memory_tag数据,让内核知道内存多大 setup_commandline_tag (“boottargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0”);
/*保存命令行bootargs参数,让内核知道根文件系统位置在/dev/mtdblock3,指定开机运行第一个脚本/linuxrc,指定打印串口0*/
setup_end_tag (void); //初始化tag结构体结束
theKernel(0,362,0x300000100); //362:机器ID, 0x300000100: params(atag)参数地址
/*传递参数跳转执行到0x30008000启动内核, */
/*相当于: mov r0,#0 */
/*ldr r1,=362 */
/*ldr r2,= 0x300000100 */
/*mov pc,#0x30008000 */
TAG参数内存布局图如下:
2.2然后来分析链接脚本arm/arm/kernel/vmlinux.lds
OUTPUT_ARCH(arm) //设置输出文件的体系架构
ENTRY(stext) //设置stext全局符号为入口地址
jiffies = jiffies_64;
SECTIONS
{
. = (0xc0000000) + 0x00008000;
/*设置内核虚拟地址=0xc0000000+0x00008000 */
.text.head : {
_stext = .;
_sinittext = .;
*(.text.head) //添加所有.text.head段
}
.init : { /* Init code and data */
*(.init.text)
_einittext = .;
__proc_info_begin = .;
*(.proc.info.init) //存放处理器相关的信息初始化
__proc_info_end = .;
__arch_info_begin = .;
*(.arch.info.init) //存放与架构(arch)相关的信息(info)初始化
__arch_info_end = .;
... ...
从vmlinux.lds中得出linux内核启动第一步是进入stext入口函数。
那么stext入口函数又在哪里定义的呢?
搜索ENTRY(stext)得出,它在arch/arm/kernel/head.S中,
stext函数的在前置条件是:MMU, D-cache, 关闭; r0 = 0, r1 = machine nr, r2 = atags prointer.代码如下:
代码语言:javascript
/*
* Kernel startup entry point. //内核 启动 入口 点
* ---------------------------
*
* This is normally called from the decompressor code. The requirements
* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
/* 前置条件是:MMU, D-cache, 关闭; r0 = 0, r1 =机器ID, r2 =atag参数地址.*/
* r1 = machine nr.
* This code is mostly position independent, so if you link the kernel at
* 0xc0008000, you call this at __pa(0xc0008000).
* See linux/arch/arm/tools/mach-types for the complete list of machine
* numbers for r1.
*
* We're trying to keep crap to a minimum; DO NOT add any machine specific
* crap here - that's what the boot loader (or in extreme, well justified
* circumstances, zImage) is for.
*/
section ".text.head", "ax" /* 定义一个.text.head段,段的属性a是允许段,x可 执行 */
.type stext, %function /*定义了由bootloader进入内核的入口stext */
ENTRY(stext)
... ...
它的功能是获取处理器类型和机器类型信息,并创建临时的页表,然后开启MMU功能(因为内核代码中全是0XCxxxxxxx地址),并跳进第一个C语言函数start_kernel。
所以,内核启动后第一步是 进入arch/arm/kernel/head.S的stext函数中.
3内核启动之stext函数分析(arch/arm/kernel/head.S)
stext函数内容,如下图:
(1) 关闭irq和fiq,设置svc管理模式
(2)判断是或支持这个CPU
(3)判断是否支持这个单板(通过uboot传入的机器ID判断)
(4)创建页表,为后面的MMU做准备
(5) 使能MMU并跳到__switch_data处,复制数据段,清除bss段,设置栈,调用start_kernel第一个C函数
stext函数代码如下:
section ".text.head", "ax" /* 定义一个.text.head段,段的属性a是允许段,x可 执行 */
.type stext, %function /*定义了由bootloader进入内核的入口stext */
ENTRY(stext) //入口地址stext函数
/*msr cpsr_c,0xD3 关闭irq和fiq,设置svc管理模式 */
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
@ and irqs disabled
/*获取cpu ID */
mrc p15, 0, r9, c0, c0 @ get processor id
/*查找内核是否支持r9这个cpuID,若不支持r5=0,支持r5=处理器ID*/
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
/*不支持则跳转到__error_p,死循环*/
beq __error_p @ yes, error 'p'
/*查找内核是否支持uboot传入的r1机器ID(362),若不支持r5=0,支持r5=机器ID*/
bl __lookup_machine_type @ r5=machinfo
movs r8, r5 @ invalid machine (r5=0)?