• [Zedboard Linux系统移植]-从MACHINE_START開始


    改动自:http://www.cnblogs.com/lknlfy/archive/2012/05/06/2486479.html
    内核的启动过程?


    3)内核的启动过程?
    arch/arm/kernel/head.S —> 内核的启动汇编
    r0 = 0 。 r1 = machine nr, r2 = atags pointer. 机器码 启动參数地址,machine 来自于u-boot传參,当中u-boot的机器码定义在
    “u-boot-Digilent-Dev-master/arch/arm/include/asm/mach-types.h” 中例如以下
    这里写图片描写叙述
    head.S中
    b    secondary_start_kernel —>跳转到C语言的入口函数
    //linux内核的机器码列表文件:arch/arm/tools/mach-types
    init/main.c —> start_kernel //C语言的程序入口
    // 操作系统的管理思想 : 内存管理、任务管理、设备管理、文件管理
    setup_arch(&command_line); //体系初始化 —> arch/arm/kernel/setup.c setup_command_line(command_line); //
    arch/arm/kernel/setup.c –> setup_arch()中
    mdesc = setup_machine(machine_arch_type); //配置当前的机器类型,machine_arch_type就是机器码的类型,这里就是赋值MACH_XILINX_EP107
    MACH_XILINX_EP107在这个宏在/arch/arm/tools/mach-types中
    这里写图片描写叙述
    SMDK2410 的初始化代码在哪里? —> 遍历查找arch/arm文件夹下的的相应机器码的初始化文件 —-> Linux-Digilent-Dev-masterarcharmmach-zynqarmcommon.c
    //跟该机器码相应的设备初始化功能列表:

        DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
        /* 64KB way size, 8-way associativity, parity disabled */
        .l2c_aux_val    = 0x00000000,
        .l2c_aux_mask   = 0xffffffff,
        .smp        = smp_ops(zynq_smp_ops),
        .map_io     = zynq_map_io,
        .init_irq   = zynq_irq_init,
        .init_machine   = zynq_init_machine,
        .init_late  = zynq_init_late,
        .init_time  = zynq_timer_init,
        .dt_compat  = zynq_dt_match,
        .reserve    = zynq_memory_init,
        .restart    = zynq_system_reset,
    MACHINE_END
        zynq_init_machine--->  当前的zybo的机器初始化主函数。如需上点后初始化该板子的其它外设,能够在本函数内加入相应的初始化功能。
    

    玩过或者移植过arm-linux的都应该知道在/arch/arm文件夹下有很多与详细处理器相关的文件夹。当然对于zynq的话所相应的文件夹就是mach-zynq。在里面找到与详细板子相关的文件Linux-Digilent-Dev-masterarcharmmach-zynqarmcommon.c,没错。就是它。不管是出于想移植到新的内核还是出于想深入学习某一款arm等,对这个文件的学习是不可缺少的。

    这个文件大部分内容是对平台设备的结构体初始化。在这个文件的最后有一个非常重要的宏:

    DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
        /* 64KB way size, 8-way associativity, parity disabled */
        .l2c_aux_val    = 0x00000000,
        .l2c_aux_mask   = 0xffffffff,
        .smp        = smp_ops(zynq_smp_ops),
        .map_io     = zynq_map_io,
        .init_irq   = zynq_irq_init,
        .init_machine   = zynq_init_machine,
        .init_late  = zynq_init_late,
        .init_time  = zynq_timer_init,
        .dt_compat  = zynq_dt_match,
        .reserve    = zynq_memory_init,
        .restart    = zynq_system_reset,
    MACHINE_END

    DT_:qMACHINE_START的定义在arch/arm/include/asm/mach/arch.h,例如以下:

    #define DT_MACHINE_START(_name, _namestr)               
    static const struct machine_desc __mach_desc_##_name    
     __used                                                 
     __attribute__((__section__(".arch.info.init"))) = {    
            .nr             = ~0,                           
            .name           = _namestr,
    
    #endif

    噢,事实上就是定义了一个struct machine_desc类型结构体变量,这个结构体还定义了其它一些成员,接下来着重关注.init_machine这个成员,它是一个函数指针,值为zynq_init_machine,这个函数也在common.c中定义。内容是什么呢?呵呵,由于在这里仅仅给出大体流程,详细内容先不分析。如今最关心的是这个结构体变量在哪里被调用,从而调用它里面的成员和成员函数呢?先来看/arch/arm/kernel/setup.c里面的setup_arch()函数:

    void __init setup_arch(char **cmdline_p)
    {
        const struct machine_desc *mdesc;
    
        setup_processor();
        mdesc = setup_machine_fdt(__atags_pointer);
        if (!mdesc)
            mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
        machine_desc = mdesc;
        machine_name = mdesc->name;
    
        if (mdesc->reboot_mode != REBOOT_HARD)
            reboot_mode = mdesc->reboot_mode;
    
        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;
    
        /* populate cmd_line too for later use, preserving boot_command_line */
        strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
        *cmdline_p = cmd_line;
    
        parse_early_param();
    
        early_paging_init(mdesc, lookup_processor_type(read_cpuid_id()));
        setup_dma_zone(mdesc);
        sanity_check_meminfo();
        arm_memblock_init(mdesc);
    
        paging_init(mdesc);
        request_standard_resources(mdesc);
    
        if (mdesc->restart)
            arm_pm_restart = mdesc->restart;
    
        unflatten_device_tree();
    
        arm_dt_init_cpu_maps();
        psci_init();
        ......................

    这个函数在/init/main.c的start_kernel()函数里被调用。看到第10行,这里的setup_machine()函数的作用就是找到我们想要的struct machine_desc类型的变量,也就是在common.c里定义那个变量。

    函数的參数machine_arch_type的值是什么呢?继续看:
    这是在u-boot中MACHINE定义
    这里写图片描写叙述

    #  define machine_arch_type     MACH_TYPE_XILINX_EP107

    也就是说參数machine_arch_type的值为2520。

    在setup_machine()函数里主要调用了lookup_machine_type()函数来查找相应的type,应该是出于效率的原因。这个函数是通过汇编实现的,在此就不给出详细代码了。

    到这里,知道了在/init/main.c的start_kernel()函数里调用了setup_arch(),在setup_arch()里找到了详细的struct machine_desc类型的变量,可是在哪里通过这个变量调用里面的成员或成员函数的呢?继续找。

    还是在setup.c里,看到了这样一个函数:

    static int __init customize_machine(void)
    {
        /*
         * customizes platform devices, or adds new ones
         * On DT based machines, we fall back to populating the
         * machine from the device tree, if no callback is provided,
         * otherwise we would always need an init_machine callback.
         */
        if (machine_desc->init_machine)
            machine_desc->init_machine();
    #ifdef CONFIG_OF
        else
            of_platform_populate(NULL, of_default_bus_match_table,
                        NULL, NULL);
    #endif
        return 0;
    }

    最终看到了,成员函数init_machine就是在这里被调用的。

    可是它没有被显式调用,而是放在了arch_initcall这个宏里。去看看它怎么定义的在./include/linux/init.h:这里写图片描写叙述
    再看__define_initcall宏:在./arch/um/include/shared/init.h中
    这里写图片描写叙述
    嗯。它被链接到了.initcall段里,如今简单看看./include/asm-generic/vmlinux.lds.h:这个链接脚本里关于initcall的定义:
    这里写图片描写叙述
    能够看到customize_machine()被放到了.initcall3.init里。说了那么多定义,到底它在哪里被调用啊?好吧,它是在/init/main.c里一个叫do_initcalls()的函数里被调用,去看看:
    这里写图片描写叙述
    看到第1行。非常熟悉吧。在for循环里依次调用了从__early_initcall_end開始到__initcall_end结束的全部函数。customize_machine()也是在其间被调用。
    好了,到这里差点儿相同该结束了,最后总结一下这些函数调用顺序:
    start_kernel()—>setup_arch()—>do_initcalls()—>customize_machine()—>zynq_init_machine()

  • 相关阅读:
    list转datatable c#
    按钮靠右css小结
    IE浏览器打印合格证相关问题
    vue项目插入视频-mp4
    vue项目bug-Couldn’t find preset "es2015"
    Mac打开swf文件
    mac+windows下从git上拉取项目及运行
    echarts.js制作中国地图
    前端数据可视化echarts.js
    vue-router 基本使用
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5352047.html
Copyright © 2020-2023  润新知