这篇文章是一个读者昨晚发给我的,文章很长,里面的细节也比较多,但是微信公众号只能发 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
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命令,而启动内核命令一旦执行就回不来了。
总结 :一切都是为了启动内核。
扫码或长按关注
回复「 篮球的大肚子」进入技术群聊