注:由于全志A10和A20在加载Bootloader过程方面基本一致,下面仅以A20叙述,但同时也适用于A10。另外在不需要区分Cubieboard1和Cubieboard2的情况下,统称为Cubieboard;另现在市面上一般所说的SD卡即为Micro SD Card,也就是TF卡,为区别于一般传统的SD卡,本文一般使用TF卡描述,但同于平时所说的SD卡。

A20的启动过程大概可分为5步:Boot ROM,SPL,Uboot,Kernel,RootFileSystem。本文关注的是镜像的加载和启动过程,分析Boot ROM→SPL→Uboot→Kernel的启动流程。

系统上电后,ARM处理器在复位时从地址0x000000开始执行指令,把板上ROM或Flash映射到这一地址。A20将启动设备选择程序固化在CPU内部的一个32KB ROM中,默认的启动时序为SD Card0,NAND FLASH,SD Card2,SPI NOR FLASH。另外通过外部的一个启动选择引脚可以使其跳转到USB启动模式。通常情况下,启动选择引脚状态连接50K内部上拉电阻。在上电后,执行存储在Boot ROM中的启动代码,将自动检测启动选择引脚状态。只有当该引脚状态为低电平时才选择USB启动模式。

在选择启动设备后将加载并执行bootloader程序,CPU通过拷贝或映射bootloader程序到内存,然后执行bootloader的第一条指令。通过阅读官方的uboot烧写方法,发现A20通过uboot引导系统之前先载入了uboot SPL。什么是SPL?通过查阅uboot的官网资料得知,SPL是一个迷你版的uboot,全拼为Second Program Loader。适用于SOC的内部SRAM<64K的情况,用它来加载完整的uboot程序到SDRAM,并通过完整uboot加载内核来启动系统。其中SRAM一般指CPU内部的L1/L2或外部的L2高速缓存,这里即为Boot ROM,而SDRAM一般指内存。

SPL程序流程如下:

  1. 初始化ARM处理器
  2. 初始化串口控制台
  3. 配置时钟和最基础的分频
  4. 初始化SDRAM
  5. 配置引脚多路复用功能
  6. 启动设备初始化(即上面选择的启动设备)
  7. 加载完整的uboot程序并转交控制权

启动设备选择程序的流程图: 

搞清楚了上面的概念,可以知道Cubieboard出厂已经烧写了NandFlash中的程序,即在启动时使用的是NandFlash。现在根据全志A20上述步骤,我们尝试用SD Card0(即Cubieboard上卡槽中的TF卡)来启动系统。

环境准备

本文所使用的主机环境为kubuntu 12.10,然而一般情况下,下面涉及到的命令对基于Debian的(X)ubuntu系列都应该适用。

为不引起混淆,我们作如下约定:

  • 工作目录为 $WORK_DIR
  • 命令均以root用户执行

笔者的设定如下:

<span class="re2">WORK_DIR</span>=<span class="sy0">/</span>home<span class="sy0">/</span>itviewer<span class="sy0">/</span>src

下载必须的工具软件

<span class="kw2">apt-get install</span> build-essential libncurses5-dev u-boot-tools qemu-user-static debootstrap <span class="kw2">git</span> binfmt-support libusb-<span class="nu0">1.0</span>-<span class="nu0">0</span>-dev pkg-config
<span class="kw2">apt-get install</span> gcc-arm-linux-gnueabihf

下载源码

从 github 下载 SPL,U-BOOT,Linux 内核源码。注意 linux-sunxi 超过 3.8G ,耗时最长。如果您曾经下载过这些代码,记得分别用 git pull 更新后再进行后续操作,因为代码仓库每天都有变化。

<span class="kw3">cd</span> <span class="re1">$WORK_DIR</span>
<span class="kw2">git clone</span> git:<span class="sy0">//</span>github.com<span class="sy0">/</span>linux-sunxi<span class="sy0">/</span>u-boot-sunxi.git
<span class="kw2">git clone</span> git:<span class="sy0">//</span>github.com<span class="sy0">/</span>cubieboard2<span class="sy0">/</span>linux-sunxi
<span class="kw2">git clone</span> git:<span class="sy0">//</span>github.com<span class="sy0">/</span>linux-sunxi<span class="sy0">/</span>sunxi-tools.git
<span class="kw2">git clone</span> git:<span class="sy0">//</span>github.com<span class="sy0">/</span>linux-sunxi<span class="sy0">/</span>sunxi-boards.git

编译uboot

 <span class="kw3">cd</span> <span class="re1">$WORK_DIR</span><span class="sy0">/</span>u-boot-sunxi<span class="kw2">make</span> distclean <span class="re2">CROSS_COMPILE</span>=arm-linux-gnueabihf-<span class="kw2">make</span> Cubieboard2 <span class="re2">CROSS_COMPILE</span>=arm-linux-gnueabihf-

得到 u-boot-sunxi-with-spl.bin(同时生成的还有其它几个文件,这里我们只用该文件,注意上面Cubieboard2,最新代码需要首字母大写)

编译kernel

 <span class="kw3">cd</span> <span class="re1">$WORK_DIR</span><span class="sy0">/</span>linux-sunxi<span class="kw2">make</span> <span class="re2">ARCH</span>=arm <span class="re2">CROSS_COMPILE</span>=arm-linux-gnueabihf- cubieboard2_defconfig<span class="kw2">make</span> <span class="re2">ARCH</span>=arm <span class="re2">CROSS_COMPILE</span>=arm-linux-gnueabihf- <span class="re5">-j4</span> uImage modules

得到内核文件 arch/arm/boot/uImage(还有其它内核模块,这里暂时没有用到)

生成 boot.scr和script.bin

在将uboot和kernel烧写到TF卡之前,我们需要先编译生成两个启动参数文件:boot.scr和script.bin。

生成 boot.scr

boot.scr是什么?

根据资料描述(https://github.com/linux-sunxi/u-boot-sunxi/wiki#bootscr-support),u-boot在启动的时候会在第一个分区(FAT/extX格式)寻找/boot.scr或者/boot/boot.scr文件,boot.scr中可以包含用于载入script.bin,kernel,initrd(可选)以及设置内核启动参数的uboot命令。

boot.scr如何生成?

在$WORK_DIR目录新建 boot.cmd 文件,添加以下内容:

setenv bootargs console<span class="sy0">=</span>ttyS0<span class="sy0">,</span><span class="nu0">115200</span> noinitrd disp<span class="sy0">.</span>screen0_output_mode<span class="sy0">=</span>EDID<span class="sy0">:</span>1280x1024p60 init<span class="sy0">=/</span>init root<span class="sy0">=/</span>dev<span class="sy0">/</span>mmcblk0p2 rootfstype<span class="sy0">=</span>ext4 rootwait panic<span class="sy0">=</span><span class="nu0">10</span> $<span class="br0">{</span>extra<span class="br0">}</span>
fatload mmc <span class="nu0">0</span> <span class="nu12">0x43000000</span> boot<span class="sy0">/</span>script<span class="sy0">.</span>bin
fatload mmc <span class="nu0">0</span> <span class="nu12">0x48000000</span> boot<span class="sy0">/</span>uImage
bootm <span class="nu12">0x48000000</span>

详细解释:

1.上述第一行设置uboot的bootargs启动参数,格式为 参数=值,不同参数使用空格分开,其中

  • console=ttyS0,115200 含义为使用特定的串口ttyS0,波特率为 115200
  • noinitrd 含义为不使用ramdisk(内存磁盘)
  • init=/init 含义为内核启起来后,进入系统中运行的第一个脚本
  • root=/dev/mmcblk0p2 含义为指定rootfs的位置为TF卡第二个分区
  • rootfstype=ext4 含义为根文件系统类型
  • rootwait 含义为等待设备/dev/mmcblk0p2就绪后才尝试挂载rootfs
  • panic=10 传递内核参数,当遇到panic(内核严重错误)时等待10秒后重启
  • screen0_output_mode 设置合适的屏幕显示分辨率

更多的参数可以通过查看Linux内核源码目录下Documentation/kernel-parameters.txt文件了解

2.第二行和第三行为将script.bin和内核uImage加载到指定内存地址。fatload是U-Boot中装载linux kernel 到内存的指令。

基本用法:fatload <interface> <dev[:part]> <addr> <filename> <bytes>

  • interface:所用到接口,如:MMC、USB
  • dev [:part]: 文件存放的设备 如:ide 0:1
  • addr: 装载到内存的开始地址。
  • filename: 装载的文件名称。
  • bytes: copy的字节数.

3.第四行bootm 用于将内核映像加载到指定的地址

保存文件后,执行以下命令生成boot.scr:

mkimage <span class="sy0">-</span>C none <span class="sy0">-</span>A arm <span class="sy0">-</span>T script <span class="sy0">-</span>d boot<span class="sy0">.</span>cmd boot<span class="sy0">.</span>scr

生成 script.bin

script.bin是什么?

script.bin是被全志SOC内核驱动或LiveSuit使用的针对特定目标板的二进制配置文件,包含如何设置基于A10/A20目标版的各种外设,端口,I/O针脚信息。

其对应的可读文本文件格式为FEX,可以利用 Sunxi-tools在二进制和文本文件之间进行转换。更多关于FEX配置的信息可以参考http://linux-sunxi.org/Fex_Guide

script.bin如何生成?

首先需要编译sunxi-tools:

<span class="kw3">cd</span> <span class="re1">$WORK_DIR</span><span class="sy0">/</span>sunxi-tools
<span class="kw2">make</span>

得到fex2bin、bin2fex等文件,其中fex2bin能把 *.fex 文件生成 *.bin文件。反之bin2fex可以将得到的*.bin文件生成可读的*.fex文件。

然后编译生成script.bin:

<span class="kw3">cd</span> <span class="re1">$WORK_DIR</span><span class="sy0">/</span>sunxi-boards<span class="sy0">/</span>sys_config<span class="sy0">/</span>a20
<span class="re1">$WORK_DIR</span><span class="sy0">/</span>sunxi-tools<span class="sy0">/</span>fex2bin cubieboard2.fex script.bin

烧写uboot和kernel到TF卡

上面罗嗦了这么多,其实就是为了将uboot和kernel烧写到TF卡上并能够启动,OK,让我们先从分区开始:

A20 芯片上电启动的时候,会读取SD卡最前面的 1M 内容,从而得到 bootloader,所以我们需要把 u-boot 写到SD卡的前1M区间。

其中详细的SD卡布局如下:

起始 大小 用途
0 8KB 存放分区表等内容
8 24KB SPL loader
32 512KB u-boot
544 128KB environment
672 352KB 保留
1024 - 用于剩余分区

接下来,我们开始使用fdisk进行分区(由于sfdisk对部分TF不兼容,故除非你真的知道怎么用sfdisk,否则不要使用):

将TF卡插到电脑上并确认设备名,为不至于混淆,我们使用sdX代替,您需要根据自己的情况修改,如sdb:

<span class="re2">card</span>=<span class="sy0">/</span>dev<span class="sy0">/</span>sdX
<span class="kw2">dd</span> <span class="re2">if</span>=<span class="sy0">/</span>dev<span class="sy0">/</span>zero <span class="re2">of</span>=<span class="co1">${card}</span> <span class="re2">bs</span>=1M <span class="re2">count</span>=<span class="nu0">1</span>      <span class="co0"># 把SD卡前1M的区域填充为0,预留给 u-boot</span>
sfdisk <span class="re5">-R</span> <span class="co1">${card}</span>                             <span class="co0"># 重新读取${card}</span>
<span class="kw2">fdisk</span> <span class="co1">${card}</span>                                 <span class="co0">#使用fdisk进行分区</span>

具体分区步骤如下:

建立第一个分区

root@kubuntu:~/src/u-boot-sunxi# fdisk ${card}
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x911332e8.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)Command (m for help): n                                   #键入n然后回车
Partition type:p   primary (0 primary, 0 extended, 4 free)e   extended
Select (default p):                                       #直接回车
Using default response p
Partition number (1-4, default 1):                        #直接回车
Using default value 1
First sector (2048-15278079, default 2048):               #直接回车
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-15278079, default 15278079): +64M         #键入+64M后回车,即分区大小为64M

建立第二个分区

Command (m for help): n                                   #键入n然后回车
Partition type:p   primary (1 primary, 0 extended, 3 free)e   extended
Select (default p):                                       #直接回车
Using default response p
Partition number (1-4, default 2):                        #直接回车
Using default value 2
First sector (133120-15278079, default 133120):           #直接回车
Using default value 133120
Last sector, +sectors or +size{K,M,G} (133120-15278079, default 15278079):      #直接回车,即第二个分区使用全部剩余空间
Using default value 15278079

接下来指定分区类型:

Command (m for help): t                                   #键入t然后回车
Partition number (1-4): 1                                 #键入1然后回车,即指定第一个分区
Hex code (type L to list codes): c                        #键入c然后回车,即指定第一个分区为vfat
Changed system type of partition 1 to c (W95 FAT32 (LBA))Command (m for help): w                                   #键入w然后回车,保存分区表
The partition table has been altered!Calling ioctl() to re-read partition table.
Syncing disks.

格式化分区:

mkfs.vfat <span class="co1">${card}</span><span class="nu0">1</span>
mkfs.ext4 <span class="co1">${card}</span><span class="nu0">2</span>                                        <span class="co0">#需要稍等片刻</span>

然后写入bootloader:

<span class="kw3">cd</span> <span class="re1">$WORK_DIR</span><span class="sy0">/</span>u-boot-sunxi
<span class="kw2">dd</span> <span class="re2">if</span>=u-boot-sunxi-with-spl.bin <span class="re2">of</span>=<span class="re1">$card</span> <span class="re2">bs</span>=<span class="nu0">1024</span> <span class="re2">seek</span>=<span class="nu0">8</span>

最后安装内核 uImage,设置启动参数:

<span class="kw2">mount</span> <span class="co1">${card}</span><span class="nu0">1</span> <span class="sy0">/</span>mnt
<span class="kw2">mkdir</span> <span class="sy0">/</span>mnt<span class="sy0">/</span>boot
<span class="kw2">cp</span> <span class="re1">$WORK_DIR</span><span class="sy0">/</span>linux-sunxi<span class="sy0">/</span>arch<span class="sy0">/</span>arm<span class="sy0">/</span>boot<span class="sy0">/</span>uImage <span class="sy0">/</span>mnt<span class="sy0">/</span>boot
<span class="kw2">cp</span> <span class="re1">$WORK_DIR</span><span class="sy0">/</span>sunxi-boards<span class="sy0">/</span>sys_config<span class="sy0">/</span>a20<span class="sy0">/</span>script.bin <span class="sy0">/</span>mnt<span class="sy0">/</span>boot
<span class="kw2">cp</span> <span class="re1">$WORK_DIR</span><span class="sy0">/</span>boot.scr <span class="sy0">/</span>mnt<span class="sy0">/</span>
<span class="kw2">sync</span> <span class="sy0">&&</span> <span class="kw2">umount</span> <span class="sy0">/</span>mnt

至此,启动到linux内核的工作已经完成,接下来我们就可以观看linux内核启动过程、进行内核调试了。

打印串口调试信息

通过查看串口输出信息,可以方便我们判断问题所在,进而找到解决问题的方法。

在linux和windows下有多种串口调试工具可供使用,这里仅给出两篇参考文章:

  • http://linux-sunxi.org/Cubieboard/TTL
  • http://cn.cubiebook.org/index.php?title=Cubieboard/串口调试

这里附上笔者的串口输出信息:http://mer.jolladev.net/data/media/cutecom.txt

信息结尾由于无法挂载根文件系统、启动init而等待10秒后重启。

总结

本文参考了众多网络内容,在后面列出了主要文章地址,在此一并感谢。

之所以写这篇内容,是因为从本人入手cubieboard2以来,通过苦寻资料,在各种痛苦与错误的尝试中不断走上了”正道“,深知对于一个没有嵌入式开发基础或开发经验的普通玩家而言,想把各种环节搞清楚是一件很难的事情,故通过大量引用、参考网络内容加上自己的摸索,总结出该文,以期望对新的玩家能够有所帮助;就嵌入式linux而言,整个 加电——启动bootloader——启动内核——加载rootfs流程对于新手会感到非常的模糊,而不知如何下手。本篇内容尽可能详细的描述了利用cubieboard从加电到启动linux内核的整个操作过程,为进一步学习如何构建一个可运行的linux系统打下了基础。后面,将会在此基础上继续介绍如何进一步挂载跟文件系统,启动到shell甚至GUI图形界面,从而构建一个完整、可用的linux系统。

参考

  • http://linux-sunxi.org/Bootable_SD_card
  • http://linux-sunxi.org/Boot
  • https://github.com/linux-sunxi/u-boot-sunxi/wiki
  • http://cn.cubieboard.org/forum.php?mod=viewthread&tid=1108&extra=page%3D1
  • http://blog.csdn.net/yichunjie/article/details/8661176
  • http://blog.csdn.net/abc47bca/article/details/6306005

Bootloader加载过程分析相关推荐

  1. 全志A10/A20 Bootloader加载过程分析

    原文 : http://blog.csdn.net/allen6268198/article/details/12905425 从这里开始:http://linux-sunxi.org/Bootabl ...

  2. 【转】全志A10/A20 Bootloader加载过程分析

    原文 : http://blog.csdn.net/allen6268198/article/details/12905425 从这里开始:http://linux-sunxi.org/Bootabl ...

  3. 转 A10/A20 Bootloader加载过程分析

    A10/A20 Bootloader加载过程分析 注:由于全志A10和A20在加载Bootloader过程方面基本一致,下面仅以A20叙述,但同时也适用于A10.另外在不需要区分Cubieboard1 ...

  4. 转:A10/A20 Bootloader加载过程分析

    来自:http://blog.csdn.net/allen6268198/article/details/12905425 A10/A20 Bootloader加载过程分析 注:由于全志A10和A20 ...

  5. Chromium插件(Plugin)模块(Module)加载过程分析

    在Chromium中,每一个Plugin都对应一个Module,称为Plugin Module.一个Plugin Module可创建多个Plugin Instance.每一个Plugin Instan ...

  6. Android-GnssHal层gps.xxx.so查找与加载过程分析

    Android-GnssHal层gps.xxx.so查找与加载过程分析 gps.xxx.so不是在系统编译的时候直接prelink的而是在运行阶段由gnss hal service动态查找并加载的; ...

  7. HarmonyOS镜像,HarmonyOS驱动加载过程分析

    HDF(硬件驱动程序基础)驱动程序框架为驱动器开发人员提供驱动程序框架功能,包括驱动器加载,驱动服务管理和驱动程序消息传递机制.它旨在构建一个统一的驱动器架构平台,为驾驶开发人员提供更准确,更高效的开 ...

  8. vue项目结构及启动文件加载过程分析

    vue项目结构及启动文件加载过程分析 一.vue项目结构 1.导入项目 准备好开发工具Visual Studio Code,导入生成的项目案例.我的Vue版本: 2.项目目录及文件说明 2.1.项目主 ...

  9. seaJS 模块加载过程分析

    先看一个seajs的官方example,  以下以seajs.use('main')为例, 解析加载mod main的过程 //app.html seajs.use("main") ...

最新文章

  1. 洛谷P1194 买礼物
  2. 软件测试——等价类划分
  3. 解决Eclipse Debug 的source not found问题
  4. java常用代码总结
  5. 苏宁张近东:春节期间拿出3亿补贴一线员工
  6. linux suse最新版本,SUSE Linux Enterprise Server 15 正式发布
  7. 人工神经网络的算法原理,人工智能神经网络算法
  8. 有什么好用的电脑录音软件?
  9. 华为电视测试软件,简单便捷!实测教你华为智慧屏怎么样用USB安装APP
  10. Android如何修改手机文件名称
  11. java助理工程师主要做什么工作,Java助理工程师面试的惨痛教训
  12. 质量管理8D报告详解,附报告模板
  13. 倍加福光电传感器OBE10M-18GM60-SE5-V1
  14. 主存、辅存、内存、外存、存储器是什么?还傻傻分不清楚?看完这一篇就够了
  15. 在 PHP 中从数组中删除一个元素
  16. TensorFlow 中文资源精选,官方网站,安装教程,入门教程,实战项目,学习路径。
  17. 灵魂歌手 演唱:梁博
  18. RXD与TXD如何连接
  19. 亚马逊测评自养号技能知识共享
  20. RK3568触摸屏驱动调试总结

热门文章

  1. ubuntu下安装mysql及常用操作
  2. Spring IO Platform简介及示例
  3. BS版代码生成器 简介
  4. [MS]Microsoft SQL Server 2008 R2 开发版/企业版/标准版
  5. Spring 源码阅读 之 Spring框架加载
  6. spring mvc中两种异常的处理手法
  7. WPF系列(一)第一个WPF应用程序!
  8. legacy bios与uefi两种模式安装windows8操作系统的方法
  9. C运行库和C语言函数库/Microsoft C运行库
  10. Python 应用领域