以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除。

汇编阶段主要是arch/arm/kernel/目录下的head.S文件,主要完成以下内容:

(1)校验启动合法性;(CPU ID,机器码,uboot给内核的传参格式)

(2)建立段式映射的页表并开启MMU以方便使用内存;

(3)构建C运行环境,跳入C阶段。

1、内核运行的物理地址与虚拟地址

(1)KERNEL_RAM_VADDR(VADDR就是virtual address),这个宏定义了内核运行时的虚拟地址,值为0xC0008000。

(2)KERNEL_RAM_PADDR(PADDR就是physical address),这个宏定义内核运行时的物理地址,值为0x30008000。

(3)因此,内核运行的物理地址是0x30008000,对应的虚拟地址是0xC0008000。

2、内核的真正入口

(1)__HEAD定义了段名为.head.text的段。

(2)ENTRY(stext)表明内核的真正入口。

(3)uboot启动内核后,实际调用zImage前面的那段未经压缩的解压代码,解压代码运行时先将zImage后面的部分解压开,然后再去调用运行真正的内核入口(即这里)。

(4)内核启动需要一定的先决条件,这个条件由启动内核的bootloader(比如uboot)来构建保证。

(5)ARM体系中,函数调用时实际是通过寄存器传参的(函数调用时传参有两种设计:一种是寄存器传参,另一种是栈内存传参)。

  • uboot中最后theKernel (0, machid, bd->bi_boot_params);执行内核时,实际把0放入r0中,machid放入到了r1中,bd->bi_boot_params放入到了r2中。
  • ARM的这种处理技巧刚好满足了kernel启动的条件和要求。

(6)此时MMU是关闭的,因此硬件上需要的是物理地址。

  • 但是内核是一个整体(zImage)只能被连接到一个地址(不能分散加载),这个连接地址肯定是虚拟地址。
  • 因此head.S文件中尚未开启MMU之前的代码必须是位置无关码,而且其中涉及到操作硬件寄存器等时必须使用物理地址。

3、__lookup_processor_type与__lookup_machine_type

(1)cp15协处理器的c0寄存器中读取出硬件的CPU ID号,然后调用__lookup_processor_type来进行合法性检验。

  • 如果合法则继续启动,如果不合法则停止启动,转向__error_p启动失败。

(2)__lookup_processor_type检验cpu id合法性的方法

  • 内核会维护一个本内核支持的CPU ID号码的数组,然后该函数将从硬件中读取到的cpu id号码和数组中存储的各个id号码依次对比,如果没有一个相等则不合法,如果有一个相等的则合法。

(3)内核启动时设计这个校验,也是为了内核启动的安全性着想。

(4)__lookup_machine_type函数的设计理念和思路和上面校验cpu id的函数一样的,不同之处是本函数校验的是机器码。

4、__vet_atags

(1)该函数的设计理念和思路和上面2个一样,用来校验uboot给内核的传参ATAGS格式是否正确。

  • 这里说的传参指的是uboot通过tag给内核传的参数(主要是板子的内存分布memtag、uboot的bootargs)。

(2)uboot给内核传参的部分如果不对,会导致内核启动不起来。譬如uboot的bootargs设置不正确,则内核可能就会不启动。

5、__create_page_tables

(1)此函数用来建立页表。

(2)linux内核本身被连接在虚拟地址处,因此kernel希望尽快建立页表并且启动MMU进入虚拟地址工作状态。

(3)kernel建立页表分为2步。

  • 第一步,kernel先建立一个段式页表(和uboot中建立的页表一样,页表以1MB为单位来区分)。此函数就是建立段式页表的。段式页表本身比较好建立(段式页表1MB一个映射,4GB空间需要4096个页表项,每个页表项4字节,因此一共需要16KB内存来做页表),但不能精细管理内存;
  • 第二步,建立一个细页表(4kb为单位的细页表),然后启用新的细页表,并废除第一步建立的段式映射页表。

(4)内核启动的早期建立段式页表,并在内核启动早期使用;内核启动的后期再次建立细页表并启用。等内核工作起来后,就只有细页表了。

6、__switch_data 函数指针数组

(1)建立段式页表后进入__switch_data部分,它是一个函数指针数组。

(2)分析得知下一步要执行__mmap_switched函数。

  • 复制数据段、清除bss段(目的是构建C语言运行环境)。
  • 保存起来cpu id号、机器码、tag传参的首地址。
  • b start_kernel跳转到C语言运行阶段。

补充

1、Makefile分析

(1)Makefile中刚开始定义了kernel的内核版本号。这个版本号在模块化驱动安装时会需要用到。

(2)在make编译内核时,可以通过命令行给内核makefile传参。譬如make O=xxx可以指定到另外一个单独文件夹下编译。

(3)kernel的顶层Makefile中定义了2个变量,一个是ARCH,一个是CROSS_COMPILE。

  • ARCH决定当前配置编译的路径,譬如ARCH = arm的时候,将来在源码目录下去操作的arch/arm目录。
  • CROSS_COMPILE用来指定交叉编译工具链的路径和前缀。
  • CROSS_COMPILE = xxx,ARCH = xxx,O=xxx,这些都可以在make时,通过命令行传参的方式传给顶层Makefile。
  • 因此makefile可以什么都不改,而是在命令行里面输入相应的参数(因为用了?=(如果定义了,则使用定义的,否则用默认的)),即输入make O=/tmp/mykernel ARCH=arm CROSS_COMPILE=/usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-

2、链接脚本分析

(1)分析连接脚本,找到整个程序的entry。

(2)kernel的连接脚本并不是直接提供的,而是提供了一个汇编文件vmlinux.lds.S,然后在编译的时候再去编译这个汇编文件得到真正的链接脚本vmlinux.lds。

(3)vmlinux.lds.S在arch/arm/kernel/目录下。

(4)为什么linux kernel不直接提供vmlinux.lds?

  • .lds文件中只能写死,不能用条件编译。
  • 在kernel中链接脚本时,有条件编译的需求(但是lds格式又不支持)。
  • kernel工作者把vmlinux.lds写成一个汇编文件,然后汇编器处理的时候顺便把条件编译给处理了,得到一个不需要条件编译的vmlinux.lds。

(5)整个程序入口在哪里?

  • 从vmlinux.lds中ENTRY(stext)可以知道入口符号是stext。
  • 在SI中搜索这个符号,发现arch/arm/kernel/目录下的head.S和head-nommu.S中都有。
  • head.S是启用了MMU情况下的kernel启动文件,相当于uboot中的start.S。head-nommu.S是未使用mmu情况下的kernel启动文件。

内核启动的汇编阶段——head.S文件相关推荐

  1. x210:uboot和系统移植扩展--内核启动之解压缩阶段

    zImage的生成过程 依据arch/arm/boot/vmlinux.lds.S生成arch/arm/boot/vmlinux.lds #arch/arm/kernel/.vmlinux.lds.c ...

  2. Linux系统从uboot到内核启动流程

    1. BROM引导: ARM CPU刚上电时,它的PC寄存器指针指向IC内嵌的一片ROM的起始位置处,这片ROM称之为BROM(boot rom),系统就是通过这片BROM引导起来的.BROM的空间比 ...

  3. 第3阶段——内核启动分析之prepare_namespace()如何挂载根文件系统和mtd分区介绍(6)...

    内核启动并初始化后,最终目的是像Windows一样能启动应用程序,在windows中每个应用程序都存在C盘.D盘等,而linux中每个应用程序是存放在根文件系统里面,那么挂载根文件系统在哪里,怎么实现 ...

  4. 系统移植-(二)u-boot:启动过程做的工作(汇编阶段、C阶段)

    u-boot 启动过程 (一)ctags 安装 (二)uboot 启动过程 (1)链接脚本u-boot.lds (2)start.S分析 (3)Reset handler 分析 (1)bl cpu_i ...

  5. 内核启动分析(三)——zImage 解压缩阶段

          在上阶段,主要是U-BOOT 向内核传递一些参数.而这些参数是通过 struct tag来传递的.U-boot 把要传递给 kernel 的东西保存在 struct tag 数据结构中,启 ...

  6. Linux内核源码分析--内核启动之(2)Image内核启动(汇编部分)(Linux-3.0 ARMv7) 【转】...

    转自:http://blog.chinaunix.net/uid-25909619-id-4938389.html 在完成了zImage自解压之后,就跳转到了解压后的内核(也就是vmlinux的bin ...

  7. uboot源码——汇编阶段的start.S文件

    以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 一.相关内容 (1) 阶段的定义 第一阶段,即在内部SRAM运行的阶段,简单地理解为汇编阶段,此阶段主要涉及start.S文件,在cpu/s ...

  8. linux文件系统启动流程,linux 内核启动过程以及挂载android 根文件系统的过程

    转载 作者:汕头大学-黄珠唐 时间:2009 年10 月29 日 主要介绍linux 内核启动过程以及挂载android 根文件系统的过程,以及介绍android 源代码中文件系统部分的浅析. 主要源 ...

  9. 内核启动的C语言阶段——start_kernel函数

    以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. start_kernel函数位于kernel/init/main.c,完成以下内容: (1)打印一些输出信息. (2)内核工作所需的模块的初 ...

最新文章

  1. Ansible06-管理roles
  2. 1027 Colors in Mars
  3. SSM项目的数据库密码加密方案
  4. php mysql书城_php在线书城 thinkphp源码(含数据库脚本)
  5. 一些SAP UI5代码审查的例子
  6. 解析ThreadPoolExecutor类是如何保证线程池正确运行的
  7. TP5.1 查询数据库中上一条和下一条记录
  8. linux搭建博客-day 7安装Nginx
  9. 【王道计组笔记】定点数编码方式(原码,补码,反码)
  10. java第四章编程题(初学篇)
  11. AMD将统治2017年的PC及服务器市场?
  12. Java的第20年:Java和我的故事
  13. 关于如何取消萤石云视频加密
  14. C语言字谜游戏(函数嵌套、指针)
  15. 买服务器上国外网站,国外服务器怎么买?
  16. RTSP协议网络摄像头互联网无插件直播EasyNVR+EasyNVS,如何保持配置地址一致?
  17. Linux重启后硬盘挂载失效问题解决
  18. VC++的窗口句柄和窗口ID
  19. jQuery 实现音乐导航案例
  20. teradata ttu_Teradata Studio中文乱码解决方法

热门文章

  1. 十、eclipse快捷键大全
  2. 慕学在线网0.4_xadmin后台管理
  3. 新网卡不能绑定“旧”IP故障的解决
  4. DataGrid 完全攻略之四 (实现统计)
  5. Qtum量子链漏洞赏金计划正式开启
  6. NG客制项目下的I18n国际化标准方案
  7. 论文笔记之:Deep Attention Recurrent Q-Network
  8. QtQuick controls和controls2 自定义样式
  9. SQL Server中的STUFF函数的使用
  10. 深度剖析SOC高性能实时事件关联分析引擎