【笔记】嵌入式uboot认识part1_外围知识

2019-07-12 17:44发布

整体简介

本笔记为记录嵌入式Linux的uboot部分基础知识,结合源码对uboot的实现原理和应用展开学习 授课老师:朱有鹏
记录少女:宕机酱=v=
2017.03 本part讲uboot的使用和相关概念。
后面会讲uboot的设计和组成原理,再往后就是移植过程。
我们的目的就是把ARM端的操作系统搭建起来,以后呢,就不玩裸机了喂。

笔记正文

一、学习前传

1.1为什么要有uboot

uboot是用来 启动操作系统内核 的!还有别的辅助功能。
1启动操作系统内核
2部署计算机系统
3操作Flash等上硬盘驱动
4提供命令行界面 uboot类似于PC机系统中的BIOS设计。典型的嵌入式系统的部署是uboot在一块支持启动的Flash上,OS部署在Flash(通常是另一块Flash,NandFlash or iNand,慢慢会发展成一块儿)。 其中,环境变量和命令是uboot的重要部分。此外uboot对于Flash和DDR有管理功能。 启动过程
step1: 先执行uboot
step2: uboot初始化DDR,初始化Flash
step3: 将OS从Flash读取到DDR中,启动OS。启动完成后uboot就无用了。 总结:嵌入式系统启动其实和PC没两样
只是BIOS代替成uboot
硬盘替换成了Flash

1.2 uboot之发展历史

uboot经过多年发展,已经成为事实上业内的bootloader标准。 uboot的版本号问题
早期的uboot版本号类似于: uboot1.3.4 //这个1.3.4是最后的老版本 从2008左右开始就不是这样子了,后来变成了类似于: uboot-2010-06 (后缀带有 -rc 的是非正式版本) 核心部分就几乎没变化,越新版本支持的开发板越多。当然也不是越新越好,新的东西有很多冗余。 uboot可移植理解
universal bootloader(通用的启动代码),具有可移植性。
注意:并不是说在哪个开发板都可以随便用。而是具有在源代码级别的移植能力。如果没有移植的话就可以直接用的。代码必然是要修改的!不是下载下来就能用。 uboot的成功:时势造英雄,他的出现是一种必然。如果没有uboot也会有另一个bootloader代替。
在那个年代嵌入式疯狂的发展,很需要一种bootloader能够移植上去,启动操作系统。所以uboot站出来了

1.4 uboot工作方式

uboot是一个单线程裸机程序。一旦运行uboot就不能运行别的 程序。
入口是开机自动启动
出口是唯一出口,启动内核 内核启动之后,uboot就会结束,而且不再重生。除非下一次开机。
uboot没有运行时表现为uboot.bin,放在存储介质里,运行时被加载入内存,逐步执行。

1.5 常用命令

uboot的命令和环境变量机制几乎和OS完全一样,连题目的名称都不带变的。 命令使用行缓冲。 //linux缓冲方式还有无缓冲和全缓冲 简写命令: printenv = print //打印环境变量 setenv = set //设置环境变量 注意:自己尝试过,pri就能自己打印出printenv的内容 命令族 有些命令有衍生的 多个命令 如 movi movi init,movi read等。命令一样,参数不一样。 环境变量和全局变量的不同
环境变量生命周期长,他存储在FLash的一块专门区域。而全局变量在程序结束后消亡。 理论上讲,环境变量在更改后,下一次开机依然保留才对,但是我试过的和老朱说的不一样。
是因为我们没有保存!命令:save/saveenv
我们操作的环境变量的是DDR中的环境变量,
DDR断电不保存,save命令是就把运行时内存中的环境变量写回Flash 注意这里的 save,会让原来的Flash中环境变量完全重写。

Flash里面有好多分区

完整Linux系统分区简表(按顺序,uboot为最开始) 序号 分区名 简写名 1 uboot uboot 2 环境变量 env 3 操作系统内核 kernel 4 根文件系统 rootfs

1.9 uboot指令

指令规范
movi read {aaa | bbb} [xxxx]
//movi read 是必填,{ }里面的内容多选一,[ ]的内容是选填 uboot默认数字问题
命令行中,uboot中所有的数字都会被当做16进制处理!!
uboot中没有默认十进制的。uboot中出现数字90%的情况都是地址,是有意义的。 【movi read】
movi read u-boot 0x30000000
//将iNand中的u-boot分区读到DDR的0x30000000处,注意读的是分区
//也许uboot本身不大,但分区有1M那么这里还是读1M大小过去
//在uboot代码中,iNand被分成了很多个分区,每个分区都有独自的地址和名称。
movi read {sector#} {byte(hex)} {addr}
//sector是扇区,读某扇区多少字节,读到哪个地址。 【nand】
//完全类似movi,操作NandFlash 【内存操作指令:mm mw md】
内存是没有分区的,我们要注意防止越界,越界会踩到别人。操作系统中不容易越界,但uboot是裸机程序,因此我们使用uboot时不注意,就可能发生自己把自己数据给覆盖了的问题。
我们之前usb下载放在0x23E00000地址处就是放在了一个低地址。(也和虚拟地址映射有关) md,memory display
mw,写内存,一般用的很少
mm,批量写内存 【启动内核指令:bootm, go】
bootm是能够传参的,他其实是正宗的启动命令 go不能传参,他本身不是为了启动内核用的,内部就是吧pc跳转到一个内存地址去执行。
go可以在uboot中执行任何的裸机程序
有一种调试裸机程序的方法就是事先启动uboot,然后再uboot中下载裸机程序 ,用go命令执行裸机程序。

1.10 uboot常用环境变量

ipaddr:开发板ip地址
serverip:tftp服务器的ip地址
gatewayip:开发板的本地网关地址
ethaddr:开发板本地网卡的MAC地址。 Tips:重装系统为什么MAC地址会变?是因为驱动重新安装了 启动内核的最关键环境变量
bootcmd(重要)自动运行命令设置
uboot启动后会倒数秒数,如果没有人按下回车键打断则会启动内核
这个 启动内核的 功能其实内部就是执行了bootcmd 查一下: bootcmd=movi read kernel 30008000 //读iNand中内核分区到30008000
movi read rootfs 30B00000 300000; //读根文件系统
bootm 30008000 30B00000 //启动内核和根文件系统
//iNand,可以简单的看成SD卡或MMC卡芯片化 bootargs(重要)
bootargs是uboot给kernel传参用的。linux内核与uboot有约定好的参数。这样的设计是为了灵活,为了内核在不重新编译的条件下以不同方式启动。 bootargs=console=ttySAC2,115200 //控制台使用SAC2,即串口2,波特率115200 root=/dev/mmcblk0p2 rw //rootfs使用mmc,block端口0,第二分区 //rw表示可读可写 init=/linuxrc //linux的进程1(init进程)的路径 rootfstype=ext3 //rootfs类型,ext3是一种文件系统类型。 内核传参是非常重要的,新手经常忘记和内核传参,或者传参不对,造成内核启动失败。 【新建、删除环境变量】 set var value //新建、更改 set var //删除

1.12.uboot中对Flash和DDR的管理

uboot对Flash和内存进行分区。 分区方法不是一定的,不是固定的,是可以变动的。但是在一个移植中必须事先设计好定死,一般在设计系统移植时就会定好,定的标准是: uboot:uboot必须从Flash起始地址开始存放(也许是扇区0,也许是扇区1,也许是其他,取决于SoC的启动设计),uboot分区的大小必须保证uboot肯定能放下,一般设计为512KB或者1MB(因为一般uboot肯定不足512KB,给再大其实也可以工作,但是浪费); 环境变量:环境变量分区一般紧贴着uboot来存放,大小为32KB或者更多一点。 kernel:kernel可以紧贴环境变量存放,大小一般为3MB或5MB或其他。 rootfs:rootfsl可以紧贴kernel存放 再往后面:则是自由分区。 总结:一般规律如下:
(1)各分区彼此相连,前面一个分区的结尾就是后一个分区的开头。
(2)整个flash充分利用,从开头到结尾。
(3)uboot必须在Flash开头,其他分区相对位置是可变的。
(4)各分区的大小由系统移植工程师自己来定,一般定为合适大小(不能太小,太小了容易溢出;不能太大,太大了浪费空间)
(5)分区在系统移植前确定好,在uboot中和kernel中使用同一个分区表。将来在系统部署时和系统代码中的分区方法也必须一样。

12.2、uboot阶段DDR的分区

(1)DDR的分区和Flash的分区不同,因为Flash是掉电存在的,而DDR是掉电消失,因此可以说DDR是每次系统运行时才开始部署使用的。
(2)内存的分区主要是在linux内核启动起来之前,linux内核启动后内核的内存管理模块会接管整个内存空间,那时候就不用我们来管了。
(3)注意内存分区关键就在于内存中哪一块用来干什么必须分配好,以避免各个不同功能使用了同一块内存造成的互相踩踏。譬如说我们tftp 0x23E00000 zImage去下载zImage到内存的0x23E00000处就会出错,因为这个内存处实际是uboot的镜像所在。这样下载会导致下载的zImage把内存中的uboot给冲掉。

2.1.shell介绍

shell是操作系统的终端命令行
系统提供给用户操作的命令行界面,是人机交互的一种方式
shell用来干什么?
在linux下创建100个文件,分别为a1.c a2.c…..a100.c。最好的做法就是把创建过程写成一 个shell脚本程序。 shell是一类编程语言,而不是一个语言。
shell语言,又叫脚本语言。常用shell语言:sh、bash、csh、ksh、perl、python等 perl、python等高级shell语言,常用在网络管理配置等领域,系统运维人员一般要学习这些。
脚本语言一般在嵌入式中应用,主要是用来做配置。
linux下最常用的脚本就是bash,我们学习也是以bash为主。 shell脚本的运行机制:解释运行
C语言(C++)这种编写过程是:编写出源代码(源代码是不能直接运行的)然后编译链接形成可执行二进制程序,然后才能运行;脚本程序编写好后源代码即可直接运行(没有编译链接过程)
所谓解释运行就是说当我们执行一个shell程序时,shell解析器会逐行的解释shell程序代码,然后一行一行的去运行。
CPU实际只认识二进制代码,根本不认识源代码。脚本程序源代码其实也不是二进制代码,CPU也不认识,也不能直接执行。【shell程序的编译链接过程不是以脚本程序源代码为单位进行的,而是在脚本运行过程中逐行的解释执行时完成二进制转化,进而无需编译链接,而是调用他。】
2.2.动手写第一个shell 编辑器 vim 编译器 无 运行方法如下 第一种:./xx.sh,这样运行shell要求shell程序必须具有可执行权限。 第二种:source xx.sh,source是linux的执行脚本程序命令。不需要脚本具有可执行权限。 第三种:bash xx.sh,bash是一个脚本程序解释器,本质上是一个可执行程序。这样执行相当于我们执行了bash程序,然后把xx.sh作为argv[1]传给他运行。 shell程序的第一行一般都是: #!/bin/sh 指定shell程序执行时被哪个解释器解释执行 可以将第一行写为:#!/bin/bash来指定使用bash执行该脚本。 注意:在ubuntu上面默认使用的默认脚本解释器sh其实不是bash,而是dash! 脚本中的注释使用#,例如“#same as ‘//’ ”,和C语言的//是一样的

2.3.shell编程学习1

shell中的变量定义和引用
shell是弱类型语言(语言中的变量如果有明确的类型则属于强类型语言)
和C语言不同。在shell编程中定义变量不需要制定类型,也没有类型这个概念。 变量定义时可以初始化,使用=进行初始化赋值。在shell中赋值的=两边是不能有空格的
注意:shell对语法非常在意,非常严格。很多地方空格都是必须没有或者必须有,而且不能随意有没有空格。 变量引用
shell中引用一个变量必须使用符号就是变量解引用符号。
注意:$符号后面跟一个字符串,这个字符串就会被当作变量去解析。如果这个字符串本身没有定义,执行时并不会报错,而是把这个变量解析为空。 注意:变量引用的时候可以var{var}。这两种的区别是在某些情况下只能用varvar。var{var}是肯定能用的。
什么情况下$var是不能用的呢?
eg: var="hello" echo "$varyou" 则打印不出东西,因为找不到varyou这个变量 正确写法: echo "${var}you" 打印出:helloyou 变量定义、初始化 string="hello world" echo $string 如果echo string(不加$),那么解释器就会将string当成一个新的变量,打印一个string出来。 单引号:完全字面替换 ‘23"33’ 就会打印出23"33 双引号: $加变量名可以取变量的值 $表示$的字面值 输出$符号 `表示`的字面值 "表示"的字面值 \表示的字面值 示例 打印结果 echo new string new string echo 'new "string' new "string echo "new "string" new "string echo "$string" hello world
PWD=`pwd` echo $PWD //打印命令pwd的返回值。返回当前路径 反引号括起来执行。有时候我们在shell中调用linux命令是为了得到这个命令的返回值(结果值),这时候就适合用一对反引号(键盘上ESC按键下面的那个按键,和~在一个按键上)来调用执行命令。 shell中的分支结构
if语法很多,只介绍重要部分。 典型if语言格式。 if [表达式]; then xxx else xxx fi 判断文件是否存在。(-f),注意[]里面前后都有空格,不能省略。 file
判断目录是否存在 (-d) diractory
判断字符串是否相等(”str1” = “str2”),注意用一个等号而不是两个
判断数字是否相等(-eq)、大于(-gt)、小于(-lt)、大于等于(-ge)、小于等于(-le)
while [ $# -gt 0 ] ; do
判断式中使用“-o”表示逻辑或 if [ -f a.c ]; then ehco yes 【注意】:[ -f a.c ]
-f前面有空格!!!
a.c后面有空格!!! 不写空格会报错 if [ 12 - eq 12 -o "abcd" = "abcd" ]; then ehco "yes" else ... fi 逻辑&&和逻辑||在shell中的独特用法
话说&& 和 || 在shell中也有,出现在shell中简写的if表达式:没有if,只有中括号 [ -z $str ] || echo "233" //str如果为空,就不显示233;如果不为空则显示233

2.5.shell中的循环结构

for循环 能看懂、能改即可。不要求能够完全不参考写出来 for i in 1 2 3 4 5 do echo $i done //循环打印12345。1 2 3 4 5,这里的数字是我们遍历的集合,没有边界,不需要用()、[]和{} for i in `ls` #当前目录文件名的集合 do echo $i done while循环 (1)和C语言的循环在逻辑上无差别。while后面的[]两边都有空格。i++的写法中有两层括号。 i=1 j=11 while [ $i -lt $j ]; do echo $i i=$(($i + 1)) #这是C语言里面的 i++,看起来有点怪异。 +两边可以有空格 done 打印信息传入一个文件 echo "start" > a.txt //创建一个a.txt,把start写进去 i=1 j=11 while [ $i -lt $j ]; do echo $i >> a.txt #追加$i的内容,写入已经存在的a.txt里面末尾去。 i=$(($i + 1)) done 打印1到10开始,大于8和等于4 的数 #!/bin/sh str="deep" str="打印出的是:" i=0 touch test.txti while [ $i -lt 10 -o $i -eq 10 ]; do if [ $i -eq 4 -o $i -gt 8 ]; then echo $str$i >> test.txt fi i=$(($i + 1)) done
case的用法 var=1 case var in 1) echo "1" ;; 2) echo "2" ;; esac bash中的传参 $# 传参个数,注意只考虑真正的参数个数。 $1 $2 $3 参数 eg echo $# $0 $1 $2 sh a.sh aa bb cc 执行sh :# = 3。0是执行shell的应用程序名字,如bash break跳出在shell中不是用于case的,而是跳出循环的。(因为case是不用break的)
C语言的argv是 只读的,是不可改的。而在shell中,$1是可以用shift改的。 echo $# $1 shift; echo $# $1 上例中输入source a.sh aa bb cc
打印
3 aa
2 bb
可见shift有点像左移运算符。把shell的传参左移了一个移出去。原来的21。

2.7 Makefile

kernel 的 本质是C语言的项目,由很多个文件组成,因此都需要Makefile的管理。
分析uboot必须对Makefile有所了解 目标、依赖、命令是Makefile中的三个最主要的成分 目标是我们要去make xxx的那个,是最后生成的东西
依赖是用来生成目标的原材料。
命令就是对原材料的加工方法。 %通配符 和 自动推导 示例:ARM裸机中的makefile led.bin: start.o //要生成bin,但当前没有led.o,看规则 arm-linux-ld -Ttext 0x0 -o led.elf $^ arm-linux-objcopy -O binary led.elf led.bin arm-linux-objdump -D led.elf > led_elf.dis gcc mkv210_image.c -o mkx210 ./mkx210 led.bin 210.bin %.o : %.S //规则:做自动推导。 //%是通配符,代表一个或几个字母 //%.o代表所有以 .o 结尾的文件 //要%.o,就需要依赖%.S。然后就回去找%.S arm-linux-gcc -o $@ $< -c -nostdlib %.o : %.c arm-linux-gcc -o $@ $< -c -nostdlib clean: //伪目标,无依赖,无条件执行 rm *.o *.elf *.bin *.dis mkx210 -f Makefile知道要得到什么,需要先得到什么,他会自己一步一步去推导。还是挺聪明的。
自动推导就是把目标文件往规则上套,如果找到了就生成。 @<: 规则的依赖文件名
$^: 依赖的文件集合 makefile 定义和使用变量
类似shell,没有变量类型,引用时候用 $var 伪目标(.PHONY)
伪目标本身不代表一个文件,而是单纯的执行命令。不生成文件或得到某个东西。
伪目标没有依赖。
为了明确声明这是伪目标,一般会在前面加一个
eg: .PHONY clean //声明伪目标 clean: rm *.o *.elf *.bin *.dis mkx210 -f 【makefile的引用】
有时候makefile总体比较复杂,因此makefile有时候 会引用其他makefile
include,和C语言一样,也是原地展开。
例如uboot中有一个:
include $(obj)include/config.mk 【makefile条件语句】 ifeq ($(xxx),var) xxx = 1 endif
2.8 Makefile 补充学习 【注释用#】
【@命令:静默执行。】 示例:不使用静默执行 all: echo "helloworld" 打印信息:
echo “helloworld”
helloworld 可见:makefile是默认打印命令的。如果不想看到命令本身,只想看到执行,那么静默执行即可。 all: @echo "helloworld" 变量赋值运算符 (1)= 最简单的赋值 //他的值取决于最后一次赋值时的值 (2):= 一般也是赋值 //就地直接解析 以上这两个大部分情况下效果是一样的,但是有时候不一样。 用=赋值的变量,取决于最后一次赋值时的值,不能只往前面看,还要往后面看。 用:=来赋值的,则是就地直接解析,只用往前看即可。 (3)?= 如果变量未定义则执行这条赋值,若定义了则本行被忽略。【注意空值也算赋值过】 (4)+= 用来给一个已经赋值的变量接续赋值,意思就是把这次的值加到原来的值的后面,有点类似于strcat。(在shell makefile等文件中,可以认为所有变量都是字符串,+=就相当于给字符串stcat接续内容)(注意一个细节,+=续接的内容和原来的内容之间会自动加一个空格隔开) 注意:Makefile中并不要求赋值运算符两边一定要有空格或者无空格,这一点比shell的格式要求要松一些。 重点:关于=和:= eg: A=ABC B=$(A)DEF A=GH all: echo $(B) 结果:GHDEF 说明猜测是正确的。A=ABC要看最后一次A是什么。在被解析时取决最后一次!! 【关于uboot中的makefile】
一共3000多行,真正有意义的差不多就是470行。用=赋值的变量在uboot中真不好分析。
我们能看懂就行了,但是这个=没:=安全。
对于安全的代码做到什么程度呢?其实想保留B赋值A的原始值,只需要B用:=即可 A=ABC B:=$(A)DEF A=GH all: echo $(B) 这种情况打印出的值就是 ABCDEF 【makefile 的环境变量】
用export导出的就是环境变量。一般情况下要求环境变量名用大写,普通变量名用小写。 环境变量 类似于整个工程中所有Makefile之间可以共享的全局变量 普通变量 只是当前本Makefile中使用的局部变量 注意定义环境变量可能会影响一个工程中的其他makefile,因此要小心。 有一些环境变量可能是makefile本身自己定义的内部的环境变量 这就好像C语言中编译器预定义的宏__LINE__ __FUNCTION__等一样。 有一些环境变量可能是当前的执行环境提供的环境变量
譬如我们在make执行时给makefile传参。 make CC=arm-linux-gcc 这里给当前Makefile传了一个环境变量CC,值是arm-linux-gcc。用make传参优先级最高。 CC =arm-linux-gcc //普通变量 export CC //导出。变成环境变量 关于make给环境变量传参 CC =gcc all: echo $(CC) 1 make打印结果:gcc
2 make CC=arm-linux-gcc 打印结果:arm-linux-gcc (覆盖前环境变量值)

makefile常见通配符

* 若干个任意字符 ? 1个任意字符 [] 将[]中的字符依次去和外面的结合匹配 % 也是通配符,表示任意多个字符,和*很相似,但是%一般只用于规则描述中,又叫做规则通配符。 all :1.c 2.c 12.c test.h echo *.c echo ?.c echo [12].c #中括号内的字符依次去外面去匹配 打印
1.c 2.c 12.c
1.c 2.c
1.c 2.c 【自动变量】
自动变量的含义:预定义的特殊意义的符号。就类似于C语言编译器中预制的那些宏FILE一样。 文件集合中文件非常多,描述的时候很麻烦。 @<、$^ 就是典型自动变量 led.bin: start.o arm-linux-ld -Ttext 0x0 -o led.elf $^ #$^代表start.o %.o : %.c arm-linux-gcc -o $@ $< -c -nostdlib #$@代表.o文件 #$<代表.c文件 常见自动变量:
@< 规则的依赖文件名
$^ 依赖的文件集合 all :1.c 2.c 12.c test.h echo $@ echo $< echo $^ 打印结果:
all
1.c
1.c 2.c 12.c test.h 【关于<<代表第一个依赖
在规则中$<代表的是所有的依赖!

3.1 uboot实践

【关于tar】 tar -jxvf //解压 tar -cjx //打包 bsp是板级支持包
选用的uboot是 B盘 linux/qt4.8/bsp
uboot在任意文件夹下解压,tar -jxvf qt_x210v3.tar.bz2 注意uboot和linux kernel等复杂项目都不能直接编译,需要事先配置。 进入uboot的根目录 执行:make x210_sd_config。 //执行了就配置完了 编译得到uboot.bin
编译前要注意:
1 一定要检查arm-linux-gcc,我们用的是arm-2009q3。
2 还有注意makefile中关于交叉编译工具链的设置:
(第147行) CROSS_COMPILE = 。。。
要保证这一行的交叉编译工具路径和我们的工具链路径一致,否则不能工作
我们放置在/usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi
我自己防止/usr/local/arm/arm-2009q3/bin,路径相同
以上做完之后即可编译 make //多线程编译(4核心编译) du -h u-boot.bin //查看编译生成的uboot.bin大小,视频中是384KB
uboot分uboot官方、SoC级uboot和开发板uboot
smdkv210是三星官方制定的开发板,昂贵且庞大。 三星的uboot有68个对象,九鼎有31个,可以说九鼎包括的功能是三星的子集 gitignore 版本管理的 config.mk arm_config.mk 某个makefile中调用的 COPYING 版权声明,GPL许可,即开源项目 credit 鸣谢 image_split 分割uboot到 BL1的 Makefile ! 很重要,主makefile,我们就是用这个mkfile编译的 mkconfig ! 很重要,uboot的可移植性就是通过此配置脚本维护的 rules.mk 很重要,但不学习他 ./mk 快速编译:先清理再设置后编译 mkmovi SD卡启动相关 文件夹 api. 硬件无关的api,是uboot本身使用的,移植不用管 common 【重要】硬件无关。普遍适用代码。环境变量和命令系统。 board 【重要】子文件夹非常多,每一个文件夹代表一个支持的开发板 这么多文件夹还能找到,要归功于配置过程。配置就是定要用于哪个文件夹 【配置】说白了配置就是确定路径,这个路径的确定过程保证了可移植。 【历史】以前是board下存放芯片型号,后来太多了就改成了厂家目录。但为了向前兼容, 还是把以前放在外面的芯片没有动。因为挪了位置很可能就不能用了。 smdkc110:是遗留问题。uboot中的borad下没有s5pv210是因为c110先出的,服务于手 机。c110和s5pv210有99%的相似度。 cpu 【重要】与SoC有关,初始化和控制代码 drivers 【重要】linux中抠出来 的驱动。如网卡、iNand等 (uboot的驱动其实是linux驱动的一部分。) sd_fusing【重要】刷写sd卡的。实现了烧录uboot镜像到SD卡。其实以前在linux下刷机时就用了。 include 【重要】头文件目录 lib_ 【重要】架构相关的库文件。如lib_arm就算是arm相关的库文件。移植不用管。 libfdt 设备树相关。 linux在3.1以前的版本使用传参的方式启动。 3.1之后的版本采用设备树的机制进行硬件信息描述 目前用到的芯片使用的内核版本都低于3.4,故暂时不讨论设备树,以后讲通过专题。 net 网络相关的,里面的tftp等功能实现就用这个。程序很精小,学网络相关可以看这个。 fs 也是从linux移植过来的,文件系统,管理Flash的 tools 有用的工具 nand_spl onenand post 略

3.6 SourceInsight,简称SI

真正的项目往往有庞大数量的文件。而且代码之间的关联非常复杂。所以读代码是问题。
sourceinsight有方便我们跳转的功能。 【创建工程】 1 首先要创建工程。New project 工程名字和路径 注意:工程项目文件和源代码的目录可以不一样,但是建议放在一起 eg ;老朱自己有一个uboot的项目,习惯在uboot下创建一个“SI_Proj”文件夹 2 新工程设置,一般不管 3 向项目中添加文件 左边是被选的文件,右边是添加了的文件。选中整个项目的文件夹,Add Tree 然后就添加了好多文件。总视窗右边就出现了我们添加了的文件。 4 遗留问题:SI找不到未知文件类型的文件 比如start.s就不在其中,因为SI不认识。 解决方法1:选项 - 文档选项,选择C源码,后缀添加*.S 然后就能搜到了。告诉SI,*.S是一个c文件,随之当做C语言处理 这还是欺骗SI的小技巧,但是很好使。 解决方法2:选项 - 装入设置,装入。装入朱有鹏给