十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FS4412 U-Boot移植实战:从启动流程到SD卡烧写

FS4412 U-Boot移植实战:从启动流程到SD卡烧写 简介面向FS4412平台的U-Boot移植实验代码包专为嵌入式Linux系统移植学习者和高校实验课设计目标是解决U-Boot引导加载程序在三星FS4412ARM架构SoC上的源码配置、驱动适配与加密文件处理等关键问题适合有一定嵌入式基础、需要系统掌握移植流程的开发者可用于课程设计、毕业设计或工程项目预研。压缩包约34.62MB共2000个文件以C源码、头文件、Makefile、链接脚本、汇编启动文件、DTS设备树和cfg配置文件为主板级初始化、内存映射、串口及外设驱动、设备树等模块分目录存放便于定位与检索。已有563人学习。资源内含uboot2013原始源码、三星加密相关文件、移植过程中需要修改的代码以及移植完成后可直接运行的完整工程可帮助使用者从硬件规格分析、配置修改、驱动编写、构建烧录到启动调试一步步掌握U-Boot在FS4412上的移植方法并可作为后续驱动开发和系统集成的参考基线。1. 这次移植实验到底在做什么FS4412这块板子用的是三星Exynos 4412四核处理器Cortex-A9架构主频能跑到1.4GHz左右。很多学校实验室和嵌入式培训机构都喜欢拿它做系统移植的教学板因为它的硬件资源足够典型——内部有SRAM、有SD/MMC控制器、有UART、有USB外部还能接DDR3和NAND Flash基本把嵌入式Linux系统移植会遇到的几个核心环节都覆盖了。所谓系统移植说白了就是让一套通用的操作系统比如Linux能在一块特定的硬件板子上跑起来。但Linux内核本身不会直接操作硬件它需要一个引导程序先把硬件初始化好、把内核镜像加载到内存里、再跳转过去执行。这个引导程序在嵌入式领域最常用的就是U-Boot。这次做的FS4412系统移植实验就是围绕U-Boot展开的从源码获取、交叉编译环境搭建、板级配置修改到编译生成u-boot.bin再到烧写到SD卡里让板子从SD卡启动整个过程完整走一遍。实验代码部分重点看的是U-Boot的启动流程、链接脚本、关键配置项以及驱动初始化相关的源码。很多人一开始会混淆BSP和U-Boot的关系。BSP是Board Support Package板级支持包它是一个更大的概念包含了引导程序、内核补丁、驱动、根文件系统等一系列让板子能跑起来的软件集合。U-Boot只是BSP里面最底层的那一环——负责把硬件点亮、把内核请进来。所以做U-Boot移植等于是在搭整个BSP的第一块地基后面内核移植和设备树修改都要踩在它上面展开。至于网上搜到的uboot stacktrace.sh这是U-Boot源码里一个调试辅助脚本一般放在scripts/目录下用于在U-Boot崩溃时解析调用栈。做移植实验时如果板子起不来这个脚本能帮你把PC指针和LR寄存器对应的函数名解析出来。后面讲排查技巧时我会再提它。2. U-Boot启动流程拆解从ROM代码到命令行U-Boot移植之所以让很多初学者头疼是因为它不是一个改个配置就能编译的简单工程。你得先搞清楚它从上电到进入命令行到底走了多少步每一步又是谁在负责。FS4412这块板子的启动流程在Exynos 4412内部有一套固定的启动序列分三个阶段。第一阶段是芯片内部的iROM代码也叫BL0这是三星出厂时固化在芯片里的用户改不了。它负责最基础的时钟初始化和启动介质选择。FS4412支持从SD卡、eMMC、NAND等多种介质启动具体从哪儿启动由OMOperating Mode引脚的电平组合决定。实验里常用的是SD卡启动所以OM引脚要拨到SD卡启动对应的档位。第二阶段是BL1。BL1是从SD卡特定位置加载到芯片内部SRAM里运行的一段代码。Exynos 4412的iROM会先读取SD卡第一个扇区512字节这里面存的是BL1的头部信息包含BL1的大小、校验和、加载地址等。校验通过后iROM把BL1完整加载到SRAM的0x02021400地址处跳转执行。第三阶段是BL2也就是真正的主角U-Boot。但严格来说FS4412上运行的U-Boot分两部分前半部分是小容量BL2负责初始化DDR控制器让外部的DDR3内存可用后半部分才是完整的U-Boot它被加载到DDR里继续执行。为什么这么麻烦因为芯片内部的SRAM只有几百KB装不下完整的U-Boot必须先让DDR工作起来才能把完整的U-Boot镜像放进去。搞清楚这个流程你就明白为什么FS4412的U-Boot编译产物往往不止一个文件。实验中你会看到u-boot.bin、u-boot-spl.bin、BL1.bin等文件它们各自承担不同的启动阶段任务。SD卡烧写时也不是把整个U-Boot一股脑丢进去而是要按偏移地址分开放BL1放某个扇区BL2放另一个扇区完整U-Boot再放后面的位置。这些偏移地址由三星的启动规范决定乱放是起不来的。如果你拿到的是正规渠道的FS4412 BSP包里面会带一个脚本通常是sd_fusing.sh自动完成SD卡分区和文件写入。但实验课上老师往往会要求你手动执行每一步目的就是让你理解这个启动链路。下面我会详细讲实验代码中每个关键部分对应的启动环节。3. 实验代码结构与关键文件解读FS4412的U-Boot实验代码一般基于U-Boot 2012.10版本或类似的老版本改造而来。这个版本虽然老旧但对于学习系统移植反而更好——代码量适中没有后来引入的Device Tree和Kconfig那套复杂机制整个配置体系就是make board_config加make两步非常直观。拿到代码先别急着编译先把目录结构过一遍。顶层目录里几个关键目录要心里有数board/samsung/fs4412/板级文件目录存放FS4412的板级初始化代码比如fs4412.c、lowlevel_init.S。移植过程中改动最频繁的地方之一。arch/arm/cpu/armv7/CPU相关代码Exynos 4412是Cortex-A9属于armv7架构。这里面的start.S是U-Boot的入口汇编文件。include/configs/fs4412.h板级配置头文件所有宏定义都在这里相当于整个U-Boot的开关面板。drivers/各类驱动源码串口、网卡、SD卡、Flash等外设驱动都在这里。看代码时建议按照启动流程倒着看。先看include/configs/fs4412.h因为这个文件决定了U-Boot编译时包含哪些功能和每种功能怎么配置。比如CONFIG_SYS_TEXT_BASE这个宏它定义了U-Boot的链接起始地址FS4412上通常是0x43E00000这个地址对应DDR内存区段。如果这个值设置错了U-Boot启动时会跳到一个非法地址直接卡死串口什么都打不出来。再往下看board/samsung/fs4412/lowlevel_init.S。这个文件的注释里常常写着一句话This file is executed from SRAM意思是这段代码在SRAM里运行而SRAM的访问速度比DDR快得多但因为容量小代码必须精简。这个文件做的事情主要是关闭看门狗、初始化时钟PLL、配置DDR控制器。每一行寄存器操作都要对着Exynos 4412的芯片手册看否则根本看不懂为什么给某个寄存器写这个值。最后看arch/arm/cpu/armv7/start.S。这是U-Boot入口负责设置CPU为SVC模式、关闭中断、初始化栈指针然后跳转到_main。如果你在实验过程中需要添加调试打印往这个文件里加是最容易的但要注意汇编阶段的打印无法调用printf因为C环境还没准备好一般用串口寄存器直接输出字符或者借助CONFIG_DEBUG_UART这种早期调试机制。这里要特别提一下链接脚本u-boot.lds它定义了U-Boot各个段在内存中的排布顺序。FS4412移植如果出现编译通过但运行崩溃的情况八成是链接脚本里某个段的加载地址和运行地址不一致。常见的表现是代码烧进SD卡后板子复位U-Boot的启动日志打了一两行就没动静了这种问题用JTAG调试器对比PC指针和符号表很快就能定位。4. 从零开始交叉编译环境与完整烧写操作做FS4412 U-Boot移植实验前你需要先准备好交叉编译工具链。FS4412是ARM Cortex-A9核所以要用arm-linux-gnueabihf系列工具链注意不是aarch64那个是给64位ARM用的32位ARM用不了。我习惯用Ubuntu 14.04或16.04的虚拟机来做这个实验因为老版本的U-Boot在太新的GCC版本下编译容易报错。如果你手里只有新系统可以用arm-linux-gnueabihf-gcc 4.9.3这个版本实测兼容性比较好。安装好工具链后先验证一下arm-linux-gnueabihf-gcc -v能看到版本信息就说明工具链可用。然后把工具链路径加入环境变量建议写进~/.bashrcexport PATH/opt/arm-linux-gnueabihf-4.9.3/bin:$PATH source ~/.bashrc接下来是编译步骤。以常见的FS4412实验包为例过程一般是三步make distclean make fs4412_config make -j4第一条命令清掉之前的编译产物防止缓存干扰。第二条命令会根据boards.cfg里的配置项生成include/config.mk和include/autoconf.mk后者是从fs4412.h中提取的宏定义编译时会自动包含。第三条命令就是正式编译。编译完成后在顶层目录下会生成u-boot.bin。但FS4412直接烧写这个文件是不够的还需要生成BL1和BL2。三星提供的工具mkbl1或者BSP包里的脚本会把u-boot.bin拆分成适合SD卡启动布局的多个文件。具体操作如下sudo ./sd_fusing.sh /dev/sdb如果你的实验环境没有现成的sd_fusing.sh手动烧写的过程大致是这样的逻辑先把SD卡分区然后按下列偏移写入分区内容起始扇区说明BL11iROM加载的BL1镜像BL217U-Boot SPL或缩小版U-BootU-Boot 完整镜像49从DDR启动的完整U-Boot环境变量区域49U-Boot环境变量存储区注意扇区偏移数值因BSP版本而异以你们实验指导书为准。我这里写的是三星典型的参考布局。烧完SD卡后把OM引脚拨到SD卡启动插上串口线波特率设115200上电后串口终端应该能看到U-Boot的启动日志最后进入FS4412 #命令行提示符。我在第一次做这个实验时踩过一个特别典型的坑串口终端什么输出都没有。排查了半天最后发现是串口线插错了COM口。FS4412板子一般有多个串口只有COM0是U-Boot调试串口别的串口在U-Boot阶段没有初始化自然什么都不打印。所以如果你遇到上电无输出先别急着怀疑代码先确认串口号对不对再看波特率是不是115200-8-N-1。5. 常见问题与排查技巧实录移植U-Boot过程中遇到的问题来来回回就那么几类但每一类都能让新手卡上好几天。我把实验过程中和学生反馈最多的问题整理成了一份速查表这里的经验比代码本身更值钱。问题一编译报错提示某些宏未定义你在修改fs4412.h时如果把某个宏注释掉了但代码里其他地方还引用着它编译就会报错。比如CONFIG_SYS_CLK_FREQ定义了系统时钟频率如果这个宏没定义start.S里的时钟初始化代码就无法编译。解决办法是用grep -r CONFIG_SYS_CLK_FREQ arch/ board/ include/把引用位置全找出来确认哪些功能依赖这个宏。U-Boot的配置体系是牵一发而动全身改宏之前先查引用是个好习惯。问题二烧写SD卡后板子没有反应第一步排除SD卡本身问题。U-Boot用的SD卡容量建议2GB到8GB之间部分大容量卡或山寨卡在启动时序上不兼容。用sudo dd if/dev/zero of/dev/sdb bs512 count8清掉SD卡开头的引导区内容再重新烧写防止旧数据干扰。第二步确认OM引脚拨到位FS4412开发板上通常有个拨码开关不同组合对应SD/eMMC/NAND启动看板子丝印确认SD启动对应的档位。问题三启动日志打印到一半卡住比如打印完Board: FS4412就停了或者打印到Net:就没了。这种问题先从串口输出位置定位函数。U-Boot的启动日志顺序和代码执行顺序是严格对应的看打印停在哪一行就去board_init_r和board_init里找对应的初始化步骤。最常见的两个原因一是DDR初始化不成功因为U-Boot代码搬运到DDR后访问内存崩溃了二是某个外设驱动初始化时读取寄存器返回值异常又没有超时保护陷入死循环。遇到这个问题建议先在include/configs/fs4412.h里打开CONFIG_DEBUG_UART和DEBUG宏重新编译烧写U-Boot会输出大量调试信息把崩溃位置缩小到具体函数。如果还定位不到就用之前提过的uboot stacktrace.sh。用法是在U-Boot崩溃时从串口记录下PC和LR寄存器的值然后运行./scripts/stacktrace.sh u-boot 0xpc值 0xlr值脚本会对照ELF符号表把这两个地址对应的函数名解析出来配合反汇编arm-linux-gnueabihf-objdump -D u-boot基本能锁定崩溃位置。问题四修改代码后烧写无效这是个反直觉的坑。只执行了make重新生成的u-boot.bin时间戳变了但烧写脚本写入SD卡的还是旧文件。原因可能是你用了sudo执行的烧写命令而sh文件里写死了输入文件名但文件路径没切换到当前编译目录。建议每次烧写前先ls -l u-boot.bin确认文件生成时间再用绝对路径执行烧写命令。另外一个常见原因是make时没有加-j参数以外的选项导致编译中断产生旧的目标文件残留保险起见正式编译前先make clean或者make distclean。问题五网络功能不通如果U-Boot启动正常但执行ping 192.168.1.10不通先查FS4412网卡芯片型号。大部分FS4412板子用的DM9000或AX88796对应的驱动宏分别是CONFIG_DRIVER_DM9000或CONFIG_DRIVER_AX88796。确认fs4412.h里已经定义了正确的网卡芯片宏还要检查CONFIG_IPADDR、CONFIG_SERVERIP这些网络参数是否设置成你主机的同一网段。很多人忽略了一个细节U-Boot里ping用的网卡必须确保板子和主机之间用网线直连时主机网卡手动设置了和U-Boot同网段的IPWindows防火墙有时也会拦截ICMP请求。问题六环境变量保存失败U-Boot里执行saveenv报错提示无法写入存储介质。这是因为fs4412.h中配置的环境变量存储位置和实际烧写布局不一致。例如你配置了CONFIG_ENV_IS_IN_MMC但没有正确设置CONFIG_ENV_OFFSETU-Boot会把环境变量写到SD卡的某个随机位置要么覆盖了U-Boot镜像要么写入不存在的扇区。解决办法是查一下BSP文档中环境变量区的固定偏移把它填到CONFIG_ENV_OFFSET里。FS4412实验中不建议用saveenv保存配置因为反复擦写SD卡扇区有损坏风险临时改配置直接setenv后在内存中用就行。6. 实验代码的后续扩展方向做完基础的U-Boot移植实验很多人会问接下来还能做什么。我建议沿着两条线深入。一条线是往U-Boot里添加自定义命令。比如让U-Boot启动时自动读取某个内存地址的数据或者自定义一个led_test命令方便验证硬件电路。实现方法是在common/目录下新建一个命令文件使用U_BOOT_CMD宏注册命令然后在common/Makefile里加上编译规则。这个过程能让你真正理解U-Boot的命令也是代码这一设计理念。另一条线是打通U-Boot到Linux内核的启动链路。U-Boot移植只是第一步后续还要移植Linux内核、制作根文件系统。FS4412的实验标准流程是U-Boot启动后通过tftp命令从主机下载zImage和设备树文件或者老版本的uImage然后bootm启动内核。你可以尝试在U-Boot里配置bootcmd环境变量让板子上电后自动执行启动流程不用每次手动敲命令。这一步做完你的系统移植实验才算是真正闭环了。还有一点值得提最新版本的U-Boot引入了Device Tree和Kconfig配置体系代码结构和2012.10版本差别很大。但FS4412的移植经历并不过时因为启动流程、DDR初始化、链接脚本这些底层逻辑是共通的。你在老版本上学到的东西迁移到新版本时只需要额外学一下设备树语法和Kconfig配置规则核心的板级初始化逻辑没变。我见过很多工程师面试时被问U-Boot启动流程能完整讲清楚BL0/BL1/BL2三层结构的几乎都做过类似的板级移植实验。最后再分享一个我个人的操作习惯每次修改U-Boot源码之前先用git初始化一个本地仓库每完成一个功能点就提交一次。做移植实验改的东西很杂有配置头文件、汇编文件、链接脚本经常改来改去就忘了上一个能启动的版本长什么样。有git在手随时可以回滚对比。这个习惯在很多实际项目中帮我省了大把时间。本文还有配套的精品资源点击获取
返回列表