uboot和linux平台区别_uboot 下的ping 跟linux下的ping有什么区别 - CSDN
  • http://www.crifan.com/records_in_the_uboot_201106_mmc_drive_the_process_of_porting_to_uboot_116/ 2.下面讨论所涉及的概念问题,具有一定普遍性:不止一个人遇到类似的疑惑,对类似的概念不熟悉, 所以...

    原文转自:http://www.crifan.com/take_sd_card_driver_as_example_explain_uboot_drive_and_linux_kernel_drive_and_how_develop_uboot_driver/

    说明:

    1.和下面论相关的帖子:

    http://www.crifan.com/records_in_the_uboot_201106_mmc_drive_the_process_of_porting_to_uboot_116/

    2.下面讨论所涉及的概念和问题,具有一定普遍性:不止一个人遇到类似的疑惑,对类似的概念不熟悉,

    所以专门在此处,一并解释清楚。

    3.此讨论,如果后续有更新,会一并添加进来的。

    4.抽空会额外整理出更详尽的内容。最终,应该会加到,相关的教程中。


    1."旧的mmc检测出sd卡的容量不对·,那现在的mmc里面是含有sd卡的驱动吗?" 
    参见前面的解释。 
    再多说几句: 
    现在的uboot里面,本身已经包含了,很多关于sd/mmc方面的代码。 
    主要可以分几部分: 
    (1)sd/mmc等协议方面的,通用的代码 
    这部分代码,是别人,别的开发者,uboot的开发者,帮你实现好了的 
    你无需再写,只是(当实现你自己的sd卡驱动的时候,)借用,利用到 
    即:你的代码,内部在执行sd卡方面的操作,比如读写数据等动作时,内部会调用此部分的,通用代码 
    (2)不同平台(即不同的开发板)中,实现了自己的sd卡驱动 
    每个平台(可以理解为开发板)都可能有不同的sd卡(主控芯片),对应的,(如果不同开发板的sk卡主控芯片不同的话)都需要自己实现自己对应的sd卡(主控芯片)的驱动 
    这部分的代码,对于你来说,对于你想要实现你自己的开发板的sd卡驱动来说, 
    你是无法直接使用的。 
    但是,别人实现的sd卡驱动的代码,多多少少,肯定还是有一些,或者说很大程度上的参考价值的。

    对于你要实现你自己的sd卡驱动,就是: 
    搞清楚你的(开发板所用的)sd卡(主控)芯片是啥 
    找到该芯片对应的数据手册 
    其中有对应的芯片的寄存器等方面的解释 
    以及关于如何设置,设置哪些寄存器 
    才能实现你要的: 
    初始化sd卡 
    sd卡的数据读写 
    高级点的功能,可能还会包括:如何利用DMA实现SD卡的(加速)数据传输(速度),等等 
    这些内容,都是需要你自己: 
    先搞懂SD卡的协议本身: 
    协议中规定的,如何去初始化,如何去实现数据读写 
    然后再去看上面的硬件(sd卡主控芯片)的数据手册,看看如何操作,实现协议中规定的内容。

    对于uboot(包含其他架构,比如Linux下的驱动框架)来说, 
    让一个设备能功能起来,此处即你想要的,实现sd卡驱动,让sd卡正常工作 
    本质上,就是实现对应的数据读写 
    但是在正常工作(数据读写)之前 
    又肯定会涉及硬件(此处为sd卡芯片)的初始化

    所以,让一个设备,正常工作的核心逻辑,都可以归为一句话: 
    先初始化硬件 
    然后实现数据的读写

    对应此处的sd卡来说就是: 
    正确初始化sd卡芯片 
    让sd卡正常数据读写

    正确初始化sd卡芯片,意思是: 
    搞懂sd卡协议中,如何初始化的逻辑和过程, 
    看懂sd卡芯片的数据手册,如何设置,设置哪些寄存器,实现sd卡的初始化

    让sd卡正常数据读写,意思是: 
    搞懂sd卡协议中,如何规定的,数据如何读写的过程 
    看懂sd卡芯片的数据手册,搞懂如何操作,需要操作哪些寄存器,才能实现sd卡的数据的收发,即数据读写

    而对于,具体的,如何去写对应的代码,此处不详细说明了,这个是写sd卡驱动的人,需要慢慢学习软硬件之后,才能搞懂的。 
    但是,其总体的逻辑,都和: 
    读操作的硬件到软件的映射 
    类似。 
    去参考参考,然后针对sd卡,去搞懂软硬件,再去一点点写对应驱动,即可。

    2.“而且我看了最新版的uboot-2013.07,有sdhci.c、sdhci.h、sdhc_boot.c、sdhc_boot.h,有sd卡驱动的话” 
    如上所述,此处,所谓的,有sd卡驱动,主要指的是: 
    对于sd卡,协议级别的,和你单个的(各个板子不同的,sd卡主控芯片,可以说是无关的,那些通用代码,用于实现sd协议的代码 
    的确是有的,也的确是Uboot就帮你做好的。 
    但是,要注意的是: 
    这些,sd卡协议方面的通用的(上层)代码, 
    不是你原以为的,你的(开发板上的)sd卡(主控)芯片的驱动。 
    你的(开发板上的)sd卡(主控)芯片的驱动,是要你自己实现的 
    再说了,Uboot开发者,即使什么芯片驱动,都会写,但是又不知道你是什么芯片,不知道你是哪款芯片 
    (背景是:市面上,sd卡芯片,作为普通硬件模块之一,也可以说有千千万万的,别人又不知道你用的哪款芯片,具体是什么硬件参数和配置) 
    所以当然无法实现帮你也都一一实现了。 
    但是,还是如前所述: 
    uboot中,已有的,别的开发板的,sd卡芯片的驱动 
    那还是有很大参考价值的: 
    看看别人代码是怎么写的 
    自己搞懂sd卡的协议和你的sd卡芯片的硬件后,可以照葫芦画瓢去写你自己的sd卡驱动

    另外,万一别人某个开发板的sd卡芯片和你的一样或类似,那么别人的代码 
    你基本上可以拿过来(稍作修改,甚至无需大的改动)或许就直接可以用了呢,也未可知。

    总之: 
    需要你自己搞懂: 
    硬件方面:你自己用的什么sd卡芯片 
    软件方面:sd协议的细节,尤其是初始化和数据读写 
    再去看对应芯片的数据手册,再去写你的(uboot中的)sd卡驱动

    3.“在uboot下面也需要像在内核中一样对设备和驱动进行注册和匹配吗?” 
    简答: 
    不需要。 
    详解: 
    先澄清一个概念: 
    Linux内核中的sd卡芯片驱动,和uboot中的芯片驱动,可以说,完全是两回事 
    换句话说: 
    对于同一款sd卡芯片,如果说从uboot到Linux内核,都已经支持 
    意味着: 
    (1)uboot中,实现了对应的,该芯片的sd卡驱动 
    uboot中,如前所述,虽然也是有共同代码 
    但是整体上来说,对于设备的操作,都是相对比较直接的,甚至说粗暴的 
    没有太多的,软件层面的多个层次的架构 
    (2)内核中,实现了对应的,该芯片的sd卡驱动 
    对应的,linux内核中,为了实现支持更多类型的设备 
    都是做了更多的,更好的,更复杂的, 
    各种层面的,层次的,架构 
    且针对不同类型的设备,有对应的不同的架构 
    比如我知道的一个,MTD类型的设备,就是一个很大的软件层 
    其他,又分很多种具体类型的硬件设备的支持 
    比如nor flash,nand flash等等。 
    而对应的sd卡的话,是属于另外的,和硬盘等设备,等价的,块设备类型中 
    这类块设备,也有对应的自己的层次划分 
    而对于你要实现sd卡驱动,意味着: 
    除了对于sd卡协议的初始化,数据读写的逻辑清楚了之外 
    还要去搞懂,对于这些逻辑过程中 
    尤其是通用的过程,Linux内核的(此处的块设备的)框架,架构中, 
    已经帮你实现了哪些 
    剩下的,还需要你: 
    实现哪些具体的,和你的sd卡硬件相关的,初始化部分,数据读写部分

    但是需要注意的是: 
    虽然,从逻辑上, 
    uboot,和linux内核,都是有点类似: 
    都算是可以分为: 
    系统(uboot或linux)都定义了自己的一套框架,帮你实现了,一般都是协议级别的,通用的代码 
    而和硬件相关的,特定的代码需要你实现 
    但是: 
    Uboot和Linux内核的: 
    (1)框架 
    (2)实现的通用的代码 
    都是完全不同的,根本不是一个数量级的,不是一个复杂度的。 
    如果说uboot的,算是大事化了型的,简化型的,已经把框架弄得足够简单了, 
    但是对于普通开发者来说,其复杂度,估计也算得上3~6之间了,即也需要花点精力,才能搞懂的 
    对此,Linux所定义,所规划,出来的框架,那绝对算得上10(甚至更高)了。 
    有些子系统(比如我之前接触过的声卡方面的alsa子系统),其复杂度更高, 
    即,单独对于这些子系统,你想要花精力搞懂,都不是个容易的事情 
    不近需要大量的相关知识背景,相关的软硬件基础知识,还需要针对Linux中的该框架本身,需要花很多精力,慢慢看代码, 
    最好是动手去实践,最后才能算是一点点,搞透彻的,算是搞懂了的

    简言之: 
    (1)uboot中,框架相对简单,实现了基本的通用的协议级别的代码=》剩下只需要你,看懂该框架,搞懂框架帮你做了哪些事情,自己去实现剩下的功能,即和硬件相关的操作,即可实现,所谓的,某某硬件驱动实现完成了,支持某某硬件了; 
    (2)而对于Linux来说,框架本身就很复杂,当然也实现了,或许更多,或者说是和uboot相比,相同级别的,协议方面的通用代码=》你所要做的,往往是在真正写这些代码之外,需要真正搞懂linux的复制的各种软件架构,各种层次,各种框架,各种设计,搞懂后,才能"下笔",才能去写,和uboot中类似的工作,即写写和硬件相关的操作,但是也要注意的是,由于框架不同,接口不同,环境不同,代码方面,出了要操作的寄存器的和要写入的值,没太大变化之外,写出来的代码,也算是差距很大,完全是两套不同体系下的代码了。

    回到此处的sd卡驱动: 
    "在uboot下面也需要像在内核中一样对设备和驱动进行注册和匹配吗?”" 
    答案就是: 
    根本不需要。 
    因为,uboot和linux的架构完全不同,框架完全不同。 
    uboot中的,更加简单,更加直接。 
    搞懂如何操作寄存器,基本上,任务算是完成了一半了。 
    剩下就是搞懂如何加对应的代码,加到哪个文件中,加到哪些(uboot中的sd卡相关的api)函数中去,就差不多了。

    展开全文
  • uboot和Linux内核移植

    千次阅读 2020-01-03 05:24:04
    这篇文章是一个读者昨晚发给我的,文章很长,里面的细节也比较多,但是微信公众号只能发 50000 字的文章,如果想阅读全文。请发送「uboot和Linux内核移植」到公众号后台获取下载...

    这篇文章是一个读者昨晚发给我的,文章很长,里面的细节也比较多,但是微信公众号只能发 50000 字的文章,如果想阅读全文。

    请发送「 uboot和Linux内核移植 」到公众号后台获取下载链接。


    这篇文章是一个读者昨晚发给我的,文章很长,里面的细节也比较多,但是微信公众号只能发 50000 字的文章,如果想阅读全文。

    请发送「uboot和Linux内核移植 」到公众号后台获取下载链接。

    一、uboot学习前传 1

    • 1.1为什么要有uboot 1

    • 1.1.1.计算机的主要部件 1

    • 1.1.2 .PC机的启动过程 1

    • 1.1.3.典型嵌入式linux系统启动过程 1

    • 1.1.4. android系统启动过程 1

    • 1.1.5.总结:uboot到底是干嘛的 1

    • 1.2 为什么是uboot 2

    • 1.2.1 .uboot从哪里来 2

    • 1.2.2 .uboot的发展历史 2

    • 1.2.3. uboot的版本号问题 2

    • 1.2.4. uboot的可移植性的正确理解 2

    • 1.2.5.总结:时势造英雄,任何牛逼的东西都是时代的产物 2

    • 1.3 uboot必须解决哪些问题 2

    • 1.3.1.能自身开机直接启动 2

    • 1.3.2.能引导操作系统内核启动并给内核传参 2

    • 1.3.3.能提供系统部署功能 3

    • 1.3.4.能进行SoC级和板级硬件管理 3

    • 1.3.5.uboot的生命周期 3

    • 1.4 uboot的工作方式 3

    • 1.4.1.从裸机程序镜像uboot.bin说起 3

    • 1.4.2.uboot的命令行式shell界面 4

    • 1.4.3.掌握uboot使用的2个关键点:命令和环境变量 4

    • 1.4.4.思考:结合ARM裸机部分进行理解和印证 4

    • 1.5 uboot的常用命令 4

    • 1.5.1.类似linux终端的行缓冲命令 4

    • 1.5.2.有些命令有简化的别名 4

    • 1.5.3.有些命令会带参数(注意格式是固定的) 5

    • 1.5.4.命令中的特殊符号(譬如单引号) 5

    • 1.5.5.有些命令是一个命令族(譬如movi) 5

    • 1.5.6.第一个命令:printenv/print 5

    • 1.5.7.设置(添加/更改)环境变量:setenv/set 5

    • 1.5.8.保存环境变量的更改:saveenv/save 5

    • 1.5.9.网络测试指令:ping 6

    • 1.5.10.tftp下载指令:tftp 6

    • 1.5.11.SD卡/iNand操作指令movi 7

    • 1.5.12.NandFlash操作指令nand 7

    • 1.5.13.内存操作指令:mm、mw、md 7

    • 1.6 开发板和主机的ping通 8

    • 1.6.1.开发板运行linux下和主机Windows的ping通 8

    • 1.6.2.开发板运行linux下和虚拟机ubuntu的ping通 8

    • 1.6.3.开发板运行uboot下和主机Windows的ping通 8

    • 1.6.4.开发板运行uboot下和虚拟机ubuntu的ping通 9

    • 1.7 uboot的常用环境变量 9

    • 1.7.1.环境变量如何参与程序运行 9

    • 1.7.2.自动运行倒计时:bootdelay 9

    • 1.7.3.网络设置:ipaddr serverip 9

    • 1.7.4.自动运行命令设置:bootcmd 9

    • 1.7.5.uboot给kernel传参:bootargs 9

    • 1.7.6.新建、更改、删除一个环境变量的方法 10

    • 1.7.7.注意:环境变量更改后的保存 10

    • 1.8 uboot中对Flash和DDR的管理 10

    • 1.8 .1.uboot阶段Flash的分区 10

    • 1.8 .2.uboot阶段DDR的分区 11

    二、Shell和Makefile 11

    • 2.1 Shell介绍 11

    • 2.1.1.Shell是什么? 11

    • 2.1.2.shell概指一类编程语言(在shell中用于编写程序的语言) 11

    • 2.1.3.shell脚本的运行机制:解释执行(没有编译和链接的过程) 11

    • 2.2 写shell程序 12

    • 2.2.1.文本编辑器 12

    • 2.2.2.shell程序的运行方法 12

    • 2.2.3.shell程序注意事项: 12

    • 2.2.4.shell不神秘 12

    • 2.3 shell编程学习 13

    • 2.3.1.shell中的变量定义、初始化、赋值和引用 13

    • 2.3.2.shell中无引号、单引号、双引号的区别 13

    • 2.3.3.shell中调用linux命令 14

    • 2.4 shell中的选择分支结构 14

    • 2.5 shell中的循环结构 15

    • 2.6 Makefile基础回顾 17

    • 2.6.1.Makefile的作用和意义 17

    • 2.6.2.目标、依赖、命令 17

    • 2.6.3.通配符%和Makefile自动推导(规则) 18

    • 2.6.4.Makefile中定义和使用变量 18

    • 2.6.5.伪目标(.PHONY) 18

    • 2.6.6.Makefile的文件名 18

    • 2.6.7.Makefile中引用其他Makefile(include指令) 18

    • 2.7 Makefile补充学习 18

    • 2.7.1.Makefile中的注释 # 18

    • 2.7.2.命令前面的@用来静默执行 18

    • 2.7.3.Makefile中几种变量赋值运算符 19

    • 2.7.4.Makefile的环境变量 20

    • 2.7.5.Makefile中的通配符 20

    • 2.7.6.Makefile的自动变量 20

    三、零距离体验uboot 20

    • 3.1 X210官方uboot配置编译实践 20

    • 3.1.1.找到官方移植好的uboot(BSP概念) 21

    • 3.1.2.在linux源生目录下配置编译 21

    • 3.1.3.配置 21

    • 3.1.4.编译得到uboot.bin 21

    • 3.2 uboot的源码目录分析 22

    • 3.2.1.九鼎官方uboot和三星原版uboot对比 22

    • 3.2.2.各文件介绍 22

    • 3.2.3.各文件夹介绍 23

    • 3.3 SourceInsight的基本使用 25

    • 3.3.1.为什么要使用SourceInsight 25

    • 3.3.2.建立工程及添加文件 25

    • 3.3.3.解析工程文件 26

    • 3.3.4.常用技巧 26

    四、uboot配置和编译过程详解 26

    • 4.1 uboot主Makefile分析 26

    • 4.1.1.uboot version确定(Makefile的24-29行) 26

    • 4.1.2.HOSTARCH和HOSTOS 26

    • 4.1.3.静默编译(50-54行) 27

    • 4.1.4.两种编译方法 27

    • 4.1.5.OBJTREE、SRCTREE、TOPDIR 27

    • 4.1.6.MKCONFIG(Makefile的101行) 27

    • 4.1.7.include $(obj)include/config.mk(133行) 28

    • 4.1.8.ARCH CROSS_COMPILE 28

    • 4.1.9.$(TOPDIR)/config.mk(主Makefile的185行) 29

    • 4.1.10.第一个目标all(主Makefile的第291行) 30

    • 4.2 uboot配置过程mkconfig详解 30

    • 4.3 uboot的u-boot.lds链接脚本 32

    五、uboot源码分析1-启动第一阶段 33

    • 5.1 start.S的引入 33

    • 5.1.1. u-boot.lds中找到start.S入口 33

    • 5.1.2. SI中如何找到文件 33

    • 5.1.3. SI中找文件技巧 33

    • 5.2 start.S解析 33

    • 5.2.1.不简单的头文件包含 34

    • 5.2.2.启动代码的16字节头部 34

    • 5.2.3.异常向量表的构建 35

    • 5.2.4.有点意思的deadbeef 35

    • 5.2.5.TEXT_BASE等 36

    • 5.2.6.(107行)CFG_PHY_UBOOT_BASE 36

    • 5.2.8.设置CPU为SVC模式(149行) 36

    • 5.2.9.设置L2、L1cache和MMU 36

    • 5.2.10.识别并暂存启动介质选择 36

    • 5.2.11.设置栈(SRAM中的栈)并调用lowlevel_init 37

    • 5.3 lowlevel_init.S解析 37

    • 5.3.1.检查复位状态 37

    • 5.3.2.IO状态恢复 37

    • 5.3.3.关看门狗 38

    • 5.3.4.一些SRAM SROM相关GPIO设置 38

    • 5.3.5.供电锁存 38

    • 5.3.6.判断当前代码执行位置 38

    • 5.3.7.system_clock_init 39

    • 5.3.8.mem_ctrl_asm_init 39

    • 5.3.9.uart_asm_init 40

    • 5.3.10.tzpc_init 40

    • 5.3.11.pop {pc}以返回 40

    • 5.4 回到start.S解析 40

    • 5.4.1.再次设置栈(DDR中的栈) 40

    • 5.4.2.再次判断当前地址以决定是否重定位 41

    • 5.5 uboot重定位详解 41

    • 5.6 start.S继续解析1 42

    • 5.6.1.关于虚拟地址和物理地址 42

    • 5.6.2.地址映射原理 43

    • 5.6.3.什么是页表(转换表)呢? 43

    • 5.6.4.uboot中虚拟地址映射采用了段模式 43

    • 5.6.5.uboot中的映射页表 46

    • 5.6.6.MMU单元的作用 46

    • 5.6.7.地址映射的额外收益1:访问控制 46

    • 5.6.8.地址映射的额外收益2:cache 46

    • 5.7 start.S继续解析2 47

    • 5.7.1.使能域访问(cp15的c3寄存器) 47

    • 5.7.2.设置TTB(cp15的c2寄存器) 47

    • 5.7.3.使能MMU单元(cp15的c1寄存器) 47

    • 5.7.4.找到映射表待分析 48

    • 5.8 start.S继续解析3 48

    • 5.8.1.再三次设置栈 48

    • 5.8.2.清理bss 48

    • 5.8.3. ldr pc, _start_armboot 48

    • 5.8.4.总结:uboot的第一阶段做了哪些工作 49

    六、uboot源码分析2-启动第二阶段 50

    • 6.1.start_armboot函数简介 50

    • 6.1.2.一个很长的函数组成uboot第二阶段 50

    • 6.1.3. 宏观分析:uboot第二阶段应该做什么 50

    • 6.1.4.思考:uboot第二阶段完结于何处? 50

    • 6.2 start_armboot解析1 51

    • 6.2.1. init_fnc_t 51

    • 6.2.2. DECLARE_GLOBAL_DATA_PTR 51

    • 6.3内存使用排布 52

    • 6.3.1.为什么要分配内存 52

    • 6.3.2.内存排布 52

    • 6.3.3. uboot运行过程中的存储分布图解 52

    • 6.4 start_armboot解析2 53

    • 6.4.1. for循环执行init_sequence 53

    • 6.4.2. int cpu_init(void) 55

    • 6.4.3. int board_init(void) 55

    • 6.4.4. int interrupt_init(void) 57

    • 6.4.5. int env_init(void) 58

    • 6.4.6. int init_baudrate(void) 59

    • 6.4.7. int serial_init(void) 59

    • 6.4.8. int console_init_f(void) 59

    • 6.4.9. int display_banner(void) 59

    • 6.4.10 int print_cpuinfo(void) 60

    • 6.4.11. int checkboard(void) 60

    • 6.4.12. int init_func_i2c(void) 61

    • 6.4.13. int dram_init(void) 61

    • 6.4.14. int display_dram_config(void) 61

    • 6.4.15. CFG_NO_FLASH 61

    • 6.4.16. 初始化堆管理器 mem_malloc_init 62

    • 6.4.17. 开发板独有初始化:mmc初始化 62

    • 6.4.18. env_relocate 62

    • 6.4.19. IP地址、MAC地址的确定 63

    • 6.4.20. int devices_init (void) 63

    • 6.4.21. void jumptable_init (void) 63

    • 6.4.22. console_init_r () 63

    • 6.4.23. void enable_interrupts (void) 64

    • 6.4.24. loadaddr、bootfile两个环境变量 64

    • 6.4.25. board_late_init (void) 64

    • 6.4.26. int eth_initialize(bd_t *bis) 64

    • 6.4.27. x210_preboot_init(void)(LCD和logo显示) 64

    • 6.4.28. check menukey to update from sd 65

    • 6.4.29. main_loop(uboot的归宿) 65

    • 6.4.30. 启动过程特征总结 66

    七、uboot源码分析3-uboot如何启动内核 66

    • 7.1 uboot和内核到底是什么 66

    • 7.1.1. uboot是一个裸机程序 66

    • 7.1.2.内核本身也是一个"裸机程序" 66

    • 7.1.3.部署在SD卡中特定分区内 66

    • 7.1.4.运行时必须先加载到DDR中链接地址处 67

    • 7.1.5.内核启动需要必要的启动参数 67

    • 7.2. 启动内核第一步:加载内核到DDR中 67

    • 7.2.1.静态内核镜像在哪里? 67

    • 7.2.2.镜像要放在DDR的什么地址? 67

    1. 3.zImage和uImage的区别联系 67

  • 7.3.1. bootm命令对应do_bootm函数 68

  • 7.3.2. vmlinux和zImage和uImage 68

  • 7.4 zImage启动细节 69

  • 7.4.1. LINUX_ZIMAGE_MAGIC 69

  • 7.4.2. image_header_t 69

  • 7.5 uImage启动 70

  • 7.6 do_bootm_linux函数 70

  • 7.6.1.找到do_bootm_linux函数 70

  • 7.6.2.镜像的entrypoint 70

  • 7.6.3.机器码的再次确定 70

  • 7.6.4.传参并启动概述 70

  • 7.7传参详解 71

  • 7.7.1. tag方式传参 71

  • 7.7.2. x210_sd.h中配置传参宏 71

  • 7.7.3.移植时注意事项 71

  • 7.8 uboot启动内核的总结 71

  • 八、uboot源码分析4-uboot的命令体系 72

    • 8.1 uboot命令体系基础 72

    • 8.1.1.使用uboot命令 72

    • 8.1.2. uboot命令体系实现代码在哪里 72

    • 8.1.3.每个命令对应一个函数 72

    • 8.1.4.命令参数以argc&argv传给函数 72

    • 8.2 uboot命令解析和执行过程分析 72

    • 8.2.1.从main_loop说起 72

    • 8.2.2关键点分析 73

    • 8.3 uboot如何处理命令集1 73

    • 8.3.1.可能的管理方式 73

    • 8.3.2.命令结构体cmd_tbl_t 73

    • 8.3.2. uboot实现命令管理的思路 74

    • 8.4 uboot如何处理命令集2 74

    • 8.4.1. uboot命令定义具体实现分析 74

    • 8.4.2. find_cmd函数详解 75

    • 8.5 uboot中添加自定义命令 76

    • 8.5.1.在已有的c文件中直接添加命令 76

    • 8.5.2.自建一个c文件并添加命令 76

    九、uboot源码分析5-uboot的环境变量 77

    • 9.1 uboot的环境变量基础 77

    • 9.1.1.环境变量的作用 77

    • 9.1.2.环境变量的优先级 77

    • 9.1.3.环境变量在uboot中工作方式 77

    • 9.2.环境变量相关命令源码解析 78

    • 9.2.1. printenv 78

    • 9.2.2. setenv 79

    • 9.2.3. saveenv 80

    • 9.2.4. getenv 80

    • 9.2.5. getenv_r 81

    十、uboot源码分析6-uboot的硬件驱动部分 81

    • 10.1 uboot与linux驱动 81

    • 10.1.2. uboot的虚拟地址对硬件操作的影响 81

    • 10.1.3. uboot借用(移植)了linux驱动 81

    • 10.2 iNand/SD驱动解析 82

    • 10.2.1.从start_armboot开始 82

    • 10.2.2. mmc_initialize 82

    • 10.2.3. cpu_mmc_init 82

    • 10.2.4. smdk_s3c_hsmmc_init 82

    • 10.2.5. s3c_hsmmc_initialize 82

    • 10.2.6. find_mmc_device 83

    • 10.2.7. mmc_init 83

    • 10.2.8. 总结 83

    • 10.2.9. struct mmc 84

    • 10.2.10.分离思想 84

    • 10.2.11.分层思想 84

    十一、uboot的移植1-从三星官方uboot开始移植 84

    • 11.1移植前的准备工作 84

    • 11.1.1.三星移植过的uboot源代码准备 85

    • 11.1.2. SourceInsight准备 85

    • 11.1.3.便捷的文件传输工具sshsecureshell 85

    • 11.2 ubuntu14.04上网及安装openssh 85

    • 11.2.1. ubuntu14.04上网问题 85

    • 11.2.2.搭建openssh环境 86

    • 11.3 移植初体验 86

    • 11.3.1.直接编译三星移植版uboot尝试运行 86

    • 11.3.2.代码分析&问题查找 86

    • 11.4时钟和DDR的配置移植 87

    • 11.4.1.确认时钟部分的配置 87

    • 11.4.2. DDR配置信息的更改 87

    • 11.5 将DDR端口0地址配置为30000000开头 87

    • 11.4.1. DDR初始化参数更改 87

    • 11.4.2. smdkv210single.h中相关宏定义修改 88

    • 11.4.3.虚拟地址映射表中相应修改 88

    • 11.4.4.修改DMC0的配置参数 88

    • 11.4.5.修改修改虚拟地址到物理地址的映射函数 89

    • 11.5 iNand驱动问题的解决 89

    • 11.5.1.先从现象出发定位问题 89

    • 11.5.2.网络搜索解决方案 89

    • 11.5.3.尝试修改代码解决问题 89

    • 11.5.4.推测和实验验证(SD卡和iNand的区别) 90

    • 11.6 一些小问题的修补 90

    • 11.6.1控制台串口更换为串口0 90

    • 11.6.2修改默认网络地址设置 90

    • 11.6.3修改行提示符 91

    • 11.6.1总结 91

    一、uboot学习前传

    1.1为什么要有uboot

    1.1.1.计算机的主要部件

    • (1)计算机系统就是由CPU来做核心进行运行的系统。典型的计算机系统有:PC机(台式机+笔记本)、嵌入式设备(手机、平板电脑、游戏机)、单片机(家用电器像电饭锅、空调)。

    • (2)计算机系统的组成部件非常多 ,不同计算机的组成部件也不同。但是所有的计算机系统运行时都需要的主要核心部件都是3个东西:CPU + 外部存储器(Flash/ 硬盘) + 内部存储器(DDR SDRAM/ SDRAM/ SRAM)。

    1.1.2 .PC机的启动过程

    • (1)典型的PC机的部署:BIOS程序部署在PC机主板上(随主板出厂时就已经预制了),操作系统部署在硬盘上,内存在掉电时无作用,CPU在掉电时不工作。

    • (2)启动过程:PC上电后先执行BIOS程序(实际上PC的BIOS保存在NorFlash),BIOS程序负责初始化DDR内存,负责初始化硬盘,然后从硬盘上将OS镜像读取到DDR中,然后跳转到DDR中去执行OS直到启动(OS启动后BIOS就无用了)。

    1.1.3.典型嵌入式linux系统启动过程

    • (1)嵌入式系统的部署和启动都是参考的PC机的。只是设备上有一些差别。

    • (2)典型嵌入式系统的部署:uboot程序部署在Flash(能作为启动设备的Flash上),OS部署在Flash(嵌入式系统中使用了Flash代替了硬盘),内存在掉电时无作用,CPU在掉电时不工作。

    • (3)启动过程:嵌入式系统上电后先执行uboot,然后ubbot负责初始化DDR、初始化Flash,然后将OS从Flash中读取到DDR中,然后启动OS(OS启动后uboot无用了)。

    总结:嵌入式系统和PC机的启动过程几乎没有两样,只是BIOS成了uboot,硬盘成了Flash。

    1.1.4. android系统启动过程

    • (1)android系统的启动和linux系统(前面讲的典型的嵌入式系统启动)几乎一样。几乎一样意思就是前面完全一样,只是在内核启动后加载根文件系统不同了。

    • (2)可以认为启动分为2个阶段:第一个阶段是uboot到OS启动;第二个阶段是OS启动后到rootfs加载到命令行执行;现在我们主要研究第一个阶段,android的启动和linux的差别在第二阶段。

    1.1.5.总结:uboot到底是干嘛的

    • (1)uboot主要作用是用来启动操作系统内核的。

    • (2)uboot还主要负责部署整个计算机系统。

    • (3)uboot中还有操作Flash等板子上硬盘的驱动。

    • (4)uboot还得提供一个命令行界面供人机交互。

    1.2 为什么是uboot

    1.2.1 .uboot从哪里来

    • (1)uboot是SourceForge上的开源项目

    • (2)uboot项目的作者:是由一个德国人最早发起的

    • (3)uboot就是由一个人发起,然后由整个网络上所有感兴趣的人共同维护发展而来的一个BootLoader

    1.2.2 .uboot的发展历史

    • (1)自己使用的小开源项目。

    • (2)被更多人认可使用

    • (3)被SoC厂商默认支持。总结:uboot经过多年发展,已经成为事实上的业内bootloader标准。现在大部分的嵌入式设备都会默认使用uboot来做为bootloader。

    1.2.3. uboot的版本号问题

    • (1)早期的uboot的版本号类似于这样:uboot1.3.4。后来版本号便成了类似于uboot-2010.06。

    • (2)uboot的核心部分几乎没怎么变化,越新的版本支持的开发板越多而已,对于一个老版本的芯片来说,新旧版本的uboot并没有差异。

    1.2.4. uboot的可移植性的正确理解

    • (1)uboot就是universal bootloader(通用的启动代码),通用的意思就是在各种地方都可以用。所以说uboot具有可移植性。

    • (2)uboot具有可移植性并不是说uboot在哪个开发板都可以随便用,而是说uboot具有在源代码级别的移植能力,可以针对多个开发板进行移植,移植后就可以在这个开发板上使用了。

    1.2.5.总结:时势造英雄,任何牛逼的东西都是时代的产物

    uboot的出现是一种必然,如果没有uboot也会有另一个bootloader来代替。

    1.3 uboot必须解决哪些问题

    1.3.1.能自身开机直接启动

    • (1)一般的SoC都支持多种方式启动,譬如SD卡启动、NorFlash启动、NandFlash启动等……  uboot要能够开机启动,必须根据具体的SoC的启动设计来设计uboot

    • (2)uboot必须进行和硬件相对应的代码级别的更改和移植,才能够保证可以从相应的启动介质启动。uboot中第一阶段的start.S文件就是具体处理了这一块。

    1.3.2.能引导操作系统内核启动并给内核传参

    • (1)uboot的终极目标就是启动内核

    • (2)linux内核在设计的时候,设计为可以被传参。也就是说我们可以在uboot中事先给linux内核准备一些启动参数放在内存中特定的位置然后传给内核,内核启动后会到这个特定的位置去取uboot传给它的参数,然后在内核中解析这些函数,这些函数将来被用来指导linux内核的启动过程。

    1.3.3.能提供系统部署功能

    • (1)uboot必须能够被人借助而完成整个系统(包括uboot、kernel、rootfs等的镜像)在Flash上的烧录下载工作。

    • (2)裸机中刷机就是利用uboot中的fastboot功能将各种镜像烧录到iNand中,然后从iNand启动。

    1.3.4.能进行SoC级和板级硬件管理

    • (1)uboot中实现了一部分硬件的控制能力(uboot中初始化了一部分硬件),因为uboot为了完成一些任务必须让这些硬件工作。譬如uboot要实现刷机必须能驱动iNand,譬如uboot要在刷机时LCD上显示进度条就必须能驱动LCD,譬如uboot能够通过串口提供操作界面就必须驱动串口,譬如uboot要实现网络功能就必须驱动网卡芯片。

    • (2)SoC级(譬如串口)就是SoC内部外设,板级就是SoC外面开发板上面的硬件(譬如 网卡、iNand)

    1.3.5.uboot的生命周期

    • (1)uboot的生命周期就是指:uboot什么时候开始运行,什么时候结束运行。

    • (2)uboot本质上是一个裸机程序(不是操作系统),一旦uboot开始SoC就会单纯运行uboot(意思就是uboot运行的时候别的程序是不可能同时运行的),一旦uboot结束运行则无法再回到uboot(所以uboot启动了内核后,uboot本身就死了,要想再次看到uboot界面只能重启系统。重启并不是复活了刚才的uboot,重启只是uboot的另一生)。

    • (3)uboot的入口和出口。uboot的入口就是开机自动启动,uboot的唯一出口就是启动内核。uboot还可以执行很多别的任务(譬如烧录系统),但是其他任务执行完后都可以回到uboot的命令行下继续执行uboot命令,而启动内核命令一旦执行就回不来了。

    总结 :一切都是为了启动内核。


    扫码或长按关注

    回复「 篮球的大肚子」进入技术群聊

    展开全文
  • Uboot Linux启动流程

    万次阅读 2014-04-07 19:58:43
    Uboot启动流程 第一阶段:关闭看门狗,设置系统时钟,初始化RAM,复制第二阶段的代码到内存中,设置好栈,跳转到第二阶段的C语言入口点。 第二阶段:检测内存映射,将内核映像要传给内核的参数从flash复制到内存中...

    Uboot启动流程

    第一阶段:关闭看门狗,设置系统时钟,初始化RAM,复制第二阶段的代码到内存中,设置好栈,跳转到第二阶段的C语言入口点。

    第二阶段:检测内存映射,将内核映像和要传给内核的参数从flash复制到内存中,,设置处理器为SVC模式,关闭MMU、缓存,调用theKernel函数,传入机器号和参数列表地址作为参数,跳转到内核在内存的地址,从而启动内核。


    Linux内核启动

    架构和开发板相关(汇编代码):

    1.检测是否支持该架构,__lookup_processor_type,检测是否支持该机器。

    2.建立一级页表,__creat_page_table

    3.关闭Cache,使能Mmu。

    4.复制数据段、清除BSS段、设置栈、保存机器ID到全局变量。

    4.start_kernel

    后续通用过程:

    setup_arch,初始化CPU子系统,之后让内存和进程管理系统就位,解析uboot传给内核的参数,接下来启动外部总线和外部设备,最后一步是激活用户空间的Init进程,Init进程执行必要的服务和用户空间的脚本,根据配置文件,决定启动哪些程序,如shell、桌面。



    展开全文
  • uboot启动linux的过程

    千次阅读 2018-09-19 17:05:58
     linux内核镜像常见到的有两种形式,zImageuImage。这两种文件的格式稍有差别,所以启动这两种格式的内核镜像也会有所不同。目前,uboot只支持启动uImage类型的镜像,对zImage还不支持(但是可以移植,TQ2440就是...

     

     

    转载地址:http://www.cnblogs.com/amanlikethis/p/3614594.html

     一、概述

      linux内核镜像常见到的有两种形式,zImage和uImage。这两种文件的格式稍有差别,所以启动这两种格式的内核镜像也会有所不同。目前,uboot只支持启动uImage类型的镜像,对zImage还不支持(但是可以移植,TQ2440就是这样做的)。

    二、uImage和zImage

    1、zImage

           zImage是用命令“#make zImage”生成的,我截取了生成信息最后部分的内容如下:

    复制代码

      OBJCOPY arch/arm/boot/Image
      Kernel: arch/arm/boot/Image is ready
      GZIP    arch/arm/boot/compressed/piggy.gz
      AS      arch/arm/boot/compressed/piggy.o
      LD      arch/arm/boot/compressed/vmlinux
      OBJCOPY arch/arm/boot/zImage
      Kernel: arch/arm/boot/zImage is ready

    复制代码

      从中可以看到,zImage是经过gzip压缩过的,所以在内核启动过程(不属于u-boot控制范围,在内核镜像的头部嵌有解压函数)中必然会对应一个解压过程。

    2、uImage

    (1) 生成方法

      uImage是u-boot专用的内核镜像,可用命令“#make uImage”生成。生成信息最后部分的内容如下:

    复制代码

      Kernel: arch/arm/boot/Image is ready
      Kernel: arch/arm/boot/zImage is ready
      UIMAGE  arch/arm/boot/uImage
    Image Name:   Linux-2.6.30.4-EmbedSky
    Created:      Thu Mar 20 19:53:32 2014
    Image Type:   ARM Linux Kernel Image (uncompressed)
    Data Size:    2314736 Bytes = 2260.48 kB = 2.21 MB
    Load Address: 0x30008000
    Entry Point:  0x30008000
      Image arch/arm/boot/uImage is ready

    复制代码

      事实上,uImage是调用mkimage(uboot制作的工具)这个工具生成的。

    复制代码

    root@daneiqi:/opt/EmbedSky#  mkimage -n 'linux-2.6.30' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -d zImage uImage
    Image Name:   linux-2.6.30
    Created:      Thu Mar 20 19:59:36 2014
    Image Type:   ARM Linux Kernel Image (uncompressed)
    Data Size:    2314736 Bytes = 2260.48 kB = 2.21 MB
    Load Address: 0x30008000
    Entry Point:  0x30008000

    复制代码

    (2)特点

      在原来的可执行映象文件zImage的前面加上一个0x40字节的头, 记录参数所指定的信息,这样uboot才能识别这个映象是针对哪个CPU体系结构的,哪个OS的, 哪种类型,加载内存中的哪个位置,入口点在内存的那个位置以及映象名是什么。

    (3)image_header

      头部的结构是在include/image.h中定义的,如下所示:

    复制代码

    typedef struct image_header {
           uint32_t  ih_magic;       /* Image Header Magic Number   */
           uint32_t  ih_hcrc;   /* Image Header CRC Checksum  */
           uint32_t  ih_time;  /* Image Creation Timestamp       */
           uint32_t  ih_size;   /* Image Data Size        */
           uint32_t  ih_load;   /* Data    Load  Address            */
           uint32_t  ih_ep;            /* Entry Point Address          */
           uint32_t  ih_dcrc;   /* Image Data CRC Checksum      */
           uint8_t           ih_os;             /* Operating System             */
           uint8_t           ih_arch;   /* CPU architecture              */
           uint8_t           ih_type;   /* Image Type               */
           uint8_t           ih_comp; /* Compression Type            */
           uint8_t           ih_name[IH_NMLEN];  /* Image Name             */
    } image_header_t;

    复制代码

      打开上边生成的uImage文件,可以看到对应的数据。

    (1)ih_magic    0x27051956  magic值,我觉得是uImage的头部开始值,根据这个值,判断是否是uImage

    (2)ih_crc    0x19dbf9c6    头部校验

    (3)ih_time   0x74295319   创建时间

    (4)ih_size   0x002351f0     镜像大小为2260.48KB

    (5)ih_load  0x30008000 内核加载地址

    (6)ih_ep        0x30008000 内核运行地址,“theKernel”指向该地址,说明这里藏着进入第一个函数--解压

    (7)ih_dcrc      0x38fc654e    内核校验

    (8)ih_os        0x05       #define IH_OS_LINUX  5 /* Linux */

    (9)ih_arch     0x02     #define IH_CPU_ARM  2 /* ARM  */

    (10)ih_type   0x02         #define IH_TYPE_KERNEL  2 /* OS Kernel Image  */

    (11)ih_comp  0x00        #define IH_COMP_NONE  0 /*  No  Compression Used */

    (12)ih_name         Linux_2.6.30.4-EmbedSky

    三、u-boot内核启动流程概述

      前文已经说明u-boot只支持uImage,步骤三、四都是针对uImage的。

      另外声明一点,步骤三四的测试uboot代码是韦东山视频提供的。

    1、从NandFlash中读取内核到RAM中

    2、在RAM中,给内核进行重定位

    3、给内核传递参数

    4、启动内核

    四、u-boot启动内核细节分析

    1、启动命令

    从环境变量中查看启动命令:

    2、从NandFlash中读取内核到RAM中

      nand read.jffs2 0x30007FC0 kernel

      此命令会激活(common/cmd_nand.c)中的do_nand函数,从而将nandflash上的kernel分区加载到0x30007fc0位置处。

    复制代码

    OpenJTAG> mtd
    
    device nand0 <nandflash0>, # parts = 4
     #: name                        size            offset          mask_flags
     0: bootloader          0x00040000      0x00000000      0
     1: params              0x00020000      0x00040000      0
     2: kernel              0x00200000      0x00060000      0
     3: root                0x0fda0000      0x00260000      0
    
    active partition: nand0,0 - (bootloader) 0x00040000 @ 0x00000000
    
    defaults:
    mtdids  : nand0=nandflash0
    mtdparts: mtdparts=nandflash0:256k@0(bootloader),128k(params),2m(kernel),-(root)

    复制代码

      从分区表中,可以看出kernel分区的起始地址是0x60000,大小是0x200000(2M),这条命令实际上等效于

    nand read.jffs2 0x30007FC0 0x60000 0x200000

      也可以使用命令

    nand read 0x30007FC0 0x60000 0x200000

      nand read.jffs2可以自动页对齐,所以大小可以是非页整的;如果使用nand read的大小必须是页对齐的。

    3、读取uImage头部

      bootm 0x30007fc0

      此命令会激活(common/cmd_bootm.c)中的do_bootm函数,从而开始执行

    2、在RAM中,给内核进行重定位
    3、给内核传递参数
    4、启动内核

    image_header_t header;  定义一个全局变量header,是读取头部的缓冲区

    addr = simple_strtoul(argv[1], NULL, 16);  定位头部地址,将字符串“0x30007fc0”转化为整型

    printf ("## Booting image at %08lx ...\n", addr); 显示从哪儿启动

    memmove (&header, (char *)addr, sizeof(image_header_t)); 读取头部到header变量中

    4、判断当前的内存区是否是uImage的开始位置

    复制代码

     if (ntohl(hdr->ih_magic) != IH_MAGIC) {
          {
      puts ("Bad Magic Number\n");
      SHOW_BOOT_PROGRESS (-1);
      return 1;
         }
     }

    复制代码

    注意到:

    #define IH_MAGIC 0x27051956 /* Image Magic Number  */(include/image.h)

    5、校验头部

    复制代码

        data = (ulong)&header;
        len  = sizeof(image_header_t);
    
        checksum = ntohl(hdr->ih_hcrc);
        hdr->ih_hcrc = 0;
    
        if (crc32 (0, (uchar *)data, len) != checksum) {
            puts ("Bad Header Checksum\n");
            SHOW_BOOT_PROGRESS (-2);
            return 1;
        }

    复制代码

    6、打印头部信息

        /* for multi-file images we need the data part, too */
        print_image_hdr ((image_header_t *)addr);

    7、核查内核数据

    复制代码

        data = addr + sizeof(image_header_t);
        len  = ntohl(hdr->ih_size);
    
        if (verify) {
            puts ("   Verifying Checksum ... ");
            if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) {
                printf ("Bad Data CRC\n");
                SHOW_BOOT_PROGRESS (-3);
                return 1;
            }
            puts ("OK\n");
        }
        SHOW_BOOT_PROGRESS (4);

    复制代码

      注意到data已经跳过了uImage的头部,指向了真正的内核首部,也即0x30008000。

    8、核查架构、内核类型、压缩类型等信息,其中会涉及到重定位

     View Code

      在这部分代码中,有这么一部分关于压缩类型的:

    复制代码

        switch (hdr->ih_comp) {
        case IH_COMP_NONE:
            if(ntohl(hdr->ih_load) == data) {
                printf ("   XIP %s ... ", name);
            } else {
    #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
                size_t l = len;
                void *to = (void *)ntohl(hdr->ih_load);
                void *from = (void *)data;
    
                printf ("   Loading %s ... ", name);
    
                while (l > 0) {
                    size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;
                    WATCHDOG_RESET();
                    memmove (to, from, tail);
                    to += tail;
                    from += tail;
                    l -= tail;
                }
    #else    /* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) */
                memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
    #endif    /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */
            }
            break;

    复制代码

      可以看到,u-boot会判断当前去除uImage头部内核代码所处的位置(7步骤已经说明地址是data)是否与编译时安排的重定位位置(hdr->ih_load)一致。

      如果一致,就打印一句话。

      如果不一致,则需要调用 memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);进行内核的重定位,要知道它有2M多的大小,会花费一些时间。尽量使读取内核的时候,就读取到hdr->ih_load-64的位置上,这样就不必再搬运一次。

    9、根据操作系统类型,启动对应的操作系统

    复制代码

        switch (hdr->ih_os) {
        default:            /* handled by (original) Linux case */
        case IH_OS_LINUX:
    #ifdef CONFIG_SILENT_CONSOLE
            fixup_silent_linux();
    #endif
            do_bootm_linux  (cmdtp, flag, argc, argv,
                     addr, len_ptr, verify);
            break;
        case IH_OS_NETBSD:   

    复制代码

    10、执行do_bootm_linux,继续启动linux系统

      此函数在lib_arm/armlinux.c中

    复制代码

        void (*theKernel)(int zero, int arch, uint params);
        image_header_t *hdr = &header;
        bd_t *bd = gd->bd;
    
    #ifdef CONFIG_CMDLINE_TAG
        char *commandline = getenv ("bootargs");
    #endif
    
        theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);

    复制代码

      可见,已经将内核运行的首地址赋给了theKernel函数指针变量,将来可以利用这个变量调用进入内核的函数。

      另外,在进入内核之前,要给内核传递参数。方法是将参数以一定的结构放在内存指定的位置上,将来内核从该地址读取数据即可。

      命令行的启动参数存储在以bootargs命名的对象里,值为

    bootargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0

      告诉内核,启动后的根文件系统位于mtd的哪个区,初始进程,以及控制台

    11、判断是否是一个ramdisk或者multi镜像

     View Code

    12、给内核传递参数

    复制代码

    #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
        defined (CONFIG_CMDLINE_TAG) || \
        defined (CONFIG_INITRD_TAG) || \
        defined (CONFIG_SERIAL_TAG) || \
        defined (CONFIG_REVISION_TAG) || \
        defined (CONFIG_LCD) || \
        defined (CONFIG_VFD)
        setup_start_tag (bd);
    #ifdef CONFIG_SERIAL_TAG
        setup_serial_tag (&params);
    #endif
    #ifdef CONFIG_REVISION_TAG
        setup_revision_tag (&params);
    #endif
    #ifdef CONFIG_SETUP_MEMORY_TAGS
        setup_memory_tags (bd);
    #endif
    #ifdef CONFIG_CMDLINE_TAG
        setup_commandline_tag (bd, commandline);
    #endif
    #ifdef CONFIG_INITRD_TAG
        if (initrd_start && initrd_end)
            setup_initrd_tag (bd, initrd_start, initrd_end);
    #endif
    #if defined (CONFIG_VFD) || defined (CONFIG_LCD)
        setup_videolfb_tag ((gd_t *) gd);
    #endif
        setup_end_tag (bd);
    #endif

    复制代码

      比较重要的函数有:

       setup_start_tag (bd);

      setup_memory_tags (bd);

      setup_commandline_tag (bd, commandline);

      setup_end_tag (bd);

      其中 bd->bi_boot_params(参考uboot全局变量),bi_boot_params=>>0x30000100,启动参数存放的位置。

    13、启动内核

        printf ("\nStarting kernel ...\n\n");
      theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

      把机器码以及启动参数存放的位置都告诉给内核。

    五、启动过程展示

    1、不需要重定位启动

    2、重定位启动

          下例中读取到的位置,不是合适的位置,内核的入口不是0x30008000,所以还要对内核进行重定位,也就是将内核搬移到指定的位置。

    六、u-boot启动zImage

     1、直接启动zImage

      既然,zImage是uImage去除头部的部分,那么可以从0x30008000直接启动zImage,我们用go命令去执行。

    可见,内核的第一个函数果然是解压函数。但是程序卡到图片最后的位置,不能继续执行。

      原因是由于没有给内核传递启动参数,也就是说在执行函数theKernel之前,没有做好准备

    void (*theKernel)(int zero, int arch, uint params);

    2、移植u-boot支持启动zImage

      具体代码可看TQ2440开发板的u-boot代码。

      再来看一下启动大纲:

    复制代码

    1、从NandFlash中读取内核到RAM中
    
    2、在RAM中,给内核进行重定位
    
    3、给内核传递参数
    
    4、启动内核

    复制代码

      可以直接从nandflash中将内核zImage读取到内存0x30008000位置处,然后在0x30000100位置处传递参数

    也就是调用函数 

    setup_start_tag (bd);
    setup_memory_tags (bd);
    setup_commandline_tag (bd, commandline);
    setup_end_tag (bd);

      最后,调用theKernel函数启动内核。

     

    参考资料:韦东山u-boot启动内核视频

    展开全文
  • u-boot启动后会运行液晶初始化程序并显示启动LOGO,但进入linux系统之后,又重新初始化一次,而且ubootlinux定义的显存地址也不一致,导致会有短暂的白屏闪烁。此补丁解决从ubootlinux启动完成一直保持LOGO不变...
  • 从学嵌入式以来,还没有真正意义上的进行过ubootLinux内核的移植,于是为了满足自己的好奇心探索精神,打算将最新的uboot和Linux内核移植到开发板上,最近移植也接近了尾声,因此打算开一个深坑:写一篇较为完整...
  • 向Flash中烧写uboot和linux操作系统 2011年03月28日  向Flash中烧写uboot和linux操作系统  ================================================================================  from:...
  • 操作系统内核本身就是一个裸机程序,我们学的uboot和其他裸机程序没有本质的区别区别就是我们操作系统运行起来后可以分为应用层内核层,分层后,两层的权限不同,内存访问设备操作的管理上...
  • 一、从 EMMC 启动 Linux 系统 1、将zImage 文件设备树文件烧录到EMMC中 2、使用以下检查一下 EMMC 的分区 1 中有没有zImage 文件设备树文件。 ls mmc 1:1 3、设置环境变量 环境变量bootcmd: 1、...
  • 今天突然找到一种下载NXP原厂修改的高版本Linux和uboot源码的地方,特地记录一下。 uboot 先从uboot下载开始说起,首先是uboot下载地址,可以点击此处访问uboot。当进入网站以后会看到如下图片: 首先下载uboot整个...
  • imx6 从ubootlinux logo显示不间断 补丁,解决闪屏问题
  • Uboot启动linux内核是使用bootz命令,bootz是如何启动linux内核?uboot的生命周期是怎么终止的?linux是如何启动? 启动linux内核的时候都会用到一个重要的局部变量:images,images在文件cmd/bootm.c中有定义。 ...
  • 韩大卫@吉林师范大学 2015.1.27....uboot 和linux 下flash 的写入速度不一样, 主要原因是两者使用的延迟最小延时时间不一样. linux比较大. 原因如下: flash 芯片手册中有两个重要的时间参数:
  • ubootlinux传递参数流程

    千次阅读 2013-07-30 11:52:42
    是用mindmanager转的,格式有点不太好。 1 ATAG 1.1 为什么用ATAG  uboot用atag向kernel传递信息: ...中找到,对应linux中的定义位于arch/arm/include/asm/setup.h中。两者的定义要相同。  参数链表必须
  • 手把手教你移植Linux内核,详细介绍啦S5PV210 嵌入式开发环境的搭建,uboot 源码移植详细步骤,Linux系统移植的详细步骤。
  • 这个资料有开发板修改后的uboot和linux、imx6ul芯片资料包、原理图。uboot和linux基于官方的开发进行针对性修改。
  • LinuxUboot详解

    千次阅读 2016-03-30 15:40:56
    在专用的嵌入式板子运行 GNU/Linux 系统已经变得越来越流行。一个嵌入式 Linux 系统从软件的角度看通常可以分为四个层次: 1. 引导加载程序。包括固化在固件(firmware)中的 boot 代码(可选), Boot Loader 两...
  • uboot和linux的编译

    2014-08-27 22:32:42
    1.uboot的编译 cd u-boot-1.1.6/ 进入目录 make 100ask24x0_config 配置 make 编译
1 2 3 4 5 ... 20
收藏数 26,891
精华内容 10,756
关键字:

uboot和linux平台区别