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

原创 2015年07月10日 22:44:50

修改自: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-master\arch\arm\mach-zynq\arm\common.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-master\arch\arm\mach-zynq\armcommon.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()

版权声明:本文为博主原创文章,未经博主允许不得转载。

MACHINE_START-内核板级初始化实现机制(linux3.1.0)

在驱动开发时,我们都是以一块开发板为基础移植驱动程序。每一块开发板对应一个板级文件,如开发 TI AM335x系列,则对应board-am335xevm.c,这个文件完成芯片和板级的初始化工作。对于驱...
  • charliewangg12
  • charliewangg12
  • 2014年11月26日 17:03
  • 1721

ARM Linux 3.x的设备树(Device Tree)

宋宝华 Barry Song 1.    ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM th...
  • 21cnbao
  • 21cnbao
  • 2013年01月01日 17:32
  • 201429

zynq下移植linux app示例

  • 2017年08月08日 22:01
  • 444KB
  • 下载

Zynq-Linux移植学习笔记之19-启动加载与固化

1、  启动加载 启动时候自动执行shell脚本 Mount ramdisk,修改rootfs里面rcs文件   在RCS中添加代码 echo "++ Starting telnet daemo...
  • jj12345jj198999
  • jj12345jj198999
  • 2017年08月08日 22:11
  • 503

MACHINE_START与MACHINE_END

在移植Linux时,有个结构体需要填写,它以MACHINE_START开始并以MACHINE_END结束,如下mini2440开发板的移植为示例 MACHINE_START(MINI2440, "M...
  • cxw3506
  • cxw3506
  • 2013年01月07日 11:01
  • 7177

(DT系列三)系统启动时, dts 是怎么被加载的

一,主要问题: 系统在启动的时候,是怎么加载 dts的; Lk,kernel中都需要调查。 二:参考文字 dts加载流程如下图所示: 启动过程中,bootloader...
  • lichengtongxiazai
  • lichengtongxiazai
  • 2014年08月30日 09:43
  • 16298

zynq开发板linux移植资料

  • 2016年12月20日 22:46
  • 32.43MB
  • 下载

zynq zc706 Linux系统移植笔记

1、uboot源码        zynq u-boot github地址:https://github.com/xilinx 2、zynq下启动流程 3、uboot编译     # ...
  • ljh618625
  • ljh618625
  • 2017年11月17日 18:05
  • 176

(DT系列四)驱动加载中, 如何取得device tree中的属性

本文以At91rm9200平台为例,从源码实现的角度来分析驱动加载时,Device tree的属性是如何取得的。 一:系统级初始化 DT_MACHINE_START 主要是定义"struct ma...
  • lichengtongxiazai
  • lichengtongxiazai
  • 2014年08月30日 09:48
  • 13868

Zynq-Linux移植学习笔记之一-入门

1、相关网站 zynq linux软件网站:www.wiki.xilinx.com zynq u-boot github地址:https://github.com/xilinx   2、启动过程 ...
  • jj12345jj198999
  • jj12345jj198999
  • 2016年12月20日 22:56
  • 7423
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:[Zedboard Linux系统移植]-从MACHINE_START开始
举报原因:
原因补充:

(最多只允许输入30个字)