linux启动流程arm

linux启动分析(1)---bootloader启动内核过程

void (*startkernel)(int zero, int arch, unsigned int params_addr) = (void(*)(int, int, unsigned int))KERNEL_RAM_BASE; 

其中KERNEL_RAM_BASE为内核在ram中启动的地址,ARCH_NUMBERMachine Type Numberkernel_params_start是参数在ram的偏移地址。

linux启动分析(2)---内核启动地址的确定

其中TEXTADDR就是内核启动的虚拟地址,定义在kernel/arch/arm/Makefile中:
ifeq ($(CONFIG_CPU_32),y)
PROCESSOR    = armv
TEXTADDR     = 0xC0008000
LDSCRIPT     = arch/arm/vmlinux-armv.lds.in
endif

内核编译链接过程是依靠vmlinux.lds文件,以arm为例vmlinux.lds文件位于kernel/arch/arm/vmlinux.lds
但是该文件是由vmlinux-armv.lds.in生成的,根据编译选项的不同源文件还可以是vmlinux-armo.lds.in
vmlinux-armv-xip.lds.in

vmlinux-armv.lds.in文件的内容:

OUTPUT_ARCH(arm)
ENTRY(stext)
SECTIONS
{
    . = TEXTADDR;
    .init : {           /* Init code and data       */
        _stext = .;
        __init_end = .;
    }

一般情况下都在生成vmlinux后,再对内核进行压缩成为zImage,压缩的目录是kernel/arch/arm/boot
下载到flash中的是压缩后的zImage文件,zImage是由压缩后的vmlinux和解压缩程序组成,如下图所示:

linux启动分析(3)---内核解压缩过程

它将调用函数decompress_kernel(),这个函数在文件arch/arm/boot/compressed/misc.c中,
decompress_kernel()
又调用proc_decomp_setup(),arch_decomp_setup()进行设置,
然后使用在打印出信息“Uncompressing Linux...”后,调用gunzip()。将内核放于指定的位置。

linux启动分析(4)---汇编启动

arch/arm/kernel/head.S 

__HEAD
ENTRY(stext)
    setmode    PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
                        @ and irqs disabled
    mrc    p15, 0, r9, c0, c0        @ get processor id
    bl    __lookup_processor_type        @ r5=procinfo r9=cpuid
    movs    r10, r5                @ invalid processor (r5=0)?
 THUMB( it    eq )        @ force fixup-able long branch encoding
    beq    __error_p            @ yes, error 'p'

#ifndef CONFIG_XIP_KERNEL
    adr    r3, 2f
    ldmia    r3, {r4, r8}
    sub    r4, r3, r4            @ (PHYS_OFFSET - PAGE_OFFSET)
    add    r8, r8, r4            @ PHYS_OFFSET
#else
    ldr    r8, =PLAT_PHYS_OFFSET
#endif

    /*
     * r1 = machine no, r2 = atags or dtb,
     * r8 = phys_offset, r9 = cpuid, r10 = procinfo
     */
    bl    __vet_atags
#ifdef CONFIG_SMP_ON_UP
    bl    __fixup_smp
#endif
#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
    bl    __fixup_pv_table
#endif
    bl    __create_page_tables

    /*
     * The following calls CPU specific code in a position independent
     * manner.  See arch/arm/mm/proc-*.S for details.  r10 = base of
     * xxx_proc_info structure selected by __lookup_processor_type
     * above.  On return, the CPU will be ready for the MMU to be
     * turned on, and r0 will hold the CPU control register value.
     */
    ldr    r13, =__mmap_switched        @ address to jump to after
                        @ mmu has been enabled
    adr    lr, BSYM(1f)            @ return (PIC) address
    mov    r8, r4                @ set TTBR1 to swapper_pg_dir
 ARM(    add    pc, r10, #PROCINFO_INITFUNC    )
 THUMB(    add    r12, r10, #PROCINFO_INITFUNC    )
 THUMB(    mov    pc, r12                )
1:    b    __enable_mmu
ENDPROC(stext)

head-common.S

    __INIT
__mmap_switched:
    adr    r3, __mmap_switched_data

    ldmia    r3!, {r4, r5, r6, r7}
    cmp    r4, r5                @ Copy data segment if needed
1:    cmpne    r5, r6
    ldrne    fp, [r4], #4
    strne    fp, [r5], #4
    bne    1b

    mov    fp, #0                @ Clear BSS (and zero fp)
1:    cmp    r6, r7
    strcc    fp, [r6],#4
    bcc    1b

 ARM(    ldmia    r3, {r4, r5, r6, r7, sp})
 THUMB(    ldmia    r3, {r4, r5, r6, r7}    )
 THUMB(    ldr    sp, [r3, #16]        )
    str    r9, [r4]            @ Save processor ID
    str    r1, [r5]            @ Save machine type
    str    r2, [r6]            @ Save atags pointer
    bic    r4, r0, #CR_A            @ Clear 'A' bit
    stmia    r7, {r0, r4}            @ Save control register values
    b    start_kernel
ENDPROC(__mmap_switched)

__lookup_processor_type

__lookup_architecture_type

__create_page_tables

__mmap_switched

b   start_kernel

linux启动分析(5)---C程序入口函数start_kernel

init\main.c

asmlinkage void __init start_kernel(void)
{
       
    printk(KERN_NOTICE "%s", linux_banner);
    
    setup_command_line(command_line);
    
 

    printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
    parse_early_param();
    parse_args("Booting kernel", static_command_line, __start___param,
           __stop___param - __start___param,
           &unknown_bootoption);
   
      
    console_init();
   
    
    fork_init(totalram_pages);
    
 
    rest_init();
}
static noinline void __init_refok rest_init(void)
{
  
    kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
   
    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
    
 
    cpu_idle();
}
static int __init kernel_init(void * unused)
{
     

    /* Open the /dev/console on the rootfs, this should never fail */
    if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
        printk(KERN_WARNING "Warning: unable to open an initial console.\n");

  
 

    init_post();
    return 0;
}

linux启动6 init_post

static noinline int init_post(void)

{

    
  
    if (execute_command) {
        run_init_process(execute_command);
        printk(KERN_WARNING "Failed to execute %s.  Attempting "
                    "defaults...\n", execute_command);
    }
    run_init_process("/sbin/init");
    run_init_process("/etc/init");
    run_init_process("/bin/init");
    run_init_process("/bin/sh");

    panic("No init found.  Try passing init= option to kernel. "
          "See Linux Documentation/init.txt for guidance.");

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值