【分析linux启动】
arch/armnommu/vmlinux.lds(由vmlinux-armv.lds.in生成):
OUTPUT_ARCH(arm)
ENTRY(stext)
SECTIONS
{
. = 0x0c008000; //链接地址(由TEXTADDR参数传递来的)。
.init: { /* Init code and data */
_stext= .;
__init_begin= .;
*(.text.init)
__proc_info_begin= .;
*(.proc.info)
……
}
arch/armnommu/kernel/head- armv.s
.section".text.init",#alloc,#execinstr
.type stext, #function
ENTRY(stext)
b 99f /* 0x00 reset vector */
b vector_undefinstr /* 0x04 undefined instruction */
b vector_swi /*0x08 software interrupt */
b vector_prefetch /* 0x0C prefetch abort */
b vector_data /*0x10 data abort */
b vector_addrexcptn /* 0x14 address exception */
b vector_IRQ /*0x18 IRQ */
b vector_FIQ /*0x1C FIQ */
99:
mov r12, r0
……
mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode
msr cpsr_c, r0 @ and all irqs disabled
#ifdefined(CONFIG_CPU_S3C3410) || defined(CONFIG_CPU_S3C4530) || \
defined(CONFIG_CPU_S3C44B0X)
adr r2, LC0
@ Copy data sections to their new home
ldmia r2, {r4-r11,sp}
cmp r9, r11
beq 2f
1: cmp r11, r10
ldrcc r3, [r9], #4
strcc r3, [r11], #4
bcc 1b
@ clear BSS
2: mov r3, #0
3: cmp r7, r8
strcc r3, [r7], #4
bcc 3b
#if defined(CONFIG_CPU_S3C44B0X)
ldr r9, =S3C44B0X_SYSCFG
ldr r3, [r9]
orr r3, r3, #0xe
str r3, [r9] @enablecache and write buffer
ldr r3,S3C44B0X_PROCESSOR_TYPE //0x44B044B0
str r3, [r5]
mov r3, #MACH_TYPE_S3C44B0X
str r3, [r6]
#endif
mov fp, #0
b start_kernel
//经过实践证明汇编程序从这里跳转到start_kernel中,位于 init/main.c中,下面的相关处理程序是在c语言中完成的。
b . //在该处加入该语句内核可以正常启动。
//加在b start_kernel之前则不能启动内核。
#if defined(CONFIG_CPU_S3C44B0X)
S3C44B0X_PROCESSOR_TYPE:
.long 0x44B044B0
#endif
在include/asm-arm/mach-types.h中定义:
#define MACH_TYPE_S3C44B0 178
// u-boot中传递的bd->bi_arch_number参数值要与这个值一致。
LC0:
#if defined(CONFIG_CPU_S3C3410) || defined(CONFIG_CPU_S3C44B0X)
.long 0x07ff0000 @r4
#endif
.long processor_id @ r5
.long __machine_arch_type @r6
.long __bss_start @r7 bss start
.long _end @ r8 bss end
……
.long _end_romfs @r9 data start in ROM (src)
……
.long _edata @ r10 data end in RAM
.long __data_start @r11 data start in RAM (dst)
.long init_task_union+8192 @ sp
……
bl __lookup_processor_type
teq r10, #0 @invalid processor?
moveq r0, #'p' @yes, error 'p'
beq __error
bl __lookup_architecture_type
#if !defined(CONFIG_ARCTURUS)
teq r7, #0 @invalid architecture?
moveq r0, #'a' @yes, error 'a'
beq __error
#endif
#ifndef CONFIG_UCLINUX
bl __create_page_tables
#endif
adr lr, __ret @return address
add pc, r10, #12 @ initialise processor
@(return control reg)
__switch_data: .long __mmap_switched
.long SYMBOL_NAME(compat)
.long SYMBOL_NAME(__bss_start)
.long SYMBOL_NAME(_end)
.long SYMBOL_NAME(processor_id)
.long SYMBOL_NAME(__machine_arch_type)
.long SYMBOL_NAME(cr_alignment)
.long SYMBOL_NAME(init_task_union)+8192
__ret: ldr lr, __switch_data
mov pc, lr
__mmap_switched:
adr r3, __switch_data + 4
ldmia r3, {r2, r4, r5, r6, r7, r8, sp}@ r2 =compat
@ sp = stack pointer
str r12, [r2]
mov fp, #0 @Clear BSS (and zero fp)
1: cmp r4, r5
strcc fp, [r4],#4
bcc 1b
str r9, [r6] @Save processor ID
str r1, [r7] @Save machine type
#ifdef CONFIG_ALIGNMENT_TRAP
orr r0, r0, #2 @...........A.
#endif
bic r2, r0, #2 @Clear 'A' bit
stmia r8, {r0, r2} @ Save control register values
b SYMBOL_NAME(start_kernel) //跳转到init/main.c中
asmlinkage void __init start_kernel(void)
{
……
lock_kernel();
printk(linux_banner);
setup_arch(&command_line);
printk("Kernelcommand line: %s\n", saved_command_line);
parse_options(command_line);
trap_init();
init_IRQ();
sched_init();
softirq_init();
time_init();
console_init();
……
rest_init();
}
static void rest_init(void)
{
kernel_thread(init, NULL, CLONE_FS | CLONE_FILES |CLONE_SIGNAL);
unlock_kernel();
current->need_resched= 1;
cpu_idle();
}
static int init(void* unused)
{
……
if(execute_command)
{
printk("printtest---->>>> execute_command\n");
run_init_process(execute_command);
}
printk("print test---->>>> /sbin/init\n"); //只有改行打印信息被输出
run_init_process("/sbin/init"); //说明只有改行语句被执行
printk("printtest---->>>> /etc/init\n");
run_init_process("/etc/init");
printk("printtest---->>>> /bin/init\n");
run_init_process("/bin/init");
printk("printtest---->>>> /bin/sh\n");
run_init_process("/bin/sh");
panic("Noinit found. Try passing init= option tokernel.");
}
static void run_init_process(char*init_filename)
{
argv_init[0]= init_filename; //此时的argv_init[0]=/sbin/init”的
if(argv_init[1])
{
printk("run_init_process---->>>> argv_init[1] = 1\n");
printk("%s.\n", argv_init[1]);
}
else
{
printk("run_init_process---->>>> argv_init[1] = 0\n"); //该信息被打印
strcpy(argv_init[1], "/etc/rc"); // argv_init[1]这个参数没有用上,更改后不影响。
}
execve(init_filename,argv_init, envp_init);
}
static void __init parse_options(char*line) //line= command_line
{
……
if(!strncmp(line,"init=",5)) {//在解析没有空格的字符串中有”init=”字符串时,将init=后字符串赋值给execute_command,如:”init=/bin/sh”。
line+= 5;
execute_command = line;
args= 0;
continue;
}
……
if(*line)
argv_init[++args] = line;
……
argv_init[args+1]= NULL;
envp_init[envs+1]= NULL;
}