我们已知u-boot的终极目的是启动内核,那么内核启动的开始必定是u-boot传入的参数。
打开Armlinux.c 发现有一行的代码为:
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);//带入三个参数
第一个参数是0,第二个参数是机器ID,第三个参数是参数所存放的地址。
内核启动时要做的几个步骤
1.处理u-boot传入的参数 //arch/arm/kernel/head.S
ENTRY(stext)
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ 确立cpu是处于svc模式。
@ and irqs disabled
mrc p15, 0, r9, c0, c0 @ get processor id //将c0寄存器的数值传送到r9寄存器中,获取cpu的id
bl __lookup_processor_type @ r5=procinfo r9=cpuid //判断cpu类型,内核支持的cpu是固定的
movs r10, r5 @ invalid processor (r5=0)?
beq __error_p @ yes, error 'p'
bl __lookup_machine_type @ r5=machinfo//判断单板的类型 如果不能支持 就跳到error里死循环,这里就处理u-boot传入的arch_number
movs r8, r5 @ invalid machine (r5=0)?
beq __error_a @ yes, error 'a'
bl __create_page_tables @创建页表
a.判断是否支持这个cpu
b.判断内核是否支持该单板,分析u-boot启动内核时传入的机器ID
3: .long .
.long __arch_info_begin
.long __arch_info_end
__lookup_machine_type:
adr r3, 3b @r3 = 3b的 address address of r3 = "3: .long" real address
ldmia r3, {r4, r5, r6} @r4 = "." virtual address of 3b,r5="__arch_info_begin" r6 = "__arch_info_end"
/* __arch_info_begin = .;
*(.arch.info.init)
__arch_info_end = .;*/
sub r3, r3, r4 @ get offset between virt&phys r3 = r3 - r4
add r5, r5, r3 @ convert virt addresses to //r5 = r5 + r3
add r6, r6, r3 @ physical address space//r6 = r3 + r6
1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
teq r3, r1 @ matches loader number
beq 2f @ found
add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
cmp r5, r6
blo 1b
mov r5, #0 @ unknown machine
2: mov pc, lr
在这里 出现了.arch.info.init 我们搜索下 发现在arch.h处有定义
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \ //这个结构体特殊的地方就是这个结构体被强制的设置一个属性(把他的段设置为.arch.info.init);
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
MACHINE_START(S3C2440, "SMDK2440")
/* Maintainer: Ben Dooks <ben@fluff.org> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100, //0x30000100,存储u-boot传进的参数
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END
#define MACHINE_START(_type,_name) \
//由上面两段代码整合后是这样的
static const struct machine_desc __mach_desc_S3C2440 \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_S3C2440, \
.name = SMDK2440,
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
.init_machine = smdk2440_machine_init,
.timer = &s3c24xx_timer,
;
c.创建页表
d.使能mmu
e.跳转到startkernel
//为什么要创建页表呢,我们观察链接文件得地址为(0xc0000000) + 0x00008000; //指定内核地址,但是这地址不对应真实存在的内存,所以需要开启mmu映射地址
/arch/arm/kernel/head.S
start_kernel
setup_arch //解析u-boot传入的启动参数
setup_command_line //解析u-boot传入的启动参数
parse_early_param
do_early_paramt
从_setup_start到_setup_end;调用early函数
unknown_bootoption
obsolete_checksetup
从_setup_start到_setup_end;调用非early函数
rest_init();
kernel_init
prepare_namespace();
mount_root();(挂接根文件系统)
init_post(); //打开/dev/console 执行应用程序run_init_professor
EdisonGao所作,转载需指明出处!!