Uboot笔记
Powered By ——Dr.Miao
什么是uboot?
-
首先u-boot可以理解成一个大型的、复杂的裸机程序。
2.uboot是一个bootloader,作用就是用于启动Linux或其他系统(可以理解为windows的BIOS)。Uboot最主要的工作就是初始化DDR。因为Linux是运行在DDR里面的。
uboot如何获取?
-
万事找厂家,有事它负责(U-Boot – DENX Software Engineering)
2.找对应芯片的SOC厂商,他们是对uboot进行了相应的芯片优化的,属于是定制版uboot
编译uboot
-
编译UBOOT的时候需要先配置
-
编译完成以后就会生成一个u-boot.bin。必须向u-boot.bin添加头部信息。Uboot编译最后会通过/tools/mkimage软件添加头部信息,生成u-boot.imx。
-
如果配置过uboot,那么一定要注意shell脚本会清除整个工程,那么配置的文件也会被删除,配置项也会被删除掉。
-
为了方便开发,建议直接在uboot顶层Makefile里面设置好ARCH和CORSS_COMPILE这两个变量的值。
Uboot命令的使用
hlep命令的使用:
-
查看某一个命令的帮助信息,?+ 命令名
-
信息查询
-
bdiofo:
-
printenv命令:
查看当前板子环境变量
-
-
setenv命令(重点)
设置环境变量、自定义环境变量、删除环境变量(设置为空值)
-
saveenv(重点)
保存环境变量
内存管理命令:
-
md命令(内存查询):
-
md.b\md.w\md.l
2.nm命令(内存修改):
3.mm命令(自增修改内存):
4.mw命令:
5.cp命令(拷贝):
6.cmp命令:
返回值为从何处开始不相等
网络操作命令(重点)
ping命令(重点)
setenv addrip ip地址(设置开发板的IP,注意:网段一定要与设置的网卡IP保持一致)
setenv ethaddr XXX(设置MAC)
setenv gatewayip 192.168.1.1(网关)
setenv netmask 255.255.255.0(子网掩码)
setenv serverip 192.168.XXX.XXX(服务器地址)
NFS命令(重点)
目的:方便调试代码
-
首先在Ubuntu服务器下安装好nfs的服务端
-
之后按照流程配置网卡、uboot的IP(一定要在同一个网段下,可以不设置网关)
-
nfs服务器版本一定要对(配置如下):
tftp命令(重点)
等同于nfs,主要是配置服务器端
mmc及文件操作命令
-
mmc命令:
2.FAT 格式文件系统操作命令:
对于 I.MX6U 来说,SD/EMMC 分为三个分区: 第一个:存放 uboot 第二个:存放 Linux zImage,.dtb。FAT 第三个:系统的根文件系统,EXT4
-
fatinfo命令
-
fatls
-
fstype(格式查看)
-
fatload命令(重要)
3.EXT格式:
略
BOOT操作指令
1、booz 命令 要启动 Linux 必须将 zImage,dtb 放到 DRAM。
bootz 80800000 - 83000000
2、bootm 命令
3、boot 命令
setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ull....;bootz 80800000 - 83000000;'
saveenv
boot
其他指令
1、reset 命令
2、go 命令(可以跳转到执行裸机程序)
3、run命令:
run 命令用于运行环境变量中定义的命令,比如可以通过“run bootcmd”来运行 bootcmd 中的启动命令
Uboot源码分析
要分析一定要分析编译后的Uboot
(压缩编译后的uboot并解压缩到Windows)
1.u-boot.lds就是整个uboot的连接脚本:
2.board\freescale\mx6ullevk(重点)
3.configs(Miao_uboot/configs)目录是uboot的默认配置文件。此目录下都是以defconfig结尾的。这些文件对应不同的板子
4.移植uboot的时候一定要重点关注:
board\freescale
./configs
5.当我们执行 make xxx_ defconfig 以后就会生成.config 文件,此文件保存了详细的 uboot 配置信息。
6.顶层 READ.ME,非常重要,介绍 uboot,包含其用法。
7.u-boot。这个就是编译出来带 ELF 信息的 uboot 可执行文件。
顶层Makefile文件分析
1.创建VSCODE工程文件,便于分析,配置工作区,将不必要的文件屏蔽
2.Mkefile流程研究(重点):
-
make distclean
-
make XXX_defconfig规则(复杂、多看、看不懂正常):
解析:
1、目标为 scripts_basic scripts_basic:
$(Q)$(MAKE) $(build)=scripts/basic 展开以后就是: make -f ./scripts/Makefile.build obj= scripts/basic build 定义在 scripts\Kbuild.include build := -f $(srctree)/scripts/Makefile.build obj build := -f ./scripts/Makefile.build obj
2、outputmakefile, 因为 KBUILD_SRC,因此 outputmakefile 无效。 最终要执行的命令
make -f ./scripts/Makefile.build obj=scripts/basic · Make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig
第一条命令:
src = scripts/basic kbuild-dir = ./scripts/basic kbuild-file = ./scripts/basic/Makefile include ./scripts/basic/Makefile __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \ $(subdir-ym) $(always) @: __build: $(builtin-target) $(lib-target) $(extra-y) $(subdir-ym) $(always) @: scripts/basic/fixdep __build: scripts/basic/fixdep
因此需要编译出 scripts/basic/fixdep,对应的.c 是 scripts/basic/fixdep.c,
第二条命令:
Make -f ./scripts/Makefile.build obj=scripts/kconfig xxx_defconfig src = scripts/kconfig kbuild-dir = ./scripts/ kconfig kbuild-file = ./scripts/ kconfig/Makefile include ./scripts/kconfig/Makefile %_defconfig: $(obj)/conf $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) xxx_defconfig: scripts/kconfig/conf $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) scripts/kconfig/conf --defconfig=arch/../configs/ xxx_defconfig Kconfig
-
make V = 1 -j12
默认目标 PHONY := _all
_all:
_all: all
all: $(ALL-y)
ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
u-boot.bin: u-boot-nodtb.bin FORCE $(call if_changed,copy)
u-boot-nodtb.bin: u-boot FORCE $(call if_changed,objcopy) $(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE)) $(BOARD_SIZE_CHECK)
u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE $(call if_changed,u-boot__)
u-boot-init := $(head-y) u-boot-main := $(libs-y)
head-y= arch/arm/cpu/armv7/start.o libs-y=保存源码的目录 libs-y += lib/ -> lib/built-in.o # 把lib/替换为lib/build-in.o libs-y 保存大量的 built-in.o u-boot 就是将 start.o 和大量的 built-in.o 链接在一起。
假如: CONFIG_ONENAND_U_BOOT =y ALL-$(CONFIG_ONENAND_U_BOOT) ALL-y += u-boot-onenand.bin
3.链接:
链接脚本为 u-boot.lds,uboot 链接首地址为 0X87800000,
在 mx6_common.h 文件中设置 CONFIG_SYS_TEXT_BASE=0X87800000
Uboot启动流程详解
1、从 u-boot.lds (链接)可知,uboot 入口地址为_start:
image_copy_start-> 0x87800000
.vetcors -> 0x87800000 存放中断向量表 arch/arm/cpu/armv7/start.o start.c
image_copy_end -> 0x8785dc6c
_rel_dyn_start -> 0x8785dc6c #rel 段 _rel_dyn_end -> 0x878668a4
_end -> 0x878668a4
_image_binary_end -> 0x878668a4
_bss_start -> 0x8785dc6c #bss 段。 _bss_end -> 0x878a8d74
2、uboot启动流程(多看):
1、reset 函数
bicne=bic + ne ①、reset 函数目的是将处理器设置为 SVC 模式,并且关闭 FIQ 和 IRQ. ②、设置中断向量。 ③、初始化 CP15 ④、调用_lowlevel_init和 _main
2、lowlevel_init 函数
CONFIG_SYS_INIT_SP_ADDR #define CONFIG_SYS_INIT_SP_ADDR \ (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
#define CONFIG_SYS_INIT_SP_OFFSET \ (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE) #define CONFIG_SYS_INIT_RAM_SIZE IRAM_SIZE #define IRAM_SIZE 0x00020000 #define CONFIG_SYS_INIT_RAM_ADDR IRAM_BASE_ADDR #define IRAM_BASE_ADDR 0x00900000 6ULL 内 部 OCRAM #define GENERATED_GBL_DATA_SIZE 256 0x00900000 + CONFIG_SYS_INIT_SP_OFFSE => 0x00900000 + CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE => 0x00900000 + 0x00020000 – 256 = 0x0091ff00 设置 SP 指针、R9 寄存器
3、s_init 函数
空函数。
4、_main 函数
5、board_init_f 函数
initcall_run_lis 此函数会调用一系列的函数,这些函数保存在 init_sequence_f 数组 里面, version_string[] = U_BOOT_VERSION_STRING #define U_BOOT_VERSION_STRING U_BOOT_VERSION " (" U_BOOT_DATE " - " \ U_BOOT_TIME " " U_BOOT_TZ ")" CONFIG_IDENT_STRING U_BOOT_VERSION = U-Boot 2016.03 TOTAL_MALLOC_LEN (CONFIG_SYS_MALLOC_LEN + CONFIG_ENV_SIZE) CONFIG_SYS_MALLOC_LEN (16 * SZ_1M) CONFIG_ENV_SIZE SZ_8K
mx6ullevk.c mx6ullevk.h 这两个文件长打交道
6、relocate_code 函数
作用:
①、初始化一系列外设,比如串口、定时器,或者打印一些消息等。
②、初始化 gd 的各个成员变量,uboot 会将自己重定位到 DRAM 最后面的地址区域,也就是将自己拷贝到 DRAM 最后面的内存区域中。这么做的目的是给 Linux 腾出空间,防止 Linuxkernel 覆盖掉 uboot,将 DRAM 前面的区域完整的空出来。
relocate_code 函数有一个参数,r0=gd->relocaddr=0X9FF47000,uboot 重定位后的首地址。 r1=0X87800000 源地址起始地址。 r4=0X9FF47000-0X87800000=0X18747000 偏移。 r2=0x8785dc6c 当简单粗暴的将 uboot 从 0X87800000 拷贝到其他地方以后,关于函数调用、全局变量引用就会出问题。Uboot 对于这个的处理方法就是采用位置无关码,这个就需要借助于.rel.dyn 段。
8785dcf8 <rel_a>: 8785dcf8: 00000000 andeq r0, r0, r0 878042b4 <rel_test>: 878042b4: e59f300c ldr r3, [pc, #12] ; 878042c8 <rel_test+0x14> 878042b8: e3a02064 mov r2, #100 ; 0x64 878042bc: e59f0008 ldr r0, [pc, #8] ; 878042cc <rel_test+0x18> 878042c0: e5832000 str r2, [r3] 878042c4: ea00d64c b 87839bfc <printf> 878042c8: 8785dcf8 ; <UNDEFINED> instruction: 0x8785dcf8 878042cc: 87842aaf strhi r2, [r4, pc, lsr #21] 设置 r3 为 878042b4+8+12=878042c8 的值,r3=8785dcf8。这里并没有直接去读 取 rel_a 的地址,而是借助了 878042c。 878042c8 叫做 Label。 重定位以后 9ffa4cf8 <rel_a>: 9ffa4cf8: 00000000 andeq r0, r0, r0 9ff4b2b4<rel_test>: 9ff4b2b4: e59f300c ldr r3, [pc, #12] ; 878042c8 <rel_test+0x14> 9ff4b2b8: e3a02064 mov r2, #100 ; 0x64 9ff4b2bc: e59f0008 ldr r0, [pc, #8] ; 878042cc <rel_test+0x18> 9ff4b2c0: e5832000 str r2, [r3] 9ff4b2c4: ea00d64c b 87839bfc <printf>
9ff4b2c8: 8785dcf8 ; <UNDEFINED> instruction: 0x8785dcf8 9ff4b2cc: 87842aaf strhi r2, [r4, pc, lsr #21] Label 中 的 值 还 是 原 来 的 ! 必 须 要 将 8785dcf8 换 为 重 定 位 后 的 rel_a 地 址 。 读 取 9ff4b2c8 里 面 的 数 据 , 也 就 是 老 的 rel_a 的 地 址 =8785dcf8+0x18747000=0x9ffa4cf8 重定位以后,需要对所有的 Label 保存的数据加上偏移!! 8785dcec: 87800020 strhi r0, [r0, r0, lsr #32] 8785dcf0: 00000017 andeq r0, r0, r7, lsl r0 ...... 8785e2fc: 878042c8 strhi r4, [r0, r8, asr #5] 8785e300: 00000017 andeq r0, r0, r7, lsl r0 878042c8+offset = 读取新的 Label 处的数据+offset 完成这个功能在连接的时候需要加上”-pie”
7、relocate_vectors 函数
设置 VBAR 寄存器为重定位后的中断向量表起始地址。
8、board_init_r 函数
Board_init_r 函 数 和 board_init_f 函 数 很 类 似 。 board_init_r 也 是 执 行init_sequence_r 初始化序列。
9、run_main_loop 函数
run_main_loop -> main_loop -> bootdelay_process 获 取 bootdelay 的 值 , 然 后 保 存 到stored_bootdelay 全局变量里面,获取 bootcmd 环境变量值,并且将其返回 -> autoboot_command 参数是 bootcmd 的值。 -> abortboot 参数为 boot delay,此函数会处理倒计时 -> abortboot_normal 参数为 boot delay,此函数会处理倒计时 -> cli_loop uboot 命令模式处理函数。 -> parse_file_outer -> parse_stream_outer -> parse_stream 解析输入的字符,得到命令 -> run_list 运行命令
-> run_list_real -> run_pipe_real -> cmd_process 处理命令,也就是执行命令
10、cli_loop 函数
11、cmd_process 函数
Uboot 使用 U_BOOT_CMD 来定义一个命令。CONFIG_CMD_XXX 来使能 uboot 中的某个命令。 U_BOOT_CMD 最终是定义了一个 cmd_tbl_t 类型的变量,所有的命令最终都是存放在.u_boot_list 段里面。cmd_tbl_t 的 cmd 成员变量就是具体的命令执行函数,命令执行函数都是 do_xxx。 cmd_process ->find_cmd 从.u_boot_list 段里面查找命令,当找到对应的命令以后以返回值的形式给出,为 cmd_tbl_t 类型 ->cmd_call ->cmdtp->cmd 直接引用 cmd 成员变量
3、bootz启动Linux内核的过程
Uboot 启动 Linux 内核使用 bootz 命令,bootm。。bootz 是如何启动 Linux 内核?uboot 的生命是怎么终止的呢?linux 又是怎么启动的呢?
1、images(保存镜像信息)全局变量
bootm_headers_t images;
2、do_bootz 函数(重点):
tftp 80800000 zImage tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb #tftp下载 bootz 80800000 - 83000000 #启动!!!
bootz 命令的执行函数,do_xxxx,do_bootz 是 bootz 的执行函数。 分析do_bootz调用函数: 1.-> bootz_start: -> do_bootm_states 阶段为 BOOTM_STATE_START -> bootm_start #对 images 全局变量清零 -> images->ep = 0X80800000 #设置入口地址 ->bootz_setup #判断 zImage 是否正确(与后文的zimage_header相关) -> bootm_find_images · -> boot_get_fdt #找 到 设 备 树 , 然 后 将 设 备 树 起 始 地 址 和 长 度 , 写 入 到images的 ft_addr 和 ft_len 成员变量中。 -> 2.bootm_disable_interrupts:关闭中断相关 -> images.os.os = IH_OS_LINUX; #表示要启动 Linux 系统 -> 3.do_bootm_states:状 态 BOOTM_STATE_OS_PREP、BOOTM_STATE_OS_FAKE_GO 、BOOTM_STATE_OS_GO, -> bootm_os_get_boot_func #查找 Linux 内核启动函数。找到 Linux 内核启动函数do_bootm_linux,赋值给 boot_fn。 -> boot_fn #(BOOTM_STATE_OS_PREP, argc, argv, images); 就是do_bootm_linux。 -> boot_prep_linux #启动之前的一些工作,对于使用设备树来说,他会将Bootargs 传递给 Linux 内核,通过设 备树完成。也就是向Linux内核传参。
-> boot_selected_os BOOTM_STATE_OS_GO, do_bootm_linux -> do_bootm_linux,BOOTM_STATE_OS_GO -> boot_jump_linux -> machid= gd->bd->bi_arch_number; #获取机器id -> void (kernel_entry)(int zero, int arch, uint params); -> kernel_entry = (void ()(int, int, uint))images->ep; #kernel_entry地址:0X80800000。 -> announce_and_cleanup #输出 Starting kernel...... -> kernel_entry(0, machid, r2); #启动 Linux 内核。Uboot 的最终使命,启动 Linux 内核。
zimage_header 的 zi_magic 为 zimage 的幻数,魔术数。应该为 0x016f2818。前面有 9 个 32 位的数据,那么 9*4=36,0~35,第 36 个字节的数据开始就是 zimage 的幻数
Uboot移植
一、NXP官方Uboot编译与测试
将NXP提供的uboot拷贝到ubuntu中。一个开发板也好运行uboot,DDR或者叫DRAM,串口,SD、EMMC、NAND。板子能工作。
测似结果:
1、uboot能正常启动
2、LCD驱动要根据所使用的屏幕修改。
3、NET初始化失败。
二、移植 NXP 官方 uboot 到 ALPHA 开发板
2.1 添加板子默认配置文件
借鉴 NXP 官方 6ULL EVK 开发板,默认配置文件也用他的
2.2 添加板子对应的头文件
不同的板子,有一些需要配置的信息,一般是在一个头文件里面配置,每个板子有一个。对于 NXP 官方的 6ULL EVK 板子,这个头文件就是:
2.3 添加板子对应的板级文件夹
每个板子都有特有的文件,也叫做板级文件(在board文件夹下)。这里我们将 6ULL EVK 的板级文件直接拷贝过来。
要修改的文件:
1./board/freescale/mx6ullevk复制一份重命名为mx6ull_miao_emmc(自定义)
2.更改其中的imximage.cfg、Kconfig、Makefile、mx6ullevk(重命名为mx6ull_miao_emmc)
3./include/configs:复制imx6ullevk.h文件重命名为mx6ull_miao_emmc.h
2.4 修改 uboot 的配置界面
2.5 使用新添加的板子配置并编译 Uboot
2.6 LCD 驱动修改
1、确定 LCD IO 初始化正确,mx6ull_alientek_emmc.c 中的 lcd_pads。
2 、 LCD 参 数 ,mx6ull_alientek_emmc.c 中 的 displays 。 fb_videomode 表 示RGB LCD 参数。
MX6ULL_LCDIF1_BASE_ADDR (=AIPS2_OFF_BASE_ADDR + 0x48000) AIPS2_OFF_BASE_ADDR (=ATZ2_BASE_ADDR + 0x80000) ATZ2_BASE_ADDR AIPS2_ARB_BASE_ADDR AIPS2_ARB_BASE_ADDR = 0x02100000 MX6ULL_LCDIF1_BASE_ADDR = 0x02100000 + 0x80000 + 0x48000 =0x21c8000
Panel 环境变量(mx6ull_miao_emmc.h里面全都要改成对应的屏幕代号)表示 LCD ID。
查看使用的屏幕手册对照着改动
2.7 网络驱动修改(重点)
6ULL 网络方案采用内部 MAC+外部 PHY,6ULL 官方开发板使用的 PHY 芯片就是KSZ8081。正点原子的 ALPHA 开发板没有使用 KSZ8081,我们使用的 LAN8720A。因此要修改驱动。
LAN872 有一个管理接口,叫做 MDIO,两根线,MDIO 和 MDC,一个 MDIO 接口,可以管理 32 个 PHY 芯片。MIDO 通过 PHY ADDR 来确定访问那个 PHY 芯片(双路选择)。ALPHA 开发板 ENET1 的 PHY ADDR 是 0x0,ENET2 的 PHY ADDR 是 0X1.
每 个 LAN8720 都 有 一 个 复 位 引 脚 , ENET1 是 SNVS_TAMPER7 ,ENET12是 SNVS_TAMPER78。
LAN8720 驱动,因为所有的 PHY,其前 32 个寄存器一模一样,因此 uboot 里面已经写好了通用 PHY 驱动,所以理论上不需要修改(国际联盟标准)。
驱动修改: 1、修改 PHY ADDR:
找到想要使用的网口:
2、删除原有的 74LV595 相关代码。
在.c文件中
3、添加 ALPHA 开发板的网络复位 IO:
fec1_pads:描述网口一的数组
fec2_pads:描述网口二的数组
找到函数setup_iomux_fec()在其中添加网口复位代码:
之后找到文件/drivers/net/phy/phy.c中,修改函数genphy_update_link()。添加lan8720驱动复位代码:
2.8 其他需要修改的地方
三、bootcmd 和 bootargs 环境变量(.h文件中)
3.1 bootcmd 环境变量
宏 CONFIG_BOOTCOMMAND 也可以设置 bootcmd 的值。
/脚本/
"run findfdt;" \ "mmc dev ${mmcdev};" \ "mmc dev ${mmcdev}; if mmc rescan; then " \ "if run loadbootscript; then " \ "run bootscript; " \ "else " \ "if run loadimage; then " \ "run mmcboot; " \ "else run netboot; " \ "fi; " \ "fi; " \ "else run netboot; fi"
Findfdt 设置 fdt_file 环境变量,也就是 dtb 文件名字。
mmc dev 1 //切换到 emmc
fatload mmc 1:1 80800000 zImage fatload mmc 1:1 83000000 imx6ull-14x14-evk.dtb booz 80800000 - 83000000
解释:
"loadbootscript=" \ "fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};\0" \
展开:fatload mmc 1:1 80800000 boot.scr(与上面的fatload mmc相对应)
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}\0" \
展开:fatload mmc 1:1 80800000 zImage(与上面的loadimage相对应)
"loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}\0" \
展开:fatload mmc 1:1 83000000 imx6ull-14x14-evk.dtb(与上面的loadfdt相对应)
bootz ${loadaddr} - ${fdt_addr}; 展开:booz 80800000 - 83000000
3.2 bootargs 环境变量
宏 CONFIG_BOOTARGS 也可以设置 bootargs 的值 mmcargs=setenv bootargs console=${console},${baudrate} " \ CONFIG_BOOTARGS_CMA_SIZE \ "root=${mmcroot}\0" \
展开以后就是: bootargs console= ttymxc0,115200 root=/dev/mmcblk1p2 Bootargs #是会传递给 Linux 内核,设置了一些东西 Bootargs #环境变量也叫做命令行参数。
四、uboot 启动 Linux 测试
4.1 从 EMMC 启动
1、首先查看 EMMC 里面是否有系统,linux 镜像 zImage 和.dtb 文件。先将当前设备切换到 EMMC:mmc dev 1 //切换到 EMMC。
fatls mmc 1:1 //查看 EMMC 分区 1 里面的文件
fatload mmc 1:1 80800000 zImage //将 zimage 下载到 DDR 的 0x80800000 处
fatload mmc 1:1 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb // 将 dtb 读取到 0X83000000
bootz 80800000 – 83000000 //启动内核
如果内核启动成功,说明 uboot 支持 emmc 启动,验证成功。
4.2 从网络启动
tftp 80800000 zImage //从 tftp 服务器下载 zimage
tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb // 从 tftp 服 务 器 下载.dtb
bootz 80800000 – 83000000 //启动系统
五、uboot DDR 初始化
1、裸 机
imxdownload 软件下载,会在 bin 文件头部添加 IVT DCD 数据,
2、uboot
uboot 编译生成 u-boot.imx。u-boot.imx 已经包含了 IVT DCD 数据。 u-boot.imx 的头部信息是怎么添加的? u-boot.imx 的 DCD 中的 DDR 初始化代码该怎么修改。
uboot 编译会输出: ./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。
默认只有 imximage.cfg 文件,imximage.cfg 里面保存的就是 DCD 数据。DDR 初始化也此文件里面。我们要修改 DDR 初始化代码,就需要修改 imximage.cfg 文件。此文件默认拷贝的NXP 给 IMX6ULL EVK 开发板写的,默认是给 512MB DDR3L 写的。
修改DDR的校准值和初始化使用工具(在裸机实验中DDR章节一致)
总结:
至此Uboot的移植部分基本结束,学完了这一部分之后其实还是一脸懵,但是有一点就是学会了,了解了整个uboot启动移植的流程,大概清楚了对应部分应该如何修改代码,只是还需要后续再去理解对应部分的函数该如何修改.
Uboot图形化配置
一、Uboot 图形化配置方法
1、通过终端配置。 2、进入到 uboot 的源码根目录下。 3、首先默认配置: make mx6ull_alientek_emmc_defconfig(make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig) //默认配置 4、输入 make menuconfig。打开图形化配置界面。
5、注意,新电脑需要安装 ncurses 库。
ncurses 库:
图形化配置界面对于一个功能的编译,或者叫做选择有 3 种模式: Y:对应的功能编译进入uboot 里面。 N:对应的功能不编译进uboot 里面 M:将对应的功能编译为模块,以.ko结尾,Linux 内核里面常用。 当我们配置好以后,需要保存一下自己的配置文件。
二、menuconfig 图形化配置原理
Kconfig 文件,uboot 源码根目录下的 Kconfig。Kconfig 文件就是图形化界面配置文件。 2.1 mainmenu 主菜单,
2.2 调用子目录下的 Kconfig source “xxx/Kconfig”
2.3 menu/endmenu 这两个之间是子菜单。
2.4 choice/endchoice 多选一。
2.5 config 条目 Config 条 目 都 是 以 config 条 目 开 头 的 。 后 面 紧 跟 着 配 置 项 , 比 如LOCALVERSION , 使 能 了 条 目 以 后 就 会 在 .config 里 面 生 成: CONFIG_LOCALVERSION=y。
2.6 depends on 和 select 当选中某一项以后,select 对应的项目都会选中。 Depends on 指定的项目要先被·选中,否则指定的项目不能选择。
2.7 menuconfig
三、添加自定义菜单
图形化配置工具的主要工作就是在.config下面生成前缀为“CONFIG”的变量,这些变量一般都要值,为 y,m 或 n,在 uboot 源码里面会根据这些变量来决定编译哪个文件。自定义菜单要求如下:
-
在主界面中添加一个名为“My test menu”,此菜单内部有一个配置项。
-
配置项为“MY_TESTCONFIG”,此配置项处于菜单“My test menu”中。
-
配置项的为变量类型为 bool,默认值为 y。
-
配置项菜单名字为“This is my test config”。
-
配置项的帮助内容为“This is a empty config, just for tset!”。
总结:
关于Uboot的学习到这里就基本结束了,个人感觉学习下来,还是觉得uboot在嵌入式方向来说还是非常重要的,他是移动设备移植系统的必经之路,关于她的改写与移植是非常复杂的,所以特别要感谢Uboot开源官方给我们提供的底层,让我们能更多地关注上层代码的改写与移植。
关于温习方面,我感觉需要重点关注一下uboot顶层Makefile中的文件以及启动流程中的那些功能函数。
——全文参