zoukankan      html  css  js  c++  java
  • 使用mkbootfs制作ramdisk根文件系统

    环境

    Qemu:QEMU emulator version 3.1.0
    Linux:Linux-4.14.13
    工具链:arm-none-linux-gnueabi-gcc  (gcc version 4.8.3 20140320)
    Android:7.1.2
    busybox:BusyBox v1.24.2
     

    概述

             Android系统使用的根文件系统是用mkbootfs和minigzip制作的,其中mkbootfs用于将根文件系统打包成cpio格式,也可以用cpio工具来打包,将来Linux内核在启动时会调用init/initramfs.c中的函数unpack_to_rootfs对cpio格式进行解包[调用路径:start_kernel --> rest_init --> kernel_init --> kernel_init_freeable --> do_basic_setup --> do_initcalls --> do_initcall_level --> do_one_initcall --> populate_rootfs --> unpack_to_rootfs],在内存中构造出根文件系统结构,mkbootfs工具是Android自己实现的,支持的功能也比cpio弱很多。minigzip也是Android实现的一个压缩工具,是对gzip的简化。
            minigzip的源码位于:external/zlib/
            mkbootfs的源码位于:system/core/cpio/mkbootfs.c
            不过需要注意mkbootfs的功能要比cpio弱,从mkbootfs.c的代码注释中可以看出来:
    /* NOTES
    **
    ** - see buffer-format.txt from the linux kernel docs for
    **   an explanation of this file format
    ** - dotfiles are ignored
    ** - directories named 'root' are ignored
    ** - device notes, pipes, etc are not supported (error)
    */

        上面的信息说明了如下几点:

    1. 对cpio格式的说明,Linux内核文档Documentation/early-userspace/buffer-format.txt中有详细说明说明:
    The full format of the initramfs buffer is defined by the following
    grammar, where:
            *       is used to indicate "0 or more occurrences of"
            (|)     indicates alternatives
            +       indicates concatenation
            GZIP()  indicates the gzip(1) of the operand
            ALGN(n) means padding with null bytes to an n-byte boundary
    
            initramfs  := ("" | cpio_archive | cpio_gzip_archive)*
    
            cpio_gzip_archive := GZIP(cpio_archive)
    
            cpio_archive := cpio_file* + (<nothing> | cpio_trailer)
    
            cpio_file := ALGN(4) + cpio_header + filename + "" + ALGN(4) + data
    
            cpio_trailer := ALGN(4) + cpio_header + "TRAILER!!!" + ALGN(4)

    2. 名为"."的文件会被忽略,不会进行打包。

    3. 名为"root"的文件也会被忽略,不会进行打包。
    4. 不支持设备节点以及管道文件。所以在使用mkbootfs时,需要确保被打包的路径下没有这两种文件,否者会导致错误,并且Linux内核也无法正常访问指定的文件。
     
       此外,在使用mkbootfs时还需要注意的时,mkbootfs会对打包的文件的权限以及uid和gid进行修改(在函数fix_stat中),有可能会遇到本来具备可执行权限的文件,在用mkbootfs打包成cpio格式后,该文件的可执行权限丢失了,比如/etc/init.d/rcS。
     

    用法

    lib_path=`readlink -f ./lib`
    bin_path=`readlink -f ./bin/`
    
    export LD_LIBRARY_PATH=${lib_path}:$LD_LIBRARY_PATH
    export PATH=${bin_path}:$PATH
    
    rm -f ramdisk.img ramdisk.cpio
    rm -rf ./tmp/
    
    # pack
    pushd rootfs2
    mkbootfs -f ../config.txt . | minigzip > ../ramdisk.img
    mkbootfs -f ../config.txt . > ../ramdisk.cpio
    popd
    
    # unpack
    mkdir -p tmp
    pushd tmp
    cpio -i < ../ramdisk.cpio
    popd

    其中config.txt是一个配置文件,内容如下:

    etc/init.d/rcS 0 0 0755
     0 0 0744

    第1行,把"etc/init.d/rcS"文件的uid设置为0,gid设置为0,权限设置为0755

    第2行,所有其他文件的uid都设置0,gid也设置为0,权限设置为0744
    需要注意的是,第2行开始有一个空格,并且需要放在最后一行,对具体文件的设置要放到前面。详见mkbootfs.c中函数read_canned_config。
     
        如果没有个指定config.txt,那么会使用Android代码中自带的配置机制[在fix_stat中会调用fs_config],功能要比config.txt更完善,如果在使用mkbootfs时还设置了-d <path>,那么函数fs_config会优先使用<path>/system/etc/fs_config_dirs和<path>/system/etc/fs_config_files中描述的规则,前者针对目录,后者针对其他文件。如果没有给mkbootfs传递-d <path>参数,那么使用Android在源码中指定的规则,它们存放在两个数组中,一个针对目录,一个针对其他文件:
     
    针对目录的配置规则:
    /* Rules for directories.
    ** These rules are applied based on "first match", so they
    ** should start with the most specific path and work their
    ** way up to the root.
    */
    
    static const struct fs_path_config android_dirs[] = { 
        { 00770, AID_SYSTEM, AID_CACHE,  0, "cache" },
        { 00500, AID_ROOT,   AID_ROOT,   0, "config" },
        { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
        { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
        { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" },
        { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
        { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
        { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
        { 00771, AID_SHELL,  AID_SHELL,  0, "data/local" },
        { 01771, AID_SYSTEM, AID_MISC,   0, "data/misc" },
        { 00770, AID_DHCP,   AID_DHCP,   0, "data/misc/dhcp" },
        { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
        { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
        { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
        { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest" },
        { 00750, AID_ROOT,   AID_SHELL,  0, "data/nativetest64" },
        ... ...

    针对其他文件的规则:

    static const struct fs_path_config android_files[] = {
        { 00440, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.rc" },
        { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.goldfish.sh" },
        { 00550, AID_ROOT,      AID_SHELL,     0, "system/etc/init.ril" },
        { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/ppp/*" },
        { 00555, AID_ROOT,      AID_ROOT,      0, "system/etc/rc.*" },
        { 00440, AID_ROOT,      AID_ROOT,      0, "system/etc/recovery.img" },
        { 00444, AID_ROOT,      AID_ROOT,      0, conf_dir + 1 },
        { 00444, AID_ROOT,      AID_ROOT,      0, conf_file + 1 },
        { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app/*" },
        { 00644, AID_MEDIA_RW,  AID_MEDIA_RW,  0, "data/media/*" },
        { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-private/*" },
        { 00644, AID_SYSTEM,    AID_SYSTEM,    0, "data/app-ephemeral/*" },
        { 00644, AID_APP,       AID_APP,       0, "data/data/*" },
        { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest/tests.txt" },
        { 00640, AID_ROOT,      AID_SHELL,     0, "data/nativetest64/tests.txt" },
        ... ...

    验证

    1.  使用压缩格式的ramdisk.img (mkbootfs -f ../config.txt . | minigzip > ../ramdisk.img)
    kernel_dir=./Linux-4.14.13
    kernel_image=${kernel_dir}/arch/arm/boot/zImage
    dtb_image=${kernel_dir}/arch/arm/boot/dts/vexpress-v2p-ca9.dtb
    qemu_path=/home/pengdonglin/disk_ext/Qemu/qemu-3.1.0/build/install/bin
    
    ${qemu_path}/qemu-system-arm 
        -M vexpress-a9 
        -m 1024M 
        -smp 1 
        -kernel ${kernel_image} 
        -nographic 
        -append "root=/dev/ram0 rw rootfstype=ramfs console=ttyAMA0 init=/init ignore_loglevel" 
        -initrd ./rootfs/ramdisk.img 
        -dtb ${dtb_image}
    部分启动log:
    [    0.609270] Trying to unpack rootfs image as initramfs...
    [    0.965940] Freeing initrd memory: 3616K
     
    2. 使用非压缩的ramdisk.cpio (mkbootfs -f ../config.txt . > ../ramdisk.cpio)
    kernel_dir=./Linux-4.14.13
    kernel_image=${kernel_dir}/arch/arm/boot/zImage
    dtb_image=${kernel_dir}/arch/arm/boot/dts/vexpress-v2p-ca9.dtb
    qemu_path=/home/pengdonglin/disk_ext/Qemu/qemu-3.1.0/build/install/bin
    
    ${qemu_path}/qemu-system-arm 
        -M vexpress-a9 
        -m 1024M 
        -smp 1 
        -kernel ${kernel_image} 
        -nographic 
        -append "root=/dev/ram0 rw rootfstype=ramfs console=ttyAMA0 init=/init ignore_loglevel" 
        -initrd ./rootfs/ramdisk.cpio 
        -dtb ${dtb_image}
     
    部分启动log:
    [    0.610055] Trying to unpack rootfs image as initramfs...
    [    0.760468] Freeing initrd memory: 7040K
    此外,Linux内核本身也支持在编译时将指定的外部根文件系统编译成cpio.gz格式,然后跟Linux内核链接到一起,在启动时就不需要指定initrd了,Linux内核支持的打包工具usr/gen_init_cpio.c也比mkbootfs强大:
    配置内核:
    General setup --->
            [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
            (/home/pengdonglin/aarch32/rootfs/rootfs) Initramfs source file(s)
     
    Linux内核对这部分的处理请参考usr/Makefile,下面是加入上面的配置之后的部分内核编译log:
      GEN     usr/initramfs_data.cpio.gz
      GZIP    kernel/config_data.gz
      CHK     kernel/config_data.h
      UPD     kernel/config_data.h
      CC      kernel/configs.o
      AR      kernel/built-in.o
      AS      usr/initramfs_data.o
      AR      usr/built-in.o
    展开:
    /bin/bash ./scripts/gen_initramfs_list.sh -o usr/initramfs_data.cpio.gz  -u 0  -g 0  /home/pengdonglin/disk_ext/Qemu/aarch32/rootfs/rootfs
    下面是测试命令:
    kernel_dir=./Linux-4.14.13
    kernel_image=${kernel_dir}/arch/arm/boot/zImage
    dtb_image=${kernel_dir}/arch/arm/boot/dts/vexpress-v2p-ca9.dtb
    qemu_path=/home/pengdonglin/disk_ext/Qemu/qemu-3.1.0/build/install/bin
    
    ${qemu_path}/qemu-system-arm 
        -M vexpress-a9 
        -m 1024M 
        -smp 1 
        -kernel ${kernel_image} 
        -nographic 
        -append "root=/dev/ram0 rw rootfstype=ramfs console=ttyAMA0 init=/init ignore_loglevel" 
        -dtb ${dtb_image}
    此外,在Documentation/filesystems/ramfs-rootfs-initramfs.txt提供了一个使用cpio打包的脚本:
    185   #!/bin/sh
    186 
    187   # Copyright 2006 Rob Landley <rob@landley.net> and TimeSys Corporation.
    188   # Licensed under GPL version 2
    189 
    190   if [ $# -ne 2 ]
    191   then
    192     echo "usage: mkinitramfs directory imagename.cpio.gz"
    193     exit 1
    194   fi
    195 
    196   if [ -d "$1" ]
    197   then
    198     echo "creating $2 from $1"
    199     (cd "$1"; find . | cpio -o -H newc | gzip) > "$2"
    200   else
    201     echo "First argument must be a directory"
    202     exit 1
    203   fi
    完。
  • 相关阅读:
    MySQL字符串相加函数如何运行?似曾相识还是记一笔吧
    JQuery使用getJSON跨域调用数据
    匹配中文字符的正则表达式
    php中删除超链接的正则表达式
    win2003系统+IIS6下,经常出现w3wp.exe和sqlserver.exe的内存占用居高不下
    如何添加修改uchome创始人
    JS中Null与Undefined的区别
    错误分析及解决办法MySQL server has gone away
    更改表自动递增值的sql
    mysql如何修改导入数据库文件大小限制
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/10468556.html
Copyright © 2011-2022 走看看