linux内核启动过程分析

linux内核启动过程分析

1.处理U-boot 传入的参数
在Linux/arch/arm/kernel/head.s中
(1)判断是否支持该CPU(uboot启动时传入的参数bd->bi_arch_number为362)

mrc p15, 0, r9, c0, c0      @ get processor id
bl  __lookup_processor_type     @ r5=procinfo r9=cpuid
/*theKernel (0, bd->bi_arch_number, bd->bi_boot_params);*/

g:\linux-2.6.22.6\arch\arm\kernel\head-common.S下

/*
 * Read processor ID register (CP#15, CR0), and look up in the linker-built
 * supported processor list.  Note that we can't use the absolute addresses
 * for the __proc_info lists since we aren't running with the MMU on
 * (and therefore, we are not in the correct address space).  We have to
 * calculate the offset.
 *
 *  r9 = cpuid
 * Returns:
 *  r3, r4, r6 corrupted
 *  r5 = proc_info pointer in physical address space
 *  r9 = cpuid (preserved)
 */
    .type   __lookup_processor_type, %function
__lookup_processor_type:
    adr r3, 3f  /* R3=3f的地址,为实际地址,物理地址 */
    ldmda   r3, {r5 - r7}   /* ldm为加载多个寄存器,DA 每次传送后地址减四,LDMDA指令,每次传送后地址减4,long 型每次占4个字节。r5=__proc_info_begin ,r6=__proc_info_end ,r7="."代表虚拟地址*/
    sub r3, r3, r7          @ get offset between virt&phys
    add r5, r5, r3          @ convert virt addresses to
    add r6, r6, r3          @ physical address space
1:  ldmia   r5, {r3, r4}            @ value, mask
/* ldm为加载多个寄存器,iA 每次传送后地址加四*/
    and r4, r4, r9          @ mask wanted bits
    teq r3, r4
    beq 2f
    add r5, r5, #PROC_INFO_SZ       @ sizeof(proc_info_list)
    cmp r5, r6
    blo 1b
    mov r5, #0              @ unknown processor
2:  mov pc, lr
/*
 * This provides a C-API version of the above function.
 */
ENTRY(lookup_processor_type)
    stmfd   sp!, {r4 - r7, r9, lr}
    mov r9, r0
    bl  __lookup_processor_type
    mov r0, r5
    ldmfd   sp!, {r4 - r7, r9, pc}

/*
 * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for
 * more information about the __proc_info and __arch_info structures.
 */
    .long   __proc_info_begin
    .long   __proc_info_end
3:  .long   .
    .long   __arch_info_begin
    .long   __arch_info_end

在G:\linux-2.6.22.6\arch\arm\kernel\vmlinux.lds.S中

SECTIONS
{
 .......
    . = PAGE_OFFSET + TEXT_OFFSET;/*TEXT_OFFSET=0x00000800*/
    .....
.init : {           /* Init code and data       */
......  
        __arch_info_begin = .;
            *(.arch.info.init)/*  *表示所有的*/
        __arch_info_end = .;

PAGE_OFFSET 在Linux/include/asm-arm/Memory.c下定义

/*
 * Page offset: 3GB
 */
#ifndef PAGE_OFFSET
#define PAGE_OFFSET     UL(0xc0000000)
#endif

在内核中查找

grep ".arch.info.init" * -nR

在include/asm-arm/mach/arch.h中,

/*
 * Set of macros to define architecture features.  This is built into
 * a table by the linker.
 */
#define MACHINE_START(_type,_name)          \
static const struct machine_desc __mach_desc_##_type    \/*##表示连字符号*/
 __used                         \
 __attribute__((__section__(".arch.info.init"))) = {    \
    .nr     = MACH_TYPE_##_type,        \
    .name       = _name,

#define MACHINE_END             \
};

关于MACHINE_START(_type,_name)的定义在include/configs/100ask24x0.h中

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*/

    .init_irq   = s3c24xx_init_irq,
    .map_io     = smdk2440_map_io,
    .init_machine   = smdk2440_machine_init,
    .timer      = &s3c24xx_timer,
MACHINE_END

两个定义带入

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,
    };

machine_desc 结构体在linux/asm-arm/arch/Arch.h中

struct machine_desc {
    /*
     * Note! The first four elements are used
     * by assembler code in head-armv.S
     */
    unsigned int        nr;     /* architecture number  */
    unsigned int        phys_io;    /* start of physical io */
    unsigned int        io_pg_offst;    /* byte offset for io 
                         * page tabe entry  */

    const char      *name;      /* architecture name    */
    unsigned long       boot_params;    /* tagged list      */

    unsigned int        video_start;    /* start of video RAM   */
    unsigned int        video_end;  /* end of video RAM */

    unsigned int        reserve_lp0 :1; /* never has lp0    */
    unsigned int        reserve_lp1 :1; /* never has lp1    */
    unsigned int        reserve_lp2 :1; /* never has lp2    */
    unsigned int        soft_reboot :1; /* soft reboot      */
    void            (*fixup)(struct machine_desc *,
                     struct tag *, char **,
                     struct meminfo *);
    void            (*map_io)(void);/* IO mapping function  */
    void            (*init_irq)(void);
    struct sys_timer    *timer;     /* system tick timer    */
    void            (*init_machine)(void);
};

(2)判断是否支持该单板

bl  __lookup_machine_type       @ r5=machinfo

(3)创建页表,由于链接地址是虚拟地址,需要创建页表与实际内存进行对应。

bl  __create_page_tables

(4)使能mmu

    adr lr, __enable_mmu        @ return (PIC) address
    add pc, r10, #PROCINFO_INITFUNC

(5)跳转到secondary_start_kernel

b   secondary_start_kernel

函数在Linux/arch/arm/kernel/smp.c

asmlinkage void __cpuinit secondary_start_kernel(void)
{

}

Linux内核启动的第二阶段在
Linux/init/main.C
主要函数

asmlinkage void __init start_kernel(void)
{
printk(linux_banner);
setup_arch(&command_line);
/*解析uboot传入的启动参数*/
setup_command_line(command_line);
/*解析uboot传入的启动参数*/
parse_early_param();
console_init();

.......
    rest_init();
}

在该函数中首先打印内核版本信息,

printk(linux_banner);

设置与体系结构相关的环境

setup_arch(&command_line);
/*解析uboot传入的启动参数*/
setup_command_line(command_line);
/*解析uboot传入的启动参数*/

在arch/arm/kernel/setup.c中

void __init setup_arch(char **cmdline_p)
{
    struct tag *tags = (struct tag *)&init_tags;
    struct machine_desc *mdesc;/*machine_desc 为前面linux/asm-arm/arch/Arch.h中定义的结构体*/
    char *from = default_command_line;

    setup_processor();
    mdesc = setup_machine(machine_arch_type);
    machine_name = mdesc->name;
    /*.name     = "SMDK2440",*/

    if (mdesc->soft_reboot)
        reboot_setup("s");

    if (mdesc->boot_params)
        tags = phys_to_virt(mdesc->boot_params);
/*  .boot_params    = S3C2410_SDRAM_PA + 0x100,=0x30000100,也是uboot启动的最后theKernel (0, bd->bi_arch_number, bd->bi_boot_params);(uboot/lib_arm/Armlinux.c)告诉内核的存放参数的地址gd->bd->bi_boot_params = 0x30000100(uboot/board/100ask24x0.c);*/
parse_early_param();

该函数同样在Linux/init/main.C下

void __init parse_early_param(void)
{
    static __initdata int done = 0;
    static __initdata char tmp_cmdline[COMMAND_LINE_SIZE];

    if (done)
        return;

    /* All fall through to do_early_param. */
    strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE);
    parse_args("early options", tmp_cmdline, NULL, 0, do_early_param);
    done = 1;
}

初始化控制台

console_init();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值