改动自: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()

[Zedboard Linux系统移植]-从MACHINE_START開始的更多相关文章

  1. 【课程分享】深入浅出嵌入式linux系统移植开发 (环境搭建、uboot的移植、嵌入式内核的配置与编译)

    深入浅出嵌入式linux系统移植开发 (环境搭建.uboot的移植.嵌入式内核的配置与编译) 亲爱的网友,我这里有套课程想和大家分享,假设对这个课程有兴趣的,能够加我的QQ2059055336和我联系 ...

  2. MiniCRT 64位 linux 系统移植记录:64位gcc的几点注意

    32位未修改源码与修改版的代码下载: git clone git@github.com:youzhonghui/MiniCRT.git MiniCRT 64位 linux 系统移植记录 MiniCRT ...

  3. 非常详细的ok6410的linux系统移植…

    目录 Linux 3.3.5系统移植 2 LED驱动移植 8 按键驱动移植 9 LCD驱动移植 11 DM9000网卡驱动移植 14 搭建NFS网络文件系统 25 移植触摸屏驱动 38 移植Qt4.8 ...

  4. 嵌入式linux系统移植(一)

    内容:   交叉编译环境   bootloader功能子系统   内核核心子系统   文件系统子系统要点:  搭建交叉编译环境  bootloader的选择和移植  kernel的配置.编译.移植和调 ...

  5. Linux系统移植的重要文件

    移植linux内核的关键文件:             arch/arm/mach-s5p6818/cpu.c                         cpu_init_machine()   ...

  6. Linux系统移植(1) ------搭建交叉编译环境

    本人的开发环境是ubuntu12.05的64版本,运行在11.00的虚拟机上.首先说明为什么需要搭建交叉编译环境.我们知道,我们的开发一般在PC机上,是基于X86架构的,而我们的开发板却是基于ARM架 ...

  7. 嵌入式Linux系统移植——uboot常用命令

    flash的一般分区: 其它数据 环境变量 可执行程序.如bootloader print(可缩写为:pri):打印查看uboot这个软件中集成的环境变量setenv.saveenv:设置.保存环境变 ...

  8. linux 系统移植uboot

    这里使用的版本为:u-boot-2014.04 查看并修改位置如下:u-boot-2014.04/include/configs/at91sam9x5ek.h(1)查看一下Linux内核在NandFl ...

  9. 2440开发板linux系统移植3G拨号上网收发短信(三)

    一.用text查看模式 下面的“发”是指我敲的命令,“收”是指回车后显示的信息包括其他接收的信息. ~ >: microcom -s 115200 /dev/ttyUSB1 发:at 收:OK ...

随机推荐

  1. 原生JavaScript插件开发[转]

    一起学习下 插件的开发,原生的. 看了这文章 JavaScript插件开发从入门到精通系列---原生JavaScript插件开发 附上 读完小结: 看了下,比较小白的方式就是把一些代码,放到一个单独的 ...

  2. 相比之前其他几个入门的, 推荐: 简单vue2 入门教程

    注意:Vue.js 不支持 IE8 及其以下 IE 版本.       具体可以看下  http://www.runoob.com/vue2/vue-tutorial.html 以下是学习过程 Vue ...

  3. (C# Window Service) Verify that you have sufficient privileges to start system services

    写了个Windows Service, 用Wix 写了个Installer,编译通过,生成了msi 安装文件,但是安装的时候总是提示: Product: KingPro Service -- Erro ...

  4. Android 图文混排 通过webview实现并实现点击图片

    在一个开源项目看到是用的webview 实现的 1. 这是在asset中的一个模板html <html> <head> <title>News Detail< ...

  5. vue2.0中的计算属性

    计算属性是一个很邪门的东西,只要在它的函数里引用了data中的某个属性,当这个属性发生变化的时候,函数仿佛可以嗅探到这个变化,并自动重新执行. 上代码会源源不断的打印出a的值.如果希望b依赖data中 ...

  6. MyBatis学习笔记(一)

    测试Demo的目录结构: com.luohao.config ->MyBatisCongfig.xml ->userMapper.xml com.luohao.Test ->Test ...

  7. python中的内容编码

    一.python编码简介 1)编码格式简介 python解释器在加载 .py 文件中的代码时,会对内容进行编码(默认ASCII),ASCII(American Standard Code for In ...

  8. Connection to linux server with ORACLE SQL DEVELOPER

    1.Link name is random 2.username and password is database account 3.host name  is ip address  ifconf ...

  9. 探寻IIS最大并发数

    原文链接,http://www.cnblogs.com/birdshover/archive/2009/08/16/1547025.html 原文评论值得一看!   测试系统Window 2003 S ...

  10. Power shell 复制文件到远程主机

    昨天因为要复制文件到多个服务器上,感觉一个个复制很麻烦,我就想用Power shell 命令来完成这个任务.具体代码如下: $servers= 'server1' ,'server2' $userna ...