系统移植
- Windows下使用OTG烧写系统
- 在Windows使用NXP提供的mfgtool来向开发板烧写系统,需要用先将开发板的USB_OTG链接到电脑上
- mfgtool工具是向板子先下载一个linux系统,然后通过系统完成烧写工作
- Ubuntu下通过脚本烧写系统
- 首先向SD卡烧写一个系统,然后使用SD卡启动,启动以后在Linux中执行烧写到EMMC或NAND中
Uboot
Uboot是一个裸机程序,比较复杂,就是一个bootloader。作用就是用于启动Linux或其他系统,Uboot最主要的工作就是初始化DDR(Linux的运行是运行在DDR里面的),一般linux镜像zimage(uimage)+设备树(.dtb)存放在SD,EMMC,NAND,SPI FLASH等等外置存储区域。
这里牵扯到一个问题,需要将Linux镜像从外置系统拷贝到DDR中,再去启动,Uboot的主要问题就是为系统的启动做准备,不仅仅能启动Linux,也可以启动其他系统,比如vxworks,Linux不仅仅能通过Uboot启动
uboot是一个通用bootload,支持多种架构
正点原子官方uboot编译
编译uboot的时候需要先配置,编译代码如下:
1
2
3make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12ARCH=arm 设置目标为 arm 架构, CROSS_COMPILE 指定所使用的交叉编译器。 第一条命令相当于“make distclean”,目的是清除工程,一般在第一次编译的时候最好清理一下工程。第二条指令相当于“make mx6ull_14x14_ddr512_emmc_defconfig”,用于配置 uboot,配置文件为 mx6ull_14x14_ddr512_emmc_defconfig。最后一条指令相当于 “make -j12”也就是使用 12 核来编译 uboot。
编译完成以后就会生成一个u-boot.bin必须向u-boot.bin添加头部信息。u-boot编译会通过 ./tools/mkimage添加头部信息,生成u-boot.imx
uboot命令
- 带有调试性质的开发,uboot都是烧写到sd卡,方便烧写
==命令==:
help命令:
- 直接输入获取当前uboot可以执行的所有命令
- 查看某一个命令帮助信息:?+命令名,例如查看boot命令帮助信息:? boot
信息查询命令:
- bdinfo:打印板子信息
- printenv:查看当前板子的环境变量(重要)
setenv:
- 设置环境变量语法:setenv [设置的环境变量] [设置的值]
- 也可以自定义环境变量,语法同上
- 删除环境变量 ,将环境变量的值设为空值,语法:setenv [要删除的值]
saveenv:保存环境变量
内存操作命令:
- md命令:用于显示内存值,语法:md [.b, .w, .l] address [# of objects],例:md.b 0x80000000 20:显示从0x80000000开始的32个字节(20是16进制,uboot所有命令都是16进制的)
- nm命令:用于修改指定地址的内存值,语法:nm [.b, .w, .l] address
- mm命令:也是修改地址,使用 mm 修改内存值的时候地址会自增,而使用命令 nm 的话地址不会自增 ,语法同nm
- mw命令:用于使用一个指定的数据填充一段内存,命令格式如下:mw [.b, .w, .l] address value [count],例子:mw.l 80000000 0A0A0A0A 10
- cp命令:数据拷贝命令,用于将 DRAM 中的数据从一段内存拷贝到另一段内存中,或者把 Nor Flash 中的数据拷贝到 DRAM 中。命令格式如下:cp [.b, .w, .l] source target count ,例: cp.l 80000000 80000100 10
- cmp命令:比较命令,用于比较两段内存的数据是否相等,命令格式如下: cmp [.b, .w, .l] addr1 addr2 count ,例:cmp.l 80000000 80000100 10
网络操作命令:
- ping命令:重点!!!
- nfs:网络文件系统:目的就是为了调试程序,格式:nfs [loadAddress] [[hostIPaddr:]bootfilename] ,例子:nfs 80800000 192.168.10.100:/home/alientek/experiment/IMX6ULL/nfs/zImage
EMMC和SD卡操作命令
mmc命令:
- mmc info:打印当前选中设备信息
- mmc rescan:扫描当前可用设备
- mmc list:打印当前可用设备
- mmc dev:选择使用设备,例如mmc dev 0
- mmc part:列出当前设备分区
- mmc read:读取mmc设备命令,格式:mmc read addr blk# cnt 例:mmc read 80800000 600 10(以600为起始地址开始读, 读10(16进制)个块,每个块为512个字节)
- mmc write:mmc write addr blk# cnt
FAT格式文件系统操作命令
对于imxu来说sd或者emmc分为三个分区,第一个存放uboot第二个存放Linux zImage .dtb FAT,第三个:系统的跟文件系统 .EXT4
- fatinfo:查看指定MMC分区的文件系统信息,格式:fatinfo
[<dev[:part]>] 例:fatinfo mmc 1:1 - fatls:用于查询FAT格式设备的目录和文件信息
- fstype:用于查看MMC设备某个分区的v文件格式系统
- fatload:把FAT分区的某个文件读取到DRAM中,例:
BOOT操作命令
- bootz命令:要先把linux镜像和设备树放到DRAM中,bootz用于启动zImage镜像文件
- bootm命令:和bootz类似,用于启动uImage
- boot命令:用来运行bootcmd环境变量
bootcmd:setenv bootcmd ‘tftp 80800000 zImage;tftp 83000000 imx6ull-14x14-emmc-7-800x480-c.dtb;bootz 80800000 - 83000000;’设置好bootcmd置环境变量后直接运行boot即可 - go命令:跳转到指定地址处执行命令
- run命令:运行环境变量中定义的命令 ,就是自己定义在环境变量中的命令
Uboot源码分析
uboot源码目录分析
因为uboot会使用到一些经过编译才会生成的文件,因此我们在分析uboot的时候需要先编译uboot
- arch\arm\cpu\u-boot.lds就是整个uboot的链接脚本
- \board\freescale\mx6ullevk,重点
- configs目录是uboot的默认配置文件目录。此目录都是以_defconfig结尾的,这些配置文件对应不同的板子
- 移植uboot的时候重点要关注\board文件夹,\configs文件夹
- 当我们执行make xxx_defconfig就会生成.config文件,此文件保存了详细的uboot配置信息
- 顶层README非常重要,介绍uboot
- u-boot,这个就是编译出来带elf信息的uboot可执行文件。
类型 | 名字 | 描述 | 备注 |
---|---|---|---|
文件夹 | api | 与硬件无关的 API 函数。 | uboot 自带 |
arch | 与架构体系有关的代码。 | ||
board | 不同板子(开发板)的定制代码。 | ||
cmd | 命令相关代码。 | ||
common | 通用代码。 | ||
configs | 配置文件。 | ||
disk | 磁盘分区相关代码 | ||
doc | 文档。 | ||
drivers | 驱动代码。 | ||
dts | 设备树。 | ||
examples | 示例代码。 | ||
fs | 文件系统。 | ||
include | 头文件。 | ||
lib | 库文件。 | ||
Licenses | 许可证相关文件。 | ||
net | 网络相关代码。 |
post | 上电自检程序。 | ||
---|---|---|---|
scripts | 脚本文件。 | ||
test | 测试代码。 | ||
tools | 工具文件夹。 | ||
文件 | .config | 配置文件,重要的文件。 | 编译生成的文件 |
.gitignore | git 工具相关文件。 | uboot 自带 | |
.mailmap | 邮件列表。 | ||
.u-boot.xxx.cmd (一系列) | 这是一系列的文件,用于保存着一些命令。 | 编译生成的文件 | |
config.mk | 某个 Makefile 会调用此文件。 | uboot 自带 | |
imxdownload | 正点原子编写的 SD 卡烧写软件。 | 正点原子提供 | |
Kbuild | 用于生成一些和汇编有关的文件。 | uboot 自带 | |
Kconfig | 图形配置界面描述文件。 | ||
MAINTAINERS | 维护者联系方式文件。 | ||
MAKEALL | 一个 shell 脚本文件,帮助编译uboot 的。 | ||
Makefile | 主 Makefile,重要文件! | ||
mx6ull_alientek_emmc.sh | 上一章编写的编译脚本文件 | 上一章编写的。 | |
mx6ull_alientek_nand.sh | 上一章编写的编译脚本文件 | ||
README | 相当于帮助文档。 | uboot 自带 | |
snapshot.commint | ??? | ||
System.map | 系统映射文件 | 编译出来的文件 | |
u-boot | 编译出来的 u-boot 文件。 | ||
u-boot.xxx (一系列) | 生成的一些 u-boot 相关文件,包括u-boot.bin、 u-boot.imx.等 |
Uboot顶层Makefile分析
刚开始是版本号:
1
2
3
4
5VERSION = 2016
PATCHLEVEL = 03
SUBLEVEL =
EXTRAVERSION =
NAME =MAKEFLAGS变量:是用来传递给子makefile的
1
MAKEFLAGS += -rR --include-dir=$(CURDIR)
命令输出:uboot 默认编译是不会在终端中显示完整的命令,都是短命令, 不利于分析 uboot 的编译过程。可以通过设置变量“V=1“来实现完整的命令输出, 。实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14ifeq ("$(origin V)", "command line") #判断V是否来自命令行
KBUILD_VERBOSE = $(V) #获取来自命令行的值
endif
ifndef KBUILD_VERBOSE
KBUILD_VERBOSE = 0
endif
ifeq ($(KBUILD_VERBOSE),1) #如果V=1
quiet = #quiet控制输出长短
Q = #Q控制是否输出完整命令
else
quiet=quiet_
Q = @
endif静默输出:如果是make -s则静默输出,不输出过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# If the user is running make -s (silent mode), suppress echoing of
# commands
ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)#如果是make -s 则if成立
quiet=silent_
endif
else # make-3.8x
ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
quiet=silent_
endif
endif
export quiet Q KBUILD_VERBOSE设置编译结果输出目录:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51# 1) O=
# Use "make O=dir/to/store/output/files/"
#
# 2) Set KBUILD_OUTPUT
# Set the environment variable KBUILD_OUTPUT to point to the directory
# where the output files shall be placed.
# export KBUILD_OUTPUT=dir/to/store/output/files/
# make
#
# The O= assignment takes precedence over the KBUILD_OUTPUT environment
# variable.
# KBUILD_SRC is set on invocation of make in OBJ directory
# KBUILD_SRC is not intended to be used by the regular user (for now)
ifeq ($(KBUILD_SRC),)
# OK, Make called in directory where kernel src resides
# Do we want to locate output files in a separate directory?
ifeq ("$(origin O)", "command line") #判断o是否来自命令行
KBUILD_OUTPUT := $(O)
endif
# That's our default target when none is given on the command line
PHONY := _all
_all:
# Cancel implicit rules on top Makefile
$(CURDIR)/Makefile Makefile: ;
ifneq ($(KBUILD_OUTPUT),) ##判断是否为空
# Invoke a second make in the output directory, passing relevant variables
# check that the output directory actually exists
saved-output := $(KBUILD_OUTPUT)
KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \ #跳转到输出目录
&& /bin/pwd)
$(if $(KBUILD_OUTPUT),, \
$(error failed to create output directory "$(saved-output)"))
PHONY += $(MAKECMDGOALS) sub-make
$(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make
@:
sub-make: FORCE
$(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \
-f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS))
# Leave processing to above invocation of make
skip-makefile := 1
endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)代码检查
模块编译
获取主机架构和系统:
1
2
3
4
5
6
7
8
9
10
11
12
13
14HOSTARCH := $(shell uname -m | \ #获取主机架构
sed -e s/i.86/x86/ \ #将i.86换成X86
-e s/sun4u/sparc64/ \
-e s/arm.*/arm/ \
-e s/sa110/arm/ \
-e s/ppc64/powerpc/ \
-e s/ppc/powerpc/ \
-e s/macppc/powerpc/\
-e s/sh.*/sh/)
HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
sed -e 's/\(cygwin\).*/cygwin/')
export HOSTARCH HOSTOS配置ARCH和交叉编译器
1
2
3
4
5
6
7
8
9
10ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-
KCONFIG_CONFIG ?= .config
export KCONFIG_CONFIG调用 scripts/Kbuild.include
1
2
3scripts/Kbuild.include: ;
include scripts/Kbuild.include工具变量设置并导出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33AS = $(CROSS_COMPILE)as
# Always use GNU ld
ifneq ($(shell $(CROSS_COMPILE)ld.bfd -v 2> /dev/null),)
LD = $(CROSS_COMPILE)ld.bfd
else
LD = $(CROSS_COMPILE)ld
endif
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
LDR = $(CROSS_COMPILE)ldr
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
AWK = awk
PERL = perl
PYTHON = python
DTC = dtc
CHECK = sparse
CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
-Wbitwise -Wno-return-void -D__CHECK_ENDIAN__ $(CF)
KBUILD_CPPFLAGS := -D__KERNEL__ -D__UBOOT__
KBUILD_CFLAGS := -Wall -Wstrict-prototypes \
-Wno-format-security \
-fno-builtin -ffreestanding
KBUILD_AFLAGS := -D__ASSEMBLY__
# Read UBOOTRELEASE from include/config/uboot.release (if it exists)
UBOOTRELEASE = $(shell cat include/config/uboot.release 2> /dev/null)
UBOOTVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)导出其他变量:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23export VERSION PATCHLEVEL SUBLEVEL UBOOTRELEASE UBOOTVERSION
export ARCH CPU BOARD VENDOR SOC CPUDIR BOARDDIR
export CONFIG_SHELL HOSTCC HOSTCFLAGS HOSTLDFLAGS CROSS_COMPILE AS LD CC
export CPP AR NM LDR STRIP OBJCOPY OBJDUMP
export MAKE AWK PERL PYTHON
export HOSTCXX HOSTCXXFLAGS DTC CHECK CHECKFLAGS
export KBUILD_CPPFLAGS NOSTDINC_FLAGS UBOOTINCLUDE OBJCOPYFLAGS LDFLAGS
export KBUILD_CFLAGS KBUILD_AFLAGS
# When compiling out-of-tree modules, put MODVERDIR in the module
# tree rather than in the kernel tree. The kernel tree might
# even be read-only.
export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions
# Files to ignore in find ... statements
export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \
-name CVS -o -name .pc -o -name .hg -o -name .git \) \
-prune -o
export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \
--exclude CVS --exclude .pc --exclude .hg --exclude .gitmake xxx_defconfig :编译uboot之前要使用make xxx_defconfig命令配置uboot,这个命令如何运行?:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114# To make sure we do not include .config for any of the *config targets
# catch them early, and hand them over to scripts/kconfig/Makefile
# It is allowed to specify more targets when calling make, including
# mixing *config targets and build targets.
# For example 'make oldconfig all'.
# Detect when mixed targets is specified, and make a second invocation
# of make so .config is not included in this case either (for *config).
version_h := include/generated/version_autogenerated.h
timestamp_h := include/generated/timestamp_autogenerated.h
no-dot-config-targets := clean clobber mrproper distclean \
help %docs check% coccicheck \
ubootversion backup
config-targets := 0
mixed-targets := 0
dot-config := 1
ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),)
ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),)
dot-config := 0
endif
endif
ifeq ($(KBUILD_EXTMOD),)
ifneq ($(filter config %config,$(MAKECMDGOALS)),)
config-targets := 1
ifneq ($(words $(MAKECMDGOALS)),1)
mixed-targets := 1
endif
endif
endif
ifeq ($(mixed-targets),1)
# ===========================================================================
# We're called with mixed targets (*config and build targets).
# Handle them one by one.
PHONY += $(MAKECMDGOALS) __build_one_by_one
$(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one
@:
__build_one_by_one:
$(Q)set -e; \
for i in $(MAKECMDGOALS); do \
$(MAKE) -f $(srctree)/Makefile $$i; \
done
else
ifeq ($(config-targets),1)
# ===========================================================================
# *config targets only - make sure prerequisites are updated, and descend
# in scripts/kconfig to make the *config target
KBUILD_DEFCONFIG := sandbox_defconfig
export KBUILD_DEFCONFIG KBUILD_KCONFIG
config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
%config: scripts_basic outputmakefile FORCE
$(Q)$(MAKE) $(build)=scripts/kconfig $@
else
# ===========================================================================
# Build targets only - this includes vmlinux, arch specific targets, clean
# targets and others. In general all targets except *config targets.
ifeq ($(dot-config),1)
# Read in config
-include include/config/auto.conf
# Read in dependencies to all Kconfig* files, make sure to run
# oldconfig if changes are detected.
-include include/config/auto.conf.cmd
# To avoid any implicit rule to kick in, define an empty command
$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
# If .config is newer than include/config/auto.conf, someone tinkered
# with it and forgot to run make oldconfig.
# if auto.conf.cmd is missing then we are probably in a cleaned tree so
# we execute the config step to be sure to catch updated Kconfig files
include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
$(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
@# If the following part fails, include/config/auto.conf should be
@# deleted so "make silentoldconfig" will be re-run on the next build.
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.autoconf || \
{ rm -f include/config/auto.conf; false; }
@# include/config.h has been updated after "make silentoldconfig".
@# We need to touch include/config/auto.conf so it gets newer
@# than include/config.h.
@# Otherwise, 'make silentoldconfig' would be invoked twice.
$(Q)touch include/config/auto.conf
-include include/autoconf.mk
-include include/autoconf.mk.dep
# We want to include arch/$(ARCH)/config.mk only when include/config/auto.conf
# is up-to-date. When we switch to a different board configuration, old CONFIG
# macros are still remaining in include/config/auto.conf. Without the following
# gimmick, wrong config.mk would be included leading nasty warnings/errors.
ifneq ($(wildcard $(KCONFIG_CONFIG)),)
ifneq ($(wildcard include/config/auto.conf),)
autoconf_is_old := $(shell find . -path ./$(KCONFIG_CONFIG) -newer \
include/config/auto.conf)
ifeq ($(autoconf_is_old),)
include config.mk
include arch/$(ARCH)/Makefile
endif
endif
endif
解释:
1 | version_h := include/generated/version_autogenerated.h #这句保存了版本号问嫁女,文件自动生成 |
make过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52#默认目标
PHONY := _all
_all: all
all: $(ALL-y) #all依赖ALL-y
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check #ALL_y后面跟着很多格式类似:ALL-$(CONFIG_RAMBOOT_PBL) += u-boot.pbl 当CONFIG_RAMBOOT_PBL设置为y的时候添加u-boot.pbl置ALL中
#在ALL_y的依赖中的u-boot.bin是最终需要的uboot二进制可执行文件对应规则:
ifeq ($(CONFIG_OF_SEPARATE),y) #判断CONFIG_OF_SEPARATE是否为y
u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE
$(call if_changed,cat)
u-boot.bin: u-boot-dtb.bin FORCE #u-boot.bin对应规则
$(call if_changed,copy)
else
u-boot.bin: u-boot-nodtb.bin FORCE
$(call if_changed,copy)
endif
#u-boot.bin依赖于u-boot-nodtb.bin,对应的规则如下:
u-boot-nodtb.bin: u-boot FORCE
$(call if_changed,objcopy)
$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
$(BOARD_SIZE_CHECK)
#u-boot.bin依赖于u-boot,u-boot对应规则:
u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE
$(call if_changed,u-boot__)
ifeq ($(CONFIG_KALLSYMS),y)
$(call cmd,smap)
$(call cmd,u-boot__) common/system_map.o
endif
#u-boot依赖与:$(u-boot-init) $(u-boot-main) u-boot.lds FORCE,
#u-boot-init u-boot-main定义如下:
u-boot-init := $(head-y)
u-boot-main := $(libs-y)
#$(head-y)跟 CPU 架构有关,我们使用的是 ARM 芯片,所以 head-y 在 arch/arm/Makefile 中被指定为:
head-y := arch/arm/cpu/$(CPU)/start.o
#根据 前面小节的分析,我们知道 CPU=armv7,因此 head-y 展开以后就是:
head-y := arch/arm/cpu/armv7/start.o
#$(libs-y)在顶层 Makefile 中被定义为 uboot 所有子目录下 build-in.o 的集合:
libs-y += lib/
libs-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/
libs-$(CONFIG_OF_EMBED) += dts/
libs-y += fs/
libs-y += net/
libs-y += disk/
libs-y += drivers/
libs-y += drivers/dma/
libs-y += drivers/gpio/
libs-y += drivers/i2c/
libs-y += drivers/mmc/
libs-y += drivers/mtd/
.......
libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
#最后一句调用patsubst就是将libs-y里面的/替换成/built-in.o,相当于libs-y就是所有目录中built-in.o,所以u-biit-mian就是所有子目录中built-in.o文件的集合uboot启动流程详解
链接脚本u-boot.lds详解
.text段
uboot入口地址为_start
__image_copy_start相当于指向整个文本开始的地方,在u-boot.map(uboot内存映射文件)该变量指向87800000
.vectos也是指向87800000,存放中断向量表arch/arm/cpu/armv7/start.o (.text*):start.o的存放位置
, _image_binary_end = .;和前方的 _image_copy_end对其,二者中间存放着镜像文件地址: 0x000000008784f1a4
.rel_dyn_start 0x000000008784f1a4
.rel_dyn_end 0x000000008785794c rel段
.rel_dyn_end 0x000000008785794c
.bss_start 0x000000008784f1a4
.bss_end 0x000000008789a194 bss段
start.s:
reset函数:将处理器设置为SVC模式,并且关闭FIQ和IRQ
设置中断向量
初始化CP15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15reset:
/* Allow the board to save important registers */
b save_boot_params
save_boot_params_ret:
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already
*/
mrs r0, cpsr @ 读取cpsr中的值,cpsr是程序状态寄存器
and r1, r0, #0x1f @将r0的值与0x1f进行与运算,并将结果保留到r1中,也就是保留cpsr的低五位(这5位是设置处理器的工作模式的)
teq r1, #0x1a @ 用于比较是否为Hyp模式也即是看r0是不是11010
bicne r0, r0, #0x1f @ 如果不是Hyp模式就是将r0设置为11111,也就是sys模式
orrne r0, r0, #0x13 @ 与10011与运算,进入svc模式
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0后面:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/*
* Setup vector:
* (OMAP4 spl TEXT_BASE is not 32 byte aligned.
* Continue to use ROM code vector only in OMAP4 spl)
*/
if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register #读取 CP15 中 c1 寄存器的值到 r0 寄存器中
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
endif继续:
1
2
3
4
5
6
7
8
9
10
11/* the mask ROM code should have PLL and others stable */
ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
bl cpu_init_crit
endif
bl _main
cpu_init_cp15:是一些和cp15有关的信息
cpu_init_crit:调用了函数 lowlevel_init,lowlevel_init函数:
设置sp指针和r9寄存器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43ENTRY(lowlevel_init)
/*
* Setup a temporary stack. Global data is not available yet.
*/
ldr sp, =CONFIG_SYS_INIT_SP_ADDR
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ifdef CONFIG_SPL_DM
mov r9, #0
else
/*
* Set up global data for boards that still need it. This will be
* removed soon.
*/
ifdef CONFIG_SPL_BUILD
ldr r9, =gdata
else
sub sp, sp, #GD_SIZE
bic sp, sp, #7
mov r9, sp
endif
endif
/*
* Save the old lr(passed in ip) and the current lr to stack
*/
push {ip, lr}
/*
* Call the very early init function. This should do only the
* absolute bare minimum to get started. It should not:
*
* - set up DRAM
* - use global_data
* - clear BSS
* - try to start a console
*
* For boards with SPL this should be empty since SPL can do all of
* this init in the SPL board_init_f() function which is called
* immediately after this.
*/
bl s_init
pop {ip, pc}
ENDPROC(lowlevel_init)s_init函数:
空函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45void s_init(void)
{
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
u32 mask480;
u32 mask528;
u32 reg, periph1, periph2;
if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL) ||
is_cpu_type(MXC_CPU_MX6ULL) || is_cpu_type(MXC_CPU_MX6SLL))
return;
/* Due to hardware limitation, on MX6Q we need to gate/ungate all PFDs
* to make sure PFD is working right, otherwise, PFDs may
* not output clock after reset, MX6DL and MX6SL have added 396M pfd
* workaround in ROM code, as bus clock need it
*/
mask480 = ANATOP_PFD_CLKGATE_MASK(0) |
ANATOP_PFD_CLKGATE_MASK(1) |
ANATOP_PFD_CLKGATE_MASK(2) |
ANATOP_PFD_CLKGATE_MASK(3);
mask528 = ANATOP_PFD_CLKGATE_MASK(1) |
ANATOP_PFD_CLKGATE_MASK(3);
reg = readl(&ccm->cbcmr);
periph2 = ((reg & MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK)
>> MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET);
periph1 = ((reg & MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK)
>> MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET);
/* Checking if PLL2 PFD0 or PLL2 PFD2 is using for periph clock */
if ((periph2 != 0x2) && (periph1 != 0x2))
mask528 |= ANATOP_PFD_CLKGATE_MASK(0);
if ((periph2 != 0x1) && (periph1 != 0x1) &&
(periph2 != 0x3) && (periph1 != 0x3))
mask528 |= ANATOP_PFD_CLKGATE_MASK(2);
writel(mask480, &anatop->pfd_480_set);
writel(mask528, &anatop->pfd_528_set);
writel(mask480, &anatop->pfd_480_clr);
writel(mask528, &anatop->pfd_528_clr);
}_main函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr sp, =(CONFIG_SPL_STACK)
else
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
endif
if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */
mov r3, sp
bic r3, r3, #7
mov sp, r3
else
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
endif
mov r0, sp
bl board_init_f_alloc_reserve
mov sp, r0
/* set up gd here, outside any C code */
mov r9, r0
bl board_init_f_init_reserve
mov r0, #0
bl board_init_f
if ! defined(CONFIG_SPL_BUILD)
/*
* Set up intermediate environment (new sp and gd) and call
* relocate_code(addr_moni). Trick here is that we'll return
* 'here' but relocated.
*/
ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */
mov r3, sp
bic r3, r3, #7
mov sp, r3
else
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
endif
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
sub r9, r9, #GD_SIZE /* new GD is below bd */
adr lr, here
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
add lr, lr, r0
if defined(CONFIG_CPU_V7M)
orr lr, #1 /* As required by Thumb-only */
endif
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
b relocate_code
here:
/*
* now relocate vectors
*/
bl relocate_vectors
/* Set up final (full) environment */
bl c_runtime_cpu_setup /* we still call old routine here */
endif
if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
ifdef CONFIG_SPL_BUILD
/* Use a DRAM stack for the rest of SPL, if requested */
bl spl_relocate_stack_gd
cmp r0, #0
movne sp, r0
movne r9, r0
endif
ldr r0, =__bss_start /* this is auto-relocated! */
ifdef CONFIG_USE_ARCH_MEMSET
ldr r3, =__bss_end /* this is auto-relocated! */
mov r1, #0x00000000 /* prepare zero to clear BSS */
subs r2, r3, r0 /* r2 = memset len */
bl memset
else
ldr r1, =__bss_end /* this is auto-relocated! */
mov r2, #0x00000000 /* prepare zero to clear BSS */
clbss_l:cmp r0, r1 /* while not at end of BSS */
if defined(CONFIG_CPU_V7M)
itt lo
endif
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
endif
if ! defined(CONFIG_SPL_BUILD)
bl coloured_LED_init
bl red_led_on
endif
/* call board_init_r(gd_t *id, ulong dest_addr) */
mov r0, r9 /* gd_t */
ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */
/* call board_init_r */
if defined(CONFIG_SYS_THUMB_BUILD)
ldr lr, =board_init_r /* this is auto-relocated! */
bx lr
else
ldr pc, =board_init_r /* this is auto-relocated! */
endif
/* we should not return here. */
endif
ENDPROC(_main)board_init_f:
- 初始化一系列外设,例如串口定时器等等
- 初始化gd的各个成员变量,uboot 会将自己重定位到 DRAM 最后面的地址区域,也就是将自己拷贝到 DRAM 最后面的内存区域中。这么做的目的是给 Linux 腾出空间,防止 Linux kernel 覆盖掉 uboot,将 DRAM 前面的区域完整的空出来。在拷贝之前肯定要给 uboot 各部分分配好内存位置和大小,比如 gd 应该存放到哪个位置, malloc 内存池应该存放到哪个位置等等。这些信息都保存在 gd 的成员变量中,因此要对 gd 的这些成员变量做初始化。最终形成一个完整的内存“分配图”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60void board_init_f(ulong boot_flags)
{
/*
* For some archtectures, global data is initialized and used before
* calling this function. The data should be preserved. For others,
* CONFIG_SYS_GENERIC_GLOBAL_DATA should be defined and use the stack
* here to host global data until relocation.
*/
gd_t data;
gd = &data;
/*
* Clear global data before it is accessed at debug print
* in initcall_run_list. Otherwise the debug print probably
* get the wrong vaule of gd->have_console.
*/
zero_global_data();
gd->flags = boot_flags;
gd->have_console = 0;
if (initcall_run_list(init_sequence_f)) //此函数会调用一系列函数,这些函数保存在init_sequence_f中
hang();
/* NOTREACHED - jump_to_copy() does not return */
hang();
/* Light up LED1 */
imx6_light_up_led1();
}
/*
* For now this code is only used on x86.
*
* init_sequence_f_r is the list of init functions which are run when
* U-Boot is executing from Flash with a semi-limited 'C' environment.
* The following limitations must be considered when implementing an
* '_f_r' function:
* - 'static' variables are read-only
* - Global Data (gd->xxx) is read/write
*
* The '_f_r' sequence must, as a minimum, copy U-Boot to RAM (if
* supported). It _should_, if possible, copy global data to RAM and
* initialise the CPU caches (to speed up the relocation process)
*
* NOTE: At present only x86 uses this route, but it is intended that
* all archs will move to this when generic relocation is implemented.
*/
static init_fnc_t init_sequence_f_r[] = {
init_cache_f_r,
NULL,
};
initcall_run_list(init_sequence_f)中的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205static init_fnc_t init_sequence_f[] = {
setup_ram_buf,
setup_mon_len,//设置gd->mon_len=_bss_end-_start=uboot image大小
fdtdec_setup,
trace_early_init,
initf_malloc,//设置gd->malloc_limit=0x400
initf_console_record,
/* TODO: can this go into arch_cpu_init()? */
probecpu,
x86_fsp_init,
arch_cpu_init, /* basic arch cpu dependent setup */
initf_dm,
arch_cpu_init_dm,
mark_bootstage, /* need timer, go after init dm */
board_early_init_f,
/* TODO: can any of this go into arch_cpu_init()? */
get_clocks, /* get CPU and bus clocks (etc.) */
adjust_sdram_tbs_8xx,
/* TODO: can we rename this to timer_init()? */
init_timebase,
timer_init, /* initialize timer */
dpram_init,
board_postclk_init,
get_clocks,
env_init, /* initialize environment */
/* get CPU and bus clocks according to the environment variable */
get_clocks_866,
/* adjust sdram refresh rate according to the new clock */
sdram_adjust_866,
init_timebase,
init_baud_rate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
sandbox_early_getopt_check,
fdtdec_prepare_fdt,
display_options, /* say that we are here 打印编译事件*/
display_text_info, /* show debugging info if required */
prt_8260_rsr,
prt_8260_clks,
prt_83xx_rsr,
checkcpu,
print_cpuinfo, /* display cpu info (and speed) */
prt_mpc5xxx_clks,
show_board_info,
INIT_FUNC_WATCHDOG_INIT
misc_init_f,
INIT_FUNC_WATCHDOG_RESET
init_func_i2c,
init_func_spi,
announce_dram_init,
/* TODO: unify all these dram functions? */
dram_init, /* configure available RAM banks */
init_func_ram,
post_init_f,
INIT_FUNC_WATCHDOG_RESET
testdram,
INIT_FUNC_WATCHDOG_RESET
init_post,
INIT_FUNC_WATCHDOG_RESET
/*
* Now that we have DRAM mapped and working, we can
* relocate the code and continue running from DRAM.
*
* Reserve memory at end of RAM for (top down in that order):
* - area that won't get touched by U-Boot and Linux (optional)
* - kernel log buffer
* - protected RAM
* - LCD framebuffer
* - monitor code
* - board info struct
*/
setup_dest_addr,
/* Blackfin u-boot monitor should be on top of the ram */
reserve_uboot,
reserve_prom,
reserve_logbuffer,
reserve_pram,
reserve_round_4k,
reserve_mmu,
reserve_video,
reserve_lcd,
/* TODO: Why the dependency on CONFIG_8xx? */
reserve_legacy_video,
reserve_trace,
reserve_uboot,
reserve_malloc,
reserve_board,
setup_machine,
reserve_global_data,
reserve_fdt,
reserve_arch,
reserve_stacks,
setup_dram_config,
show_dram_config,
setup_board_part1,
INIT_FUNC_WATCHDOG_RESET
setup_board_part2,
display_new_sp,
setup_board_extra,
INIT_FUNC_WATCHDOG_RESET
reloc_fdt,
setup_reloc,
copy_uboot_to_ram,
clear_bss,
do_elf_reloc_fixups,
jump_to_copy,
NULL,
};
uboot移植实验
- 添加板子默认配置头文件:借鉴NXP官方6ULL_EVK开发板,默认配置文件在/config文件夹中
- 添加板子对应的头文件:不同的板子有一些需要配置的信息,一般是在一个头文件里面配置,每个板子里面有一个,对于NXP官方的6ULLEVK板子,在/include/configs文件夹中
- 添加板子对应的板级文件夹:每个板子都有特有的文件,也叫做板级文件,这里将6ull evk的板级文件直接拷贝过来/board/freescale
LCD驱动的修改
- 确定LCDIO初始化正确,mx6ull_alientek_emmc.c中的lcd_pads
- LCD参数,mx6ull_alientek_emmc.c中的displays中的fb_videomode表示RGB LCD参数
网络驱动修改
6ull网络方案采用内部MAC加外部PHY,6ULL官方开发板使用的PHY芯片就是KSY8081(V2.4及以后版本的底板网络芯片更换为SR8201F )
- 修改PHY地址
- 删除uboot中74LV595 的驱动代码
- 添加 I.MX6U-ALPHA 开发板网络复位引脚驱动
uboot启动Linux测试
从EMMC中启动:
- 首先查看EMMC里面是否有系统,linux镜像zImage和.dtb文件,先将当前设备切换到EMMC
- mmc dev 1 //切换到EMMC
- fatls mmc 1:1 // 查看EMMC分区1里面的文件
- fatload mmc 1:1 80800000 zImage //将zImage下载到DDR的80800000处
- fatload mmc 1:1 8300000 imx6ull-14x14-emmc-7-800x480-c.dtb //将dtb读取到0x83000000
- bootz 80800000 - 83000000 //启动内核
从网络启动:
- tftp 80800000 zImage //从tftp下载zImage
- tftp 83000000 imx6ull-14x14-emmc-7-800x480-c.dtb //从tftp下载.dtb
- bootz 80800000 - 83000000 //启动内核
bootcmd和bootargs
1.bootcmd:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
"mmc dev ${mmcdev};" \ //切换到emmc
"mmc dev ${mmcdev}; if mmc rescan; then " \
"if run loadbootscript; then " \
"run bootscript; " \
"else " \
"if run loadimage; then " \ //检查mmc 1:1中是否有zImage文件
"run mmcboot; " \
"else run netboot; " \
"fi; " \
"fi; " \
"else run netboot; fi"
//最后化简后就为:
mmc dev 1
fatload mmc 1:1 0x80800000 zImage
fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb
bootz 0x80800000 - 0x83000000bootargs:
1
2"mmcargs=setenv bootargs console=${console},${baudrate} " \ //指定串口,波特率
"root=${mmcroot}\0" \ //设置跟文件系统
uboot DDR初始化
裸机:imxdownload软件下载,会在bin文件头部添加IVT DCD数据
uboot:编译生成u-boot.imx,u-boot.imx已经包含了IVT DCD数据。
u-boot.imx的头部信息时怎么添加的
u-boot.imx的DCD中的DDR初始化代码该怎么修改
./tools/mkimage -n board/freescale/mx6ull_alientek_emmc/imximage.cfg.cfgtmp -T imximage -e 0x87800000 -d u-boot.bin u-boot.imx
可以看粗uboot使用./tools/mkimage工具,向u-boot.bin添加board/freescale/mx6ull_alientek_emmc/imximage.cfg.cfgtmp文件信息,从而得到u-boot.imx
Uboot图形化配置界面
通过终端配置,进入到源码根目录下,首先默认配置:
1
make mx6ull_alientek_emmc_defconfig
输入make menuconfig 打开图形化配置界面,(新ubuntu需要安装ncurses库),图形化配置界面对一个功能的编译或选择有三种模式:
- Y:对应的功能编译进uboot中
- N:对应功能,不编译进uboot里面
- M:将对应的功能编译为模块,.ko Linux内核中常用
==当我们配置好以后,需要保存自己的配置文件==
- 在图形化配置界面选择save,选择保存进./config/name
- 下次使用时在图形化配置界面选择load即可
原理:
Kconfig文件,uboot源码根目录下的Kconfig,Kconfig文件就是图形化界面配置文件
- mainmenu 主菜单
- 调用子目录下的Kconfig:source “*/Kconfig”
- menu/endmenu:子菜单
- choice/endchoice :多选一
- config :具体配置项:config条目都是以config条目开头的。后面紧跟着配置项,列如:ARC使能了条目以后就会在config里面生成 CONFIG_ARC=y
- depend on和select
- 当选中某一项以后,select对应的项就会同样选中
- 只有depend on 指定的项要先被选中,否则指定的项不能选择
Linux内核
编译步骤
disclean清理工程
make xxx——defconfig 使用默认配置文件配置工程
make 编译
make menuconfig 打开配置界面进行配置
zImage存放在./arch/arm/boot/zImage
.dtb存放在./arch/arm/boot/dts/*.dtb
==源码目录分析==
- arch/arm/boot/这个目录,Linux内核编译完成以后,在此目录下生成image zImage
- arch/arm/boot/dts/这个目录存放Linux内核所有设备树文件,包括dts编译后对应的.dtb文件
- Documentation\devicetree\bindings 此目录下的文件很重要,设备树绑定信息
在linux中添加自己的开发板
- 一个就是imx6ull_alientek_emmc_defconfig 默认配置文件
- imx6ull-alientek-emmc.dts编译出来就是.dtb文件
设置板子默认从网络启动:setenv bootcmd ‘tftp 80800000 zImage;tftp 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 - 83000000’ (==bootcmd默认不进入uboot后执行==)
设置根文件系统存放在EMMC的分区2里面: setenv bootargs ‘console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw’
根文件系统的构建
根文件系统也叫做rootfs,FAT这类文件系统属于Linux的一部分,属于软件代码,根文件系统= ‘根’ + ‘文件’ + ‘系统’ 。根文件系统就是一堆的文件,比如软件,配置文件等等,这些文件时Linux运行所必须的,将他们组合在一起就构成了根文件系统。
根文件系统就是一个“文件夹”此文件夹有很多个文件,这些文件是Linux运行所必须的,但是无法放到内核中,比如命令,库,配置文件等等,所有这些软件需要我们自己构建
- /bin 目录看到“bin”大家应该能想到 bin 文件, bin 文件就是可执行文件。所以此目录下存放着系统需要的可执行文件,一般都是一些命令,比如 ls、 mv 等命令。此目录下的命令所有的客户都可以使用。
- /dev 目录dev 是 device 的缩写,所以此目录下的文件都是和设备有关的,此目录下的文件都是设备文件。在 Linux 下一切皆文件,即使是硬件设备,也是以文件的形式存在的,比如/dev/ttymxc0(I.MX6ULL 根目录会有此文件)就表示 I.MX6ULL 的串口 0,我们要想通过串口 0发送或者接收数据就要操作文件/dev/ttymxc0,通过对文件/dev/ttymxc0 的读写操作来实现串口0 的数据收发。
- /etc 目录此目录下存放着各种配置文件,大家可以进入 Ubuntu 的 etc 目录看一下,里面的配置文件非常多!但是在嵌入式 Linux 下此目录会很简洁。
- /lib 目录lib 是 library 的简称,也就是库的意思,因此此目录下存放着 Linux 所必须的库文件。这些库文件是共享库,命令和用户编写的应用程序要使用这些库文件。
- /mnt 目录临时挂载目录,一般是空目录,可以在此目录下创建空的子目录,比如/mnt/sd、 /mnt/usb,这样就可以将 SD 卡或者 U 盘挂载到/mnt/sd 或者/mnt/usb 目录中。
- /proc 目录此目录一般是空的,当 Linux 系统启动以后会将此目录作为 proc 文件系统的挂载点, proc是个虚拟文件系统,没有实际的存储设备。 proc 里面的文件都是临时存在的,一般用来存储系统运行信息文件。
- /usr 目录要注意, usr 不是 user 的缩写,而是 Unix Software Resource 的缩写,也就是 Unix 操作系统软件资源目录。这里有个小知识点,那就是 Linux 一般被称为类 Unix 操作系统,苹果的 MacOS也是类 Unix 操作系统。关于 Linux 和 Unix 操作系统的渊源大家可以直接在网上找 Linux 的发展历史来看。既然是软件资源目录,因此/usr 目录下也存放着很多软件,一般系统安装完成以后此目录占用的空间最多。
- /var 目录此目录存放一些可以改变的数据。
- /sbin 目录此目录页用户存放一些可执行文件,但是此目录下的文件或者说命令只有管理员才能使用,主要用户系统管理。
- /sys 目录系统启动以后此目录作为 sysfs 文件系统的挂载点, sysfs 是一个类似于 proc 文件系统的特殊文件系统, sysfs 也是基于 ram 的文件系统,也就是说它也没有实际的存储设备。此目录是系统设备管理的重要目录,此目录通过一定的组织结构向用户提供详细的内核数据结构信息。/opt可选的文件、软件存放区,由用户选择将哪些文件或软件放到此目录中。
BusyBox构建根文件系统
构建根文件系统,busybox,还有很多成熟化的根文件系统的构建方式,buildroot,yoctos,构建的根文件系统调试,我们通过nfs网络挂载,也就是根文件系统存放在ubuntu下,开发板启动以后通过nfs服务使用ubuntu下的根文件系统
- 修改makefile添加交叉编译器,修改ARCH CROSS_COMPILE
- busy支持中文字符
- 配置busybox :make defconfig
- 编译 busybox
- 将库文件拷贝过来,库文件就是交叉编译器的库文件
- 创建其他文件夹
- 设置nfs挂载根文件系统: setenv bootargs ‘console=ttymxc0,115200 rw root=/dev/nfs nfsroot=192.168.10.100:/home/alientek/experiment/IMX6ULL/nfs/rootfs ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off’