Linux_Kernel_2.6.36引导内核流程分析

//U-BOOT阶段,使用的开发板6410
U-Boot 1.1.6 (May 13 2011 - 14:10:28) for SMDK6410


****************************************
**    u-boot 1.1.6                    **
**    Updated for TE6410 Board        **
**    Version 1.0 (10-01-15)          **
**    OEM: Forlinx Embedded           **
**    Web: http://www.witech.com.cn   **
****************************************


CPU:     S3C6410 @532MHz
         Fclk = 532MHz, Hclk = 133MHz, Pclk = 66MHz, Serial = CLKUART (SYNC Mode
)
Board:   SMDK6410
DRAM:    128 MB
Flash:   0 kB
NAND:    select s3c_nand_oob_mlc_128
2048 MB
*** Warning - bad CRC or NAND, using default environment


In:      serial
Out:     serial
Err:     serial
Hit any key to stop autoboot:  0


NAND read: device 0 offset 0x100000, size 0x500000
 5242880 bytes read: OK
Boot with zImage


Starting kernel ...
--------------------------------------------------------------------------------------------------------
//解压缩镜像文件zimage文件
--------------------------------------------------------------------------------------------------------
Uncompressing Linux... done, booting the kernel.
--------------------------------------------------------------------------------------------------------
//linux/init/main.c 初始化开始阶段 进行一大堆初始化工作
--------------------------------------------------------------------------------------------------------
Linux version 2.6.36-svn85 (root@monkey-MS-7678) (gcc version 4.3.2 (Sourcery G+ //smp_setup_processor_id()
+ Lite 2008q3-72) ) #499 PREEMPT Wed Jun 1 07:19:51 CST 2011
CPU: ARMv6-compatible processor [410fb766] revision 6 (ARMv7), cr=00c5387f //linux/arch/arm/kernel/setup.c setup_machine()
CPU: VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
Machine: SMDK6410 //linux/arch/arm/kernel/setup.c setup_machine()
Memory policy: ECC disabled, Data cache writeback
CPU S3C6410 (id 0x36410101)
S3C24XX Clocks, Copyright 2004 Simtec Electronics
camera: no parent clock specified
S3C64XX: PLL settings, A=532000000, M=532000000, E=24000000
S3C64XX: HCLK2=266000000, HCLK=133000000, PCLK=66500000
mout_apll: source is fout_apll (1), rate is 532000000
mout_epll: source is epll (1), rate is 24000000
mout_mpll: source is mpll (1), rate is 532000000
mmc_bus: source is mout_epll (0), rate is 24000000
mmc_bus: source is mout_epll (0), rate is 24000000
mmc_bus: source is mout_epll (0), rate is 24000000
usb-bus-host: source is clk_48m (0), rate is 48000000
uclk1: source is dout_mpll (1), rate is 66500000
spi-bus: source is mout_epll (0), rate is 24000000
spi-bus: source is mout_epll (0), rate is 24000000
audio-bus: source is mout_epll (0), rate is 24000000
audio-bus: source is mout_epll (0), rate is 24000000
audio-bus: source is mout_epll (0), rate is 24000000
irda-bus: source is mout_epll (0), rate is 24000000
camera: no parent clock specified
s3c64xx: 10485760 bytes SDRAM reserved for fimc at 0x575f9000
s3c64xx: 8388608 bytes SDRAM reserved for tv at 0x56df9000
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 32512
--------------------------------------------------------------------------------------------------------
//初始化结束工作,开始传递参数给文件系统了,init的最后
//if (execute_command)
//execve(execute_command,argv_init,envp_init);
//execute_command与ppcboot传的命令行参数是有关的哦,就是init=/linuxrc
--------------------------------------------------------------------------------------------------------
Kernel command line: root=/dev/mtdblock2 rootfstype=yaffs2 init=/linuxrc nconsol
e=tty1 console=ttySAC0,115200
--------------------------------------------------------------------------------------------------------
//根目录下的linuxrc脚本,这个脚本会去执行文件系统
//然后文件系统又去执行/etc/init.d/rcS脚本,这个脚本又去执行/usr/etc/rc.local
--------------------------------------------------------------------------------------------------------
之后的阶段是一大堆脚本,文件系统上的工作流程,初始化驱动,配置系统参数等工作
--------------------------------------------------------------------------------------------------------
PID hash table entries: 512 (order: -1, 2048 bytes)
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 128MB = 128MB total
Memory: 102940k/102940k available, 28132k reserved, 0K highmem




FAT: utf8 is not a recommended IO charset for FAT filesystems, filesystem will b
e case sensitive!
s3c-nand: 1 bit(s) error detected, corrected successfully


以下是参考的别人的KERNEL内核启动的资料:

还是从编译链接生成vmlinux的过程来看吧,由一大堆.o文件链接而成,第一个就是

kernel\arch\arm\kernel\head-armv.o ,而且我们还看到了lds链接文件kernel\arch\arm\vmlinux.lds,先把它分析一下ENTRY(stext) //入口点是stext 应该就在head-armv.s中了
SECTIONS
{
. = 0xC0008000; //基址,是内核开始的虚拟地址
.init : { /* Init code and data */
_stext = .;
__init_begin = .;
*(.text.init)
__proc_info_begin = .;
*(.proc.info)
__proc_info_end = .;
__arch_info_begin = .;
*(.arch.info)
__arch_info_end = .;
__tagtable_begin = .;
*(.taglist)
__tagtable_end = .;
*(.data.init)
. = ALIGN(16);
__setup_start = .;
*(.setup.init)
__setup_end = .;
__initcall_start = .;
*(.initcall.init)
__initcall_end = .;
. = ALIGN(4096);
__init_end = .;
}
关于虚拟地址和物理地址的:使用MMU后,系统就会使用虚拟地址,通过MMU来指向实际物理地址而在这里我们的0xC0008000实际物理地址就是0x30008000,具体关于MMU的介绍参考《ARM体系结构与编程》。

到head-armv.s找到程序的入口
.section ".text.init",#alloc,#execinstr
.type stext, #function
ENTRY(stext)
mov r12, r0
mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode
msr cpsr_c, r0 @ and all irqs disabled
bl __lookup_processor_type
teq r10, #0 @ invalid processor?
moveq r0, #'p' @ yes, error 'p'
beq __error
bl __lookup_architecture_type
teq r7, #0 @ invalid architecture?
moveq r0, #'a' @ yes, error 'a'
beq __error
bl __create_page_tables
adr lr, __ret @ return address
add pc, r10, #12 @ initialise processor

来看看上一句跳到哪里去了
去追寻r10的值,是在__lookup_processor_type子函数中赋的
__lookup_processor_type:
adr r5, 2f //r5 标号2的地址 基址是0x30008000
ldmia r5, {r7, r9, r10} //r7=__proc_info_end r9=__proc_info_begin
sub r5, r5, r10 //r10 标号2的链接地址 基址是0xc0008000
add r7, r7, r5 @ to our address space
add r10, r9, r5 //r10 变换为基址是0x30008000的__proc_info_begin
2: .long __proc_info_end
.long __proc_info_begin
.long 2b
这样r10中存放的是__proc_info_begin的地址,因为现在我们还没有打开MMU
所以还是需要把基址变换到0x30008000,接着我们就去找__proc_info_begin吧
注意到在上面的vmlinux.lds中有这个标号,下来链接的是.proc.info段,
在kernel\arch\arm\mm\proc-arm920.s的最后找到了这个段
.section ".proc.info", #alloc, #execinstr
.type __arm920_proc_info,#object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.long 0x00000c1e @ mmuflags
b __arm920_setup
ok,这样我们就知道add pc, r10, #12跳到哪里去了,因为这个地址刚好放了条跳转语句
注意了b语句用的都是相对地址,所以不需要变换地址,反正是跳到__arm920_setup,而且
上一条语句是adr lr, __ret,设定了__arm920_setup的返回地址是__ret,所以执行完
__arm920_setup后回到head-armv.s的__ret标号继续执行.
__ret: ldr lr, __switch_data
mcr p15, 0, r0, c1, c0 //注意这里了,在这里打开了MMU
mov r0, r0
mov r0, r0
mov r0, r0
mov pc, lr //跳到__mmap_switched,这里已经用了虚拟地址了吧
// 这条指令ldr lr, __switch_data加载的__mmap_switched地址就是虚拟地址啊
__switch_data: .long __mmap_switched
从__mmap_switched一路执行下来,就要调到C语言代码中去了
b SYMBOL_NAME(start_kernel) //在kernel\init\main.c中
这个程序不是特别复杂,细心看看还是能大概看懂,我也不能去一一注释
这里有一个流程图


到了C语言中就不是很难理解了
lock_kernel();
printk(linux_banner);
setup_arch(&command_line);
printk("Kernel command line: %s\n", saved_command_line);
parse_options(command_line);
trap_init();
init_IRQ();
sched_init();
softirq_init();
time_init();
就是一大堆初始化工作,追着每个函数去看好了

start_kernel最后调用的一个函数
static void rest_init(void)
{
kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
unlock_kernel();
current->need_resched = 1;
cpu_idle();
}
用kernel_thread建立了一个init进程,执行的是main.c中的init函数
lock_kernel();
do_basic_setup();
在do_basic_setup中调用了do_initcalls函数
各种驱动都是在do_initcalls(void)中完成的
static void __init do_initcalls(void)
{
initcall_t *call;
call = &__initcall_start;
do {
(*call)();
call++;
} while (call < &__initcall_end);
flush_scheduled_tasks();
}
__initcall_start也是在vmlinux.lds中赋值的,那就需要找到.initcall.ini这个段
在kernel\include\linux\init.h中可以找到
#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
typedef int (*initcall_t)(void);
#define __initcall(fn) \
static initcall_t __initcall_##fn __init_call = fn
仔细研究下就发现这是把初始化函数的地址放到了.initcall.init段中
这样就可以不断调用驱动的初始化函数了
如果没有定义MODULE,那么#define module_init(x) __initcall(x);
所以如果要把驱动的编译进内核就很简单了吧
init的最后
if (execute_command)
execve(execute_command,argv_init,envp_init);
execute_command与ppcboot传的命令行参数是有关的哦,就是init=/linuxrc
这样就要去执行根目录下的linuxrc脚本,这个脚本会去执行busybox
而busybox又去执行/etc/init.d/rcS脚本,这个脚本又去执行/usr/etc/rc.local

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值