[uboot] uboot启动kernel篇(一)——Legacy-uImage & FIT-uImage

转载地址:https://blog.youkuaiyun.com/ooonebook/article/details/53495002

一、uImage

编译kernel之后,会生成Image或者压缩过的zImage。但是这两种镜像的格式并没有办法提供给uboot的足够的信息来进行load、jump或者验证操作等等。因此,uboot提供了mkimage工具,来将kernel制作为uboot可以识别的格式,将生成的文件称之为uImage。 
uboot支持两种类型的uImage。

  • Legacy-uImage 
    在kernel镜像的基础上,加上64Byte的信息提供给uboot使用。

  • FIT-uImage 
    以类似FDT的方式,将kernel、fdt、ramdisk等等镜像打包到一个image file中,并且加上一些需要的信息(属性)。uboot只要获得了这个image file,就可以得到kernel、fdt、ramdisk等等镜像的具体信息和内容。

Legacy-uImage实现较为简单,并且长度较小。但是实际上使用较为麻烦,需要在启动kernel的命令中额外添加fdt、ramdisk的加载信息。 
而FIT-uImage实现较为复杂,但是使用起来较为简单,兼容性较好,(可以兼容多种配置)。但是需要的额外信息也较长。

二、Legacy-uImage

1、使能需要打开的宏

CONFIG_IMAGE_FORMAT_LEGACY=y
  •  

注意,这个宏在自动生成的autoconf.mk中会自动配置,不需要额外配置。

2、如何制作 & 使用

(1)工具mkimage 
编译完uboot之后会在uboot的tools目录下生成mkimage可执行文件 
(2)命令

mkimage -A arm -O linux -C none -T kernel -a 0x20008000 -e 0x20008040 -n Linux_Image -d zImage uImage 

各个参数意义如下
Usage: mkimage -l image
          -l ==> list image header information
       mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
          -A ==> set architecture to 'arch'  // 体系
          -O ==> set operating system to 'os' // 操作系统
          -T ==> set image type to 'type' // 镜像类型
          -C ==> set compression type 'comp' // 压缩类型
          -a ==> set load address to 'addr' (hex) // 加载地址
          -e ==> set entry point to 'ep' (hex) // 入口地址
          -n ==> set image name to 'name' // 镜像名称,注意不能超过32B
          -d ==> use image data from 'datafile' // 输入文件
          -x ==> set XIP (execute in place) 

(3)使用 
将生成的Legacy-uImage下载到参数中指定的load address中,使用bootm ‘实际load address’命令跳转到kernel中。 
但是注意,如果使用Legacy-uImage后面还需要跟上文件系统的ram地址以及dtb的ram地址,否则可能会导致bootm失败。 
格式如下:

bootm Legacy-uImage加载地址 ramdisk加载地址 dtb加载地址
  •  

3、和zImage的区别

-rw-rw-rw-  1 hlos hlos 1560120 Dec  5 14:46 uImage
-rwxrwxrwx  1 hlos hlos 1560056 Nov 30 15:42 zImage*

可以看出uImage比zImage多了64Byte,通过对比可以发现这64Byte的数据是加载zImage的头部的。 
直接查看这64Byte的数据,通过od命令查看如下:

hlos@node4:boot$ od -tx1 -tc -Ax -N64 uImage
000000  27  05  19  56  5a  f3  f7  8e  58  45  0d  3d  00  17  cd  f8
         ' 005 031   V   Z 363 367 216   X   E  \r   =  \0 027 315 370
000010  20  00  80  00  20  00  80  40  e2  4b  43  b6  05  02  02  00
            \0 200  \0      \0 200   @ 342   K   C 266 005 002 002  \0
000020  4c  69  6e  75  78  5f  49  6d  61  67  65  00  00  00  00  00
         L   i   n   u   x   _   I   m   a   g   e  \0  \0  \0  \0  \0
000030  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
        \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0

Legacy-uImage是在zImage的基础上加上64Byte的头部。 
下面通过Legacy-uImage的头部数据结构来解析这串数据。

4、格式头说明

uboot用image_header来表示Legacy-uImage的头部

typedef struct image_header {
    __be32      ih_magic;   /* Image Header Magic Number    */   // 幻数头,用来校验是否是一个Legacy-uImage
    __be32      ih_hcrc;    /* Image Header CRC Checksum    */ // 头部的CRC校验值
    __be32      ih_time;    /* Image Creation Timestamp */ // 镜像创建的时间戳
    __be32      ih_size;    /* Image Data Size      */ // 镜像数据长度
    __be32      ih_load;    /* Data  Load  Address      */ // 加载地址
    __be32      ih_ep;      /* Entry Point Address      */ // 入口地址
    __be32      ih_dcrc;    /* Image Data CRC Checksum  */ // 镜像的CRC校验
    uint8_t     ih_os;      /* Operating System     */ // 操作系统类型
    uint8_t     ih_arch;    /* CPU architecture     */ // 体系 
    uint8_t     ih_type;    /* Image Type           */ // 镜像类型
    uint8_t     ih_comp;    /* Compression Type     */ // 压缩类型
    uint8_t     ih_name[IH_NMLEN];  /* Image Name       */ // 镜像名
} image_header_t;
#define IH_NMLEN        32  /* Image Name Length        */

可以发现这个头部就是64Byte。根据上述3来说明一下这个数据结构

  • ih_magic 
    27 05 19 56 
    头部幻数,用来判断这个是否是Legacy-uImage的头部。为0x27051956则表示是一个Legacy-uImage。
  • ih_size 
    00 17 cd f8 
    数据镜像长度。这里是0x17cdf8,也就是1560056,和我们前面测得的zImage的长度一致。
  • ih_load 
    20 00 80 00 
    加载地址,也就是0x20008000, 和我们执行mkimage使用的参数一致。
  • ih_ep 
    20 00 80 40 
    入口地址,也就是0x20008040, 和我们执行mkimage使用的参数一致。

三、FIT-uImage

0、原理说明

flattened image tree,类似于FDT(flattened device tree)的一种实现机制。其通过一定语法和格式将一些需要使用到的镜像(例如kernel、dtb以及文件系统)组合到一起生成一个image文件。其主要使用四个组件。

  • its文件 
    image source file,类似于dts文件,负责描述要声称的image的的信息。需要自行进行构造。
  • itb文件 
    最终得到的image文件,类似于dtb文件,也就是uboot可以直接对其进行识别和解析的FIT-uImage。
  • mkimage 
    mkimage则负责dtc的角色,用于通过解析its文件、获取对应的镜像,最终生成一个uboot可以直接进行识别和解析的itb文件。
  • image data file 
    实际使用到的镜像文件。

mkimage将its文件以及对应的image data file,打包成一个itb文件,也就是uboot可以识别的image file(FIT-uImage)。我们将这个文件下载到么memory中,使用bootm命令就可以执行了。

1、使能需要打开的宏

CONFIG_FIT=y
  •  

2、如何制作 & 使用

(1)its文件制作 
因为mkimage是根据its文件中的描述来打包镜像生成itb文件(FIT-uImage),所以首先需要制作一个its文件,在its文件中描述需要被打包的镜像,主要是kernel镜像,dtb文件,ramdisk镜像。 
简单的例子如下:

/*
 * U-Boot uImage source file for "X project"
 */

/dts-v1/;

/ {
    description = "U-Boot uImage source file for X project";
    #address-cells = <1>;

    images {
        kernel@tiny210 {
            description = "Unify(TODO) Linux kernel for project-x";
            data = /incbin/("/home/hlos/code/xys/temp/project-x/build/out/linux/arch/arm/boot/zImage");
            type = "kernel";
            arch = "arm";
            os = "linux";
            compression = "none";
            load = <0x20008000>;
            entry = <0x20008000>;
        };
        fdt@tiny210 {
            description = "Flattened Device Tree blob for project-x";
            data = /incbin/("/home/hlos/code/xys/temp/project-x/build/out/linux/arch/arm/boot/dts/s5pv210-tiny210.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        ramdisk@tiny210 {
            description = "Ramdisk for project-x";
            data = /incbin/("/home/hlos/code/xys/temp/project-x/build/out/rootfs/initramfs.gz");
            type = "ramdisk";
            arch = "arm";
            os = "linux";
            compression = "gzip";
        };
    };

    configurations {
        default = "conf@tiny210";
        conf@tiny210 {
            description = "Boot Linux kernel with FDT blob";
            kernel = "kernel@tiny210";
            fdt = "fdt@tiny210";
            ramdisk = "ramdisk@tiny210";
        };
    };
};
  • 语法可以参考蜗窝科技的u-boot FIT image介绍 
    注意,可以有多个kernel节点或者fdt节点等等,兼容性更强。同时,可以有多种configurations,来对kernel、fdt、ramdisk来进行组合,使FIT-uImage可以兼容于多种板子,而无需重新进行编译烧写。

(2)生成FIT-uImage 
生成的命令相对Legacy-uImage较为简单,因为信息都在its文件里面描述了

mkimage -f ITS文件 要生成的ITB文件,如下:
${UBOOT_OUT_DIR}/tools/mkimage -f ${UIMAGE_ITS_FILE} ${UIMAGE_ITB_FILE}

最终在project X项目上生成了xprj_uImage.itb,这就是我们需要的FIT-uImage文件。

(3)使用 
将生成的FIT-uImage下载到参数中指定的load address中,使用bootm ‘实际load address’命令跳转到kernel中。 
uboot会自动解析出FIT-uImage中,kernel、ramdisk、dtb的信息,使用起来相当方便。

3、简单说明

FIT-uImage的格式类似于DTB。uboot会去解析出FIT-uImage中的configurations节点,根据节点选择出需要的kernel、dtb、rootfs。因此,在节点的基础上,添加很多节点信息,提供uboot使用。

&lt;think&gt;好的,用户的问题是关于在编译Linux 4.19-rc3内核后,使用U-Boot引导时卡在&ldquo;Starting kernel ...&rdquo;的情况,特别是针对mini2440开发板。我需要步步分析可能的原因和解决方案。 首先,回忆下这个问题的常见原因。卡在&ldquo;Starting kernel ...&rdquo;通常意味着内核启动过程中遇到了严重错误,可能无法正确初始化硬件或跳转到内核入口点。可能的原因包括内核配置错误、设备树(DTB)问题、U-Boot参数设置不当、内核镜像格式或加载地址错误,以及串口驱动或早期控制台配置问题。 接下来,需要具体针对mini2440的情况来考虑。mini2440是基于ARM9的处理器,属于较旧的硬件,可能有些特定的配置需求。例如,内核配置中需要包含对S3C2440处理器的支持,以及相关的驱动如串口驱动、NAND Flash驱动等。同时,设备树是否正确生成和加载也是关键,因为较新的内核版本可能依赖设备树来配置硬件。 然后,检查U-Boot的环境变量,尤其是bootcmd和bootargs。确保bootargs中的控制台参数正确指定了串口设备和波特率,比如console=ttySAC0,115200。另外,内核镜像的加载地址是否正确,是否与U-Boot的加载地址致,例如是否从0x30008000启动。 内核镜像的格式也是个需要注意的点。旧版U-Boot可能需要使用uImage格式,而不是zImage,因为uImage包含U-Boot的头部信息。需要确认生成的是否为正确的uImage,并且使用mkimage工具处理过。 此外,串口驱动的兼容性问题可能导致控制台输出无法显示,进而看起来像是内核卡住。需要确保内核配置中启用了正确的串口驱动,比如S3C2440的串口驱动,并且设备树中正确配置了串口节点。 可能的解决步骤包括:检查内核配置,确保处理器和必要驱动启用;验证设备树的正确性;检查U-Boot环境变量;确认内核镜像格式和加载地址;尝试启用早期调试选项,如earlyprintk和earlycon;检查硬件连接,如串口线是否正确。 最后,如果以上步骤无法解决,可能需要查阅社区或类似问题的经验,看看是否有特定的补丁或配置调整适用于mini2440和这个内核版本的组合。可能需要启用更多的调试选项,甚至逐步跟踪内核启动过程,以确定具体的故障点。&lt;/think&gt;针对Linux 4.19-rc3内核在mini2440开发板上U-Boot引导卡在&quot;Starting kernel...&quot;的问题,以下是系统性排查指南: --- ### 、常见原因分析 1. **内核配置问题** - 缺少S3C2440处理器支持 - 未启用关键驱动(如NAND Flash控制器、DM9000网卡) - 控制台串口驱动未正确配置(`CONFIG_SERIAL_S3C24XX=y`) 2. **设备树(DTB)问题** - 未生成或加载正确的设备树二进制文件(如`s3c2440-mini2440.dtb`) - 设备树中串口/内存节点配置错误 3. **U-Boot参数错误** - 内核加载地址不正确(应匹配`CONFIG_S3C2440_PHYS_OFFSET=0x30000000`) - `bootargs`未正确设置控制台参数: ```bash setenv bootargs console=ttySAC0,115200 root=/dev/mtdblock3 rootfstype=jffs2 ``` 4. **镜像格式问题** - U-Boot可能需要`uImage`而非`zImage` - 未使用`mkimage`添加U-Boot头: ```bash mkimage -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -n Linux-4.19.0 -d zImage uImage ``` --- ### 二、关键调试步骤 1. **验证U-Boot环境变量** ```bash # 确认加载地址与内核配置致 setenv loadaddr 0x30008000 # 确认bootm命令参数 setenv bootcmd &#39;nand read ${loadaddr} 0x60000 0x300000; bootm ${loadaddr}&#39; ``` 2. **启用早期调试输出** 在内核配置中: ```bash CONFIG_DEBUG_LL=y # 启用低级调试 CONFIG_EARLY_PRINTK=y # 早期控制台输出 CONFIG_DEBUG_UNCACHED=y # 避免缓存问题 ``` 在设备树中添加: ```dts chosen { bootargs = &quot;earlycon=s3c2410,0x50000000 console=ttySAC0,115200&quot;; }; ``` 3. **检查内存映射** - 确认内核`phys_offset`与U-Boot- 验证`CONFIG_PAGE_OFFSET=0xC0000000`(ARM32标准配置) --- ### 三、硬件兼容性注意 1. **NAND Flash分区表** ```bash # 典型mini2440分区布局 setenv mtdparts mtdparts=nand:256k@0(bootloader),128k(params),5m(kernel),-(rootfs) ``` 2. **串口连接验证** - 确认使用开发板上的`ttySAC0`(非ttyS0) - 检查波特率是否匹配(115200 8N1) --- ### 四、测试建议 1. **最小化内核测试** ```bash # 编译仅含基本功能的内核 make menuconfig # 禁用模块化:取消CONFIG_MODULES # 仅保留以下驱动: CONFIG_ARM_MINI2440=y CONFIG_MTD_NAND_S3C2410=y CONFIG_FB_S3C2410=y ``` 2. **使用JTAG调试** 如果仍无法启动,可通过OpenOCD+JTAG: ```bash halt arm7_9 sw_bkpts enable load_image uImage 0x30008000 resume 0x30008000 ``` --- ### 五、已知补丁需求 该内核版本可能需要针对mini2440的补丁: ```bash # 应用S3C24XX DMA修复补丁 git apply 0001-ARM-s3c24xx-fix-dma-subsystem-initialization.patch ``` 建议参考mini2440社区维护的分支: [https://github.com/legacy-embedded/linux/tree/mini2440](https://github.com/legacy-embedded/linux/tree/mini2440) --- 通过以上步骤逐步排查,80%的问题可定位到设备树配置或U-Boot参数错误。若仍无法解决,建议捕获启动时的JTAG调试信息或使用示波器检测CPU复位信号。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值