Linux内核引导代码分析

内核干了什么:处理u-boot 传进来的参数———-到识别根文件系统,运行其中的应用程序。

u-boot在内存中设置了一大堆参数,然后通过函数指针theKernel传递给内核,第二个参数为机器ID,第三个为内存中参数存放的地址。
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

1、内核第一个执行的文件:linux/arch/arm/kernel/head.S
主要调用__lookup_processor_type和__lookup_machine_type判断当前内核是否支持CPU和开发板。id由U-Boot传过来,之后再进行创建页表等一些工作。创建页表之后才使用虚拟地址。最后跳到init/main.c中的secondary_start_kernel

ENTRY(stext)
    msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE//进入管理模式,禁止中断
    mrc p15, 0, r9, c0, c0          @ get processor id
    bl  __lookup_processor_type     @ r5=procinfo r9=cpuid
    movs    r10, r5                 @ invalid processor (r5=0)?
    beq __error_p                   @ yes, error 'p'
    bl  __lookup_machine_type       @ r5=machinfo
    movs    r8, r5                  @ invalid machine (r5=0)?
    beq __error_a                   @ yes, error 'a'
    bl  __create_page_tables

......
    b   secondary_start_kernel

2、CPU信息结构定义在:include/asm-arm/procinfo.h,这是每个CPU的信息结构

struct proc_info_list {
    unsigned int        cpu_val;
    unsigned int        cpu_mask;
    unsigned long       __cpu_mm_mmu_flags; /* used by head.S */
    unsigned long       __cpu_io_mmu_flags; /* used by head.S */
    unsigned long       __cpu_flush;        /* used by head.S */
    const char      *arch_name;
    const char      *elf_name;
    unsigned int        elf_hwcap;
    const char      *cpu_name;
    struct processor    *proc;
    struct cpu_tlb_fns  *tlb;
    struct cpu_user_fns *user;
    struct cpu_cache_fns    *cache;
};


内核对每个开发板都使用宏MACHINE_START、MACHINE_END来定义一个结构,
位于:/include/asm-arm/mach/arch.h

#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             \
};

3、每个CPU具体信息在:arch/arm/mm下对应没一个文件。如proc-arm920.S

//.section表示下面__arm920_proc_info定义在.proc.info.init段,所有CPU信息都连接在该段。
    .section ".proc.info.init", #alloc, #execinstr

    .type   __arm920_proc_info,#object
__arm920_proc_info:
    .long   0x41009200
    .long   0xff00fff0
    .long   PMD_TYPE_SECT | \
        PMD_SECT_BUFFERABLE | \
        PMD_SECT_CACHEABLE | \
        PMD_BIT4 | \
        PMD_SECT_AP_WRITE | \
        PMD_SECT_AP_READ
    .long   PMD_TYPE_SECT | \
        PMD_BIT4 | \
        PMD_SECT_AP_WRITE | \
        PMD_SECT_AP_READ
    b   __arm920_setup
    .long   cpu_arch_name
    .long   cpu_elf_name
    .long   HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
    .long   cpu_arm920_name
    .long   arm920_processor_functions
    .long   v4wbi_tlb_fns
    .long   v4wb_user_fns
#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
    .long   arm920_cache_fns
#else
    .long   v4wt_cache_fns
#endif
    .size   __arm920_proc_info, . - __arm920_proc_info



每个开发板对应一个文件如:arch/arm/mach-s3c2440/mach-smdk2440.c,
所有开发板信息位于.arch.info.init段,即位于__arch_info_begin 和 __arch_info_end
之间。U-Boot调用内核时会在r1寄存器中给出机器  ID。


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,

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

4、__lookup_processor_type和__lookup_machine_type位于arch/arm/kernel/head-commom.S

//__lookup_processor_type就是在存储各种CPU信息的段之间,即__arch_info_begin和
__arch_info_end之间寻找有没有传入的我们需要的CPU
//以数字当标号,跳转时如2b指跳到上一个标号22f指跳到下一个标号2

    .type   __lookup_processor_type, %function
__lookup_processor_type:
    adr r3, 3f
    ldmda   r3, {r5 - 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
    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

5、最后跳到init/main.c中的start_kernel
U-Boot传给内核的参数有两类:

调用内核时r1寄存器指定的机器ID,其在引导阶段__lookup_machine_type函数已经用到。

预先存在某个地址的tag列表(内存tag和命令行tag),其将在arch/arm/kernel/setup.c中函数setup_arch进行初步处理。

start_kernel中调用函数setup_arch

void __init setup_arch(char **cmdline_p)
{
    struct tag *tags = (struct tag *)&init_tags;
    struct machine_desc *mdesc;

//要是启动时没有传进命令,则使用默认命令
    char *from = default_command_line;

    setup_processor();
    mdesc = setup_machine(machine_arch_type);
    machine_name = mdesc->name;

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

    if (mdesc->boot_params)
        tags = phys_to_virt(mdesc->boot_params);

    /*
     * If we have the old style parameters, convert them to
     * a tag list.
     */
    if (tags->hdr.tag != ATAG_CORE)
        convert_to_tag_list(tags);
    if (tags->hdr.tag != ATAG_CORE)
        tags = (struct tag *)&init_tags;

    if (mdesc->fixup)
        mdesc->fixup(mdesc, tags, &from, &meminfo);

    if (tags->hdr.tag == ATAG_CORE) {
        if (meminfo.nr_banks != 0)
            squash_mem_tags(tags);
        parse_tags(tags);
    }

    init_mm.start_code = (unsigned long) &_text;
    init_mm.end_code   = (unsigned long) &_etext;
    init_mm.end_data   = (unsigned long) &_edata;
    init_mm.brk    = (unsigned long) &_end;

    memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
    boot_command_line[COMMAND_LINE_SIZE-1] = '\0';

//如果命令行传进来则解析
    parse_cmdline(cmdline_p, from);
    paging_init(&meminfo, mdesc);
    .......
start_kernel最后会调用
    setup_arch(&command_line);//解析u-boot传进的参数
    setup_command_line(command_line);
    rest_init(还在init/main.c中)
        kernel_init
            prepare_namespace
                mount_root挂接根文件系统
            init_post(和prepare_————并列                            run_init_process执行应用程序

MTD:内存技术设备
分区在下面代码中写死,u-boot传进来的/dev/mtdblock3就对应其中一个分区
linux-2.6.22.6\arch\arm\plat-s3c24xx\Common-smdk.c

static struct mtd_partition smdk_default_nand_part[] = {
    [0] = {
        .name   = "Boot Agent",
        .size   = SZ_16K,
        .offset = 0,
    },
    [1] = {
        .name   = "S3C2410 flash partition 1",
        .offset = 0,
        .size   = SZ_2M,
    },
    [2] = {
        .name   = "S3C2410 flash partition 2",
        .offset = SZ_4M,
        .size   = SZ_4M,
    },
    [3] = {
        .name   = "S3C2410 flash partition 3",
        .offset = SZ_8M,
        .size   = SZ_2M,
    },
    [4] = {
        .name   = "S3C2410 flash partition 4",
        .offset = SZ_1M * 10,
        .size   = SZ_4M,
    },
    [5] = {
        .name   = "S3C2410 flash partition 5",
        .offset = SZ_1M * 14,
        .size   = SZ_1M * 10,
    },
    [6] = {
        .name   = "S3C2410 flash partition 6",
        .offset = SZ_1M * 24,
        .size   = SZ_1M * 24,
    },
    [7] = {
        .name   = "S3C2410 flash partition 7",
        .offset = SZ_1M * 48,
        .size   = SZ_16M,
    }
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值