yocto系列讲解 (实战篇) 51 - 制作boot.img内核镜像

By: fu linux
E-mail: fulinux@sina.com
Blog: https://blog.csdn.net/fulinus
喜欢的盆友欢迎点赞和订阅!
你的喜欢就是我写作的动力!

简单回顾下

继续,上一篇我们完成了 zImage 的编译,
但是我们需要将其制作成类似安卓那样的 boot.img

上传meta到gitee

比如可以自己在gitee上创建一个新的meta-mybsp,参考:yocto-第4篇-创建自己的meta layer

  1. 下载源码和添加layer
poky]$ git clone https://gitee.com/fulinux/meta-mybsp.git #使用自己的meta-mybsp
poky]$ source oe-init-build-env 
build]$ bitbake-layers add-layer ../meta-mybsp #加入conf/bblayers.conf中
  • 1
  • 2
  • 3
  1. 然后,将内核拷贝到recipe目录中:
    我之前有说过我们内核是需要自备的哈,我就没有上传上去,请知悉~
build]$ cd ../meta-mybsp/
meta-mybsp]$ cp <you kernel path> recipes-kernel/linux-msm/ -rf
  • 1
  • 2
  1. 修改build/conf/local.conf:
poky]$ vim build/conf/local.conf
MACHINE ?= "msm8909"
PACKAGE_CLASSES ?= "package_ipk" #有可能你的机器不需要修改哦
  • 1
  • 2
  • 3
  1. 重新source环境,再编译
poky]$ source oe-init-build-env 
build]$ bitbake core-image-minimal
ERROR: Unable to start bitbake server (None)
ERROR: Server log for this session (/home/peeta/poky/build/bitbake-cookerdaemon.log):
--- Starting bitbake server pid 30365 at 2021-04-01 19:00:06.842137 ---
ERROR: Layer meta-mybsp is not compatible with the core layer which only supports these series: dunfell (layer is compatible with gatesgarth)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

上面编译失败了

  1. 修复编译问题
    这个主要是 meta-bsp 中的 meta-mybsp/conf/layer.conf 配置不兼容问题导致的,修改如下:
#LAYERSERIES_COMPAT_meta-mybsp = "gatesgarth" #禁用这个兼容配置,当前我的是dunfell,但是我觉得经常改,还不如不要这个设置
  • 1
  1. 再次编译
build]$ bitbake core-image-minimal  #通用的镜像,就暂时不用考虑文件系统的问题了,这个是迷你版
  • 1

这个过程是不是so easy, 我也只是将这个过程演示给大家看,方便大家能够容易上手,遇到具体问题需要具体分析。
编译过程发现好多这些警告:

NOTE: preferred version 3.18 of linux-msm not available (for item kernel-module-raid1)
NOTE: versions of linux-msm available: 3.18.71
  • 1
  • 2

是不是很烦~ 也很简单,修改如下:

meta-mybsp] vim conf/machine/msm8909.conf
PREFERRED_VERSION_linux-msm ?= "3.18%"
  • 1
  • 2

制作boot.img

好了开始制作我们的 boot.img 之旅。
之所以需要将内核制作成 boot.img ,是因为bootloader( lk )需要吧!没确认~

添加mkbootimg-native的recipe

高通制作 boot.img 需要用到 zImage mkbootimg 工具,zImage已经完成了,现在添加 mkbootimg 工具。因为该工具是在 ubuntu/linux 编译机器上运行的,所以后面通常有recipe后面通常带 native 关键词,并将其放到开发工具类的 recipes-devtools 目录中:

meta-mybsp]$ mkdir -p recipes-devtools/mkbootimg
meta-mybsp]$ cp <some path>/mkbootimg/ recipes-devtools/mkbootimg/ -rf #后续我直接提交到gitee上去
meta-mybsp]$ ls recipes-devtools/mkbootimg/mkbootimg/    
Android.mk  bootimg.h  makefile  mkbootimg.c
  • 1
  • 2
  • 3
  • 4

工具还是挺简单的就一个源码和头文件。现在添加bb文件:

meta-mybsp]$ vim recipes-devtools/mkbootimg/mkbootimg-native_git.bb
# mkbootimg-native

inherit native  #继承了native,就告诉了yocto这个是编译机运行的,在build/tmp/work/x86_64-linux目录下

#这下面一大坨就不看了,就是license和说明啥的。
DESCRIPTION = "Boot image creation tool from Android"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/\
${LICENSE};md5=89aea4e17d99a7cacdbeed46a0096b10"
HOMEPAGE = "http://android.git.kernel.org/?p=platform/system/core.git"

PROVIDES = "mkbootimg-native" #一个别名列表,通过它可以知道一个特定的recipe,就像前面的virtual/kernel

FILESEXTRAPATHS_prepend := "${THISDIR}/:" #指定文件搜索的路径(扩展构建系统在处理recipe和bbappend文件时查找文件和补丁时使用的搜索路径),就是当前bb文件所在目录加进这个变量了, 并且在其他目录前面,优先搜索
SRC_DIR = "mkbootimg" #源码目录,这个变量加上

SRC_URI = "file://mkbootimg/" #本地或远程的源文件的列表, 很多项目源码我都直接放在recipe目录里面了,主要是有时候在源码和bb文件直接切换太麻烦了,所以放一起了,根据需要可以放在其他地方哈。
S = "${WORKDIR}/mkbootimg" #bitbake -e mkbootimg | grep ^S=就知道什么意思了

DEPENDS = "libmincrypt-native" #还需要依赖这个recipe,需要在编译这个之前完成这个recipe

PR = "r6" #这个要不要无所谓

MY_PN = "mkbootimg" #自定义

#指定编译参数,头文件和静态库,因为这个是一个makefile文件的项目,需要指定编译器CC
EXTRA_OEMAKE = "INCLUDES='-Imincrypt' LIBS='${libdir}/libmincrypt.a'"
EXTRA_OEMAKE += "CC=${CC}"

do_configure[noexec]="1" #这个是一个makefile文件的项目,没有配置阶段

do_install() { #重定义安装任务
    install -d ${D}${bindir} #创建这个目录
    install ${MY_PN} ${D}${bindir} #相当于复制:cp mkbootimg ${D}${bindir}
}
  • 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

添加libmincrypt-native的recipe

libmincrypt字面意思是迷你的加密库。

  1. 创建recipe目录和复制源码
meta-mybsp]$ mkdir -p recipes-devtools/libmincrypt/
meta-mybsp]$ cp -rf <some path>/libmincrypt/ recipes-devtools/libmincrypt/
meta-mybsp]$ cd recipes-devtools/libmincrypt/
  • 1
  • 2
  • 3
  1. 创建recipe的bb文件
libmincrypt]$ vim libmincrypt-native_git.bb
# libmincrypt-native
inherit native autotools pkgconfig externalsrc  #这里面重点就是native,说明是在编译机器上运行的库

DESCRIPTION = "Minimalistic encryption library from Android"
HOMEPAGE = "http://developer.android.com/"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/\
${LICENSE};md5=89aea4e17d99a7cacdbeed46a0096b10"

PR = "r1"

EXTERNALSRC = "${THISDIR}/libmincrypt"

EXTRA_OECONF = " --with-core-includes=${S}/"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

后记:使用导入外部代码,会在编译的时候在我的源码目录中生成一些其他文件,导致我的git经常发生变动:

        modified:    libmincrypt/autom4te.cache/output.0
        modified:    libmincrypt/autom4te.cache/output.1
        ...
        modified:   libmincrypt/ltmain.sh
  • 1
  • 2
  • 3
  • 4

因此,这里修改该bb文件,如下:

libmincrypt]$ vim libmincrypt-native_git.bb 
# libmincrypt-native
inherit native autotools pkgconfig

DESCRIPTION = "Minimalistic encryption library from Android"
HOMEPAGE = "http://developer.android.com/"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://${COREBASE}/meta/files/common-licenses/\
${LICENSE};md5=89aea4e17d99a7cacdbeed46a0096b10"

PR = "r1"

FILESEXTRAPATHS_prepend := "${THISDIR}/:"
SRC_DIR = "libmincrypt"
SRC_URI = "file://libmincrypt/"
S = "${WORKDIR}/libmincrypt"

EXTRA_OECONF = " --with-core-includes=${S}/"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  1. 编译和简单验证
build]$ bitbake libmincrypt-native
build]$ file ../meta-mybsp/recipes-devtools/libmincrypt/libmincrypt/oe-workdir/image/home/peeta/poky/build/tmp-msm8909/work/x86_64-linux/libmincrypt-native/git-r1/recipe-sysroot-native/usr/lib/libmincrypt.so.0.0.0 
../meta-mybsp/recipes-devtools/libmincrypt/libmincrypt/oe-workdir/image/home/peeta/poky/build/tmp-msm8909/work/x86_64-linux/libmincrypt-native/git-r1/recipe-sysroot-native/usr/lib/libmincrypt.so.0.0.0: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=eebf1e2e3edb8147c8151c6297635e6a78c19a01, not stripped
  • 1
  • 2
  • 3

重点: ELF 64-bit LSB shared object, x86-64

  1. 准备好libmincrypt项目后开始编译mkboot-native
build]$ bitbake mkbootimg-native
...
g++: error: /home/peeta/poky/build/tmp-msm8909/work/x86_64-linux/mkbootimg-native/git-r6/recipe-sysroot-native/usr/lib/libmincrypt.a: No such file or directory
...
  • 1
  • 2
  • 3
  • 4

不过报错了,看下为什么没有这个“文件”,具体看下:

build]$ ls /home/peeta/poky/build/tmp-msm8909/work/x86_64-linux/mkbootimg-native/git-r6/recipe-sysroot-native/usr/lib/
libltdl.so  libltdl.so.7  libltdl.so.7.3.1  libmincrypt.so  libmincrypt.so.0  libmincrypt.so.0.0.0  pkgconfig
  • 1
  • 2

显然只有动态库,没有静态库。
为什么是静态库?要知道linux类的服务器上运行的程序依赖的库都是需要到/usr/lib或者/lib/查找,或者通过设置库路径的环境变量。我们yocto如果要在编译的过程中安装库显然是不合理的,或者设置环境变量也是不合适的,那么这里就可以通过静态库编译进程序中。

不过,在修改成静态库之前我想先试试看能否修改成动态库:

meta-mybsp]$ vim recipes-devtools/mkbootimg/mkbootimg-native_git.bb
#屏蔽下面这句话
#EXTRA_OEMAKE = "INCLUDES='-Imincrypt' LIBS='${libdir}/libmincrypt.a'"
#添加下面这句话
EXTRA_OEMAKE = "INCLUDES='-Imincrypt' LIBS='-lmincrypt'"
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 再次编译mkbootimg-native
build]$ bitbake mkbootimg-native
#编译成功
  • 1
  • 2
  1. 验证mkbootimg程序:
build]$ file tmp-msm8909/work/x86_64-linux/mkbootimg-native/git-r6/image/home/peeta/poky/build/tmp-msm8909/work/x86_64-linux/mkbootimg-native/git-r6/recipe-sysroot-native/usr/bin/mkbootimg
tmp-msm8909/work/x86_64-linux/mkbootimg-native/git-r6/image/home/peeta/poky/build/tmp-msm8909/work/x86_64-linux/mkbootimg-native/git-r6/recipe-sysroot-native/usr/bin/mkbootimg: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /home/peeta/poky/build/tmp-msm8909/sysroots-uninative/x86_64-linux/lib/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=44e32c6abf2f477aefa2d0b0613449e772cbd1d4, not stripped
build]$ ./tmp-msm8909/work/x86_64-linux/mkbootimg-native/git-r6/image/home/peeta/poky/build/tmp-msm8909/work/x86_64-linux/mkbootimg-native/git-r6/recipe-sysroot-native/usr/bin/mkbootimg 
error: no output filename specified
usage: mkbootimg
       --kernel <filename>
       --ramdisk <filename>
       [ --second <2ndbootloader-filename> ]
       [ --cmdline <kernel-commandline> ]
       [ --board <boardname> ]
       [ --base <address> ]
       [ --pagesize <pagesize> ]
       [ --ramdisk_offset <ramdisk_offset> ]
       [ --dt <filename> ]
       [ --tags-addr <address> ]
       -o|--output <filename>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

说明单独编译mkbootimg程序也是OK的,没有出现动态库找不到的问题,我们就不费那个劲去编译静态库了。
应该是x86_64-linux/lib/ld-linux-x86-64.so.2加载动态库的工具做了这方面工作。

  1. 在kernel的recipe文件中添加mkbootimg依赖
    因为我们需要在kernel的recipe中使用 mkbootimg-native recipe将zImage制作成 boot.img ,因此需要添加相应的依赖,如下:
meta-mybsp]$ vim recipes-kernel/linux-msm/linux-msm_3.18.bb
...
inherit kernel kernel-yocto
DEPENDS_append = "mkbootimg-native" #添加该行
...
  • 1
  • 2
  • 3
  • 4
  • 5

编译后可以看到这个:

build]$ cd tmp-msm8909/work/msm8909-poky-linux-gnueabi/linux-msm/3.18.71-r0/
[peeta@peeta-OptiPlex-7050 3.18.71-r0]$ find -iname mkbootimg
./recipe-sysroot-native/usr/bin/mkbootimg
  • 1
  • 2
  • 3

8.在do_install_append函数中添加mkbootimg命令

do_install_append() {
    mkbootimg --kernel ${D}/${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}-${KERNEL_VERSION} \
        --ramdisk /dev/null \
        --cmdline "${KERNEL_CMD_PARAMS}" \
        --pagesize ${PAGE_SIZE} \
        --base ${KERNEL_BASE} \
        --ramdisk_offset 0x0 \
        ${extra_mkbootimg_params} --output ${D}/${KERNEL_IMAGEDEST}/${BOOTIMAGE_TARGET}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

可见上面使用mkbootimg前面不需要加任何的路径即可执行,这个太棒了!
其中
${D}/${KERNEL_IMAGEDEST}/${KERNEL_IMAGETYPE}-${KERNEL_VERSION}
指向的就是
/home/peeta/poky/build/tmp-msm8909/work/msm8909-poky-linux-gnueabi/linux-msm/3.18.71-r0/image/boot/zImage-3.18.71

使用到了 KERNEL_CMD_PARAMS 变量,在 msm8909.conf 定义如下:

KERNEL_CMD_PARAMS = "noinitrd console=ttyHSL0,115200,n8 androidboot.hardware=qcom ehci-hcd.park=3 msm_rtb.filter=0x37 lpm_levels.sleep_disabled=1 rootwait androidboot.bootdevice=7824900.sdhci"
  • 1

其中PAGE_SIZE、KERNEL_BASE、BOOTIMAGE_TARGET三个变量未定义,我们在config文件中定义如下:

meta-mybsp]$ vim conf/machine/msm8909.conf
PAGE_SIZE ?= "4096" #页通常是4K
KERNEL_BASE ?= "0x81C00000" #这个是内核加载到DRAM中的起始地址吧~
BOOTIMAGE_TARGET ?= "${MACHINE}-boot.img" #输出的镜像名,前面加了一个机器名msm8909
  • 1
  • 2
  • 3
  • 4

还有这个 extra_mkbootimg_params 变量,主要是预留这个后期扩展使用,现在空着不管不顾。

  1. 编译过程遇到这个问题:
NOTE: Executing Tasks
ERROR: linux-msm-3.18.71-r0 do_package: QA Issue: linux-msm: Files/directories were installed but not shipped in any package:
  /boot/msm8909-boot.img
Please set FILES such that these items are packaged. Alternatively if they are unneeded, avoid installing them or delete them within do_install.
linux-msm: 1 installed and not shipped files. [installed-vs-shipped]
ERROR: linux-msm-3.18.71-r0 do_package: Fatal QA errors found, failing task.
ERROR: Logfile of failure stored in: /home/peeta/poky/build/tmp-msm8909/work/msm8909-poky-linux-gnueabi/linux-msm/3.18.71-r0/temp/log.do_package.26642
ERROR: Task (/home/peeta/poky/meta-mybsp/recipes-kernel/linux-msm/linux-msm_3.18.bb:do_package) failed with exit code '1'
NOTE: Tasks Summary: Attempted 509 tasks of which 493 didn't need to be rerun and 1 failed.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

错误提示说安装了一个没有shipped的文件,就是msm8909-boot.img文件,该如何处理呢?

不过也给了提示,让我们设置FILES和[installed-vs-shipped],于是我们在bb文件中添加如下内容:

FILES_${PN} += "/${KERNEL_IMAGEDEST}/${BOOTIMAGE_TARGET}"
INSANE_SKIP_${PN} := "installed-vs-shipped"
  • 1
  • 2
  1. 再次编译执行成功:
build]$ ls tmp-msm8909/work/msm8909-poky-linux-gnueabi/linux-msm/3.18.71-r0/image/boot/
config-3.18.71          msm8909-boot.img    vmlinux-3.18.71
Module.symvers-3.18.71  System.map-3.18.71  zImage-3.18.71
  • 1
  • 2
  • 3

生成了我们需要的 msm8909-boot.img 镜像文件。
不过在 tmp-msm8909/deploy/images/msm8909/ 目录中没有 msm8909-boot.img 镜像文件

build]$ ls tmp-msm8909/deploy/images/msm8909/
modules--3.18.71-r0-msm8909-20210407122010.tgz  zImage
modules-msm8909.tgz                             zImage--3.18.71-r0-msm8909-20210407122010.bin
zImage-msm8909.bin
  • 1
  • 2
  • 3
  • 4
  1. 可以通过do_deploy函数中进行安装:
do_deploy_append() {
    install -d ${DEPLOY_DIR_IMAGE}
    install ${D}/${KERNEL_IMAGEDEST}/${BOOTIMAGE_TARGET} ${DEPLOY_DIR_IMAGE}
    install ${D}/${KERNEL_IMAGEDEST}/vmlinux-${KERNEL_VERSION} ${DEPLOY_DIR_IMAGE} #vmlinux对于高通抓dump有用,也导出来
}
  • 1
  • 2
  • 3
  • 4
  • 5

编译后就有了:

build]$ bitbake virtual/kernel
build]$ ls tmp-msm8909/deploy/images/msm8909/
modules--3.18.71-r0-msm8909-20210408105958.tgz  zImage
modules-msm8909.tgz                             zImage--3.18.71-r0-msm8909-20210408105958.bin
msm8909-boot.img                                zImage-msm8909.bin
vmlinux-3.18.71
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

刷机跑一跑进行验证

  1. 刷机
C:\Users\peeta.chen>fastboot flash boot U:\poky\build\tmp-msm8909\deploy\images\msm8909\msm8909-boot.img
Sending 'boot' (8524 KB)                           OKAY [  0.369s]
Writing 'boot'                                     OKAY [  0.262s]
Finished. Total time: 0.660s
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述
不过在bootloader启动阶段解析设备树DTB文件出错了:
在这里插入图片描述

[840] Unable to locate /bootselect partition
[850] Loading (boot) image (8728576): start
[910] Loading (boot) image (8728576): done
[920] use_signed_kernel=1, is_unlocked=1, is_tampered=0.
[920] Uncpmpressed kernel in use
[920] Kernel image not patched..Unable to locate dt offset
[940] DTB offset is incorrect, kernel image does not have appended DTB
[940] Device info 0x000000f5/00020000/0x00010008/0, pmic 0x1010d/0x0/0x0/0x0
[950] ERROR: Appended Device Tree Blob not found
[950] ERROR: Could not do normal boot. Reverting to fastboot mode.
[970] battery is not present
[970] fastboot_init()
[970] Loading keystore failed status 5 [1070] USB init ept @ 0x8f6ca000
[1090] udc_start()
[1190] -- reset --
[1190] -- portchange --
[1310] fastboot: processing commands
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

经过一番捣鼓,发现kernel的的镜像类型有个这个类型: zImage-dtb

[peeta@peeta-OptiPlex-7050 3.18.71]$ grep -i zImage-dtb -r .
arch/arm/Kconfig:1923:    The image will built in arch/arm/boot/zImage-dtb
arch/arm/Kconfig:1930:    building a concatenated zImage-dtb.
arch/arm/boot/Makefile:70:$(obj)/zImage-dtb:    $(obj)/zImage $(DTB_OBJS) FORCE
arch/arm/Makefile:291:KBUILD_IMAGE := zImage-dtb
arch/arm/Makefile:331:zImage-dtb: vmlinux scripts dtbs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

大体的意思是zImage和设备树的dtb两个镜像文件是拼接在一起的~

直接和kernel编译在一起,生成zImage-dtb,dtb的位置在kernel起始地址偏移0x2C的位置,然后和kernel一起打包到bootimage里。
https://blog.csdn.net/chenzhen1080/article/details/101000470

  1. 于是修改msm8909.conf文件中的 KERNEL_IMAGETYPE ,如下:
meta-mybsp]$ vim conf/machine/msm8909.conf
...
KERNEL_IMAGETYPE = "zImage-dtb"
  • 1
  • 2
  • 3
  1. 再次编译,然后刷机
C:\Users\peeta.chen>fastboot flash boot U:\poky\build\tmp-msm8909\deploy\images\msm8909\msm8909-boot.img
Sending 'boot' (19236 KB)                          OKAY [  0.821s]
Writing 'boot'                                     OKAY [  0.539s]
Finished. Total time: 1.392s

C:\Users\peeta.chen>fastboot reboot
Rebooting
Finished. Total time: 0.007s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在串口中打印的内容截图:
在这里插入图片描述
下一篇讲解如何添加bootloader(或者叫lk)

给我点个赞加个关注呗!万分感谢!
在这里插入图片描述