OpenWrt使用block2mtd工具模拟mtd升级EMMC分区

    OpenWrt 19.07系统下参考imx6平台移植imx8平台,使用EMMC作为启动和存储介质,imx6 的apalis平台使用的是4GB eMMC,但实际升级时使用MTD操作nand flash,这时就需要MTD能操作EMMC的方法了。

分析sysupgrade升级流程

    sysupgrade命令脚本sbin/sysupgrade 代码

#!/bin/sh
 
. /lib/functions.sh 提供工具函数
. /lib/functions/system.sh 提供mtd和mac操作函数
. /usr/share/libubox/jshn.sh 提供json_xx函数
 
# initialize defaults
export MTD_ARGS=""
export MTD_CONFIG_ARGS=""
export INTERACTIVE=0
export VERBOSE=1
export SAVE_CONFIG=1
export SAVE_OVERLAY=0
export SAVE_OVERLAY_PATH=
export SAVE_PARTITIONS=1
export SAVE_INSTALLED_PKGS=0
export SKIP_UNCHANGED=0
export CONF_IMAGE=
export CONF_BACKUP_LIST=0
export CONF_BACKUP=
export CONF_RESTORE=
export NEED_IMAGE=
export HELP=0
export FORCE=0
export TEST=0
export UMOUNT_ETCBACKUP_DIR=0
 
# parse options
while [ -n "$1" ]; do
    case "$1" in
        -i) export INTERACTIVE=1;;
        -v) export VERBOSE="$(($VERBOSE + 1))";;
        -q) export VERBOSE="$(($VERBOSE - 1))";;
        -n) export SAVE_CONFIG=0;;
        -c) export SAVE_OVERLAY=1 SAVE_OVERLAY_PATH=/etc;;
        -o) export SAVE_OVERLAY=1 SAVE_OVERLAY_PATH=/;;
        -p) export SAVE_PARTITIONS=0;;
        -k) export SAVE_INSTALLED_PKGS=1;;
        -u) export SKIP_UNCHANGED=1;;
        -b|--create-backup) export CONF_BACKUP="$2" NEED_IMAGE=1; shift;;
        -r|--restore-backup) export CONF_RESTORE="$2" NEED_IMAGE=1; shift;;
        -l|--list-backup) export CONF_BACKUP_LIST=1;;
        -f) export CONF_IMAGE="$2"; shift;;
        -F|--force) export FORCE=1;;
        -T|--test) export TEST=1;;
        -h|--help) export HELP=1; break;;
        -*)
            echo "Invalid option: $1" >&2
            exit 1
        ;;
        *) break;;
    esac
    shift;
done
 
export CONFFILES=/tmp/sysupgrade.conffiles
export CONF_TAR=/tmp/sysupgrade.tgz
export ETCBACKUP_DIR=/etc/backup
export INSTALLED_PACKAGES=${ETCBACKUP_DIR}/installed_packages.txt
 
IMAGE="$1"
 
[ -z "$IMAGE" -a -z "$NEED_IMAGE" -a $CONF_BACKUP_LIST -eq 0 -o $HELP -gt 0 ] && {
    cat <<EOF
Usage: $0 [<upgrade-option>...] <image file or URL>
       $0 [-q] [-i] [-c] [-u] [-o] [-k] <backup-command> <file>
upgrade-option:
    -f <config>  restore configuration from .tar.gz (file or url)
    -i           interactive mode
    -c           attempt to preserve all changed files in /etc/
    -o           attempt to preserve all changed files in /, except those
                 from packages but including changed confs.
    -u           skip from backup files that are equal to those in /rom
    -n           do not save configuration over reflash
    -p           do not attempt to restore the partition table after flash.
    -k           include in backup a list of current installed packages at
                 $INSTALLED_PACKAGES
    -T | --test
                 Verify image and config .tar.gz but do not actually flash.
    -F | --force
                 Flash image even if image checks fail, this is dangerous!
    -q           less verbose
    -v           more verbose
    -h | --help  display this help
backup-command:
    -b | --create-backup <file>
                 create .tar.gz of files specified in sysupgrade.conf
                 then exit. Does not flash an image. If file is '-',
                 i.e. stdout, verbosity is set to 0 (i.e. quiet).
    -r | --restore-backup <file>
                 restore a .tar.gz created with sysupgrade -b
                 then exit. Does not flash an image. If file is '-',
                 the archive is read from stdin.
    -l | --list-backup
                 list the files that would be backed up when calling
                 sysupgrade -b. Does not create a backup file.
EOF
    exit 1
}
 
[ -n "$IMAGE" -a -n "$NEED_IMAGE" ] && {
    cat <<-EOF
        -b|--create-backup and -r|--restore-backup do not perform a firmware upgrade.
        Do not specify both -b|-r and a firmware image.
    EOF
    exit 1
}

include /lib/upgrade导入common.sh  fwtool.sh  luci-add-conffiles.sh  nand.sh  platform.sh脚本函数

type platform_check_image >/dev/null 2>/dev/null || {
    echo "Firmware upgrade is not implemented for this platform." >&2
    exit 1
}
 
lib/upgrade/platform.sh
platform_check_image() {
    local board=$(board_name)
 
    case "$board" in
    apalis*)
        return 0
        ;;
    *gw5*)
        nand_do_platform_check $board $1
        return $?;
        ;;
    esac
 
    echo "Sysupgrade is not yet supported on $board."
    return 1
}

检测函数会根据board_name名称

if [ -n "$CONF_IMAGE" ]; then
    case "$(get_magic_word $CONF_IMAGE cat)" in
        # .gz files
        1f8b) ;;
        *)
            echo "Invalid config file. Please use only .tar.gz files" >&2
            exit 1
        ;;
    esac
    get_image "$CONF_IMAGE" "cat" > "$CONF_TAR"
    export SAVE_CONFIG=1
elif ask_bool $SAVE_CONFIG "Keep config files over reflash"; then
    [ $TEST -eq 1 ] || do_save_conffiles "$CONF_TAR"
    export SAVE_CONFIG=1
else
    [ $TEST -eq 1 ] || rm -f "$CONF_TAR"
    export SAVE_CONFIG=0
fi
 
if [ $TEST -eq 1 ]; then
    exit 0
fi
 
install_bin /sbin/upgraded
v "Commencing upgrade. Closing all shell sessions."
 
COMMAND='/lib/upgrade/do_stage2'
 
if [ -n "$FAILSAFE" ]; then
    printf '%s\x00%s\x00%s' "$RAM_ROOT" "$IMAGE" "$COMMAND" >/tmp/sysupgrade
    lock -u /tmp/.failsafe
else
    force_attr=""
    [ $FORCE -eq 1 ] && force_attr="\"force\": true,"
    backup_attr=""
    [ $SAVE_CONFIG -eq 1 ] && backup_attr="\"backup\": $(json_string $CONF_TAR),"
    ubus call system sysupgrade "{
        \"prefix\": $(json_string "$RAM_ROOT"),
        \"path\": $(json_string "$IMAGE"),
        $force_attr
        $backup_attr
        \"command\": $(json_string "$COMMAND"),
        \"options\": {
            \"save_partitions\": $SAVE_PARTITIONS
        }
    }"
fi

最后使用ubus call system sysupgrade调用do_stage2升级:

#!/bin/sh
. /lib/functions.sh
include /lib/upgrade
 
v "Performing system upgrade..."
if type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
    platform_do_upgrade "$IMAGE"
else
    default_do_upgrade "$IMAGE"
fi
 
if [ -n "$UPGRADE_BACKUP" ] && type 'platform_copy_config' >/dev/null 2>/dev/null; then
    platform_copy_config
fi
 
v "Upgrade completed"
sleep 1
 
v "Rebooting system..."
umount -a
reboot -f
sleep 5
echo b 2>/dev/null >/proc/sysrq-trigger

platform_do_upgrade函数的实现

platform_do_upgrade() {
    local board=$(board_name)
 
    case "$board" in
    apalis*)
        apalis_do_upgrade "$1"
        ;;
    *gw5*)
        nand_do_upgrade "$1"
        ;;
    esac
}
 
apalis_do_upgrade() {
    local board_name=$(board_name)
    board_name=${board_name/,/_}
 
    apalis_mount_boot
    get_image "$1" | tar Oxf - sysupgrade-${board_name}/kernel > /boot/uImage
    get_image "$1" | tar Oxf - sysupgrade-${board_name}/root > $(rootpart_from_uuid)
    sync
    umount /boot
}
 
apalis_mount_boot() {
    mkdir -p /boot
    mount -t jffs2 mtd:rootfs_data /boot
}

没有rootfs_data分区导致挂载失败:

root@OpenWrt:~# sysupgrade openwrt-imx8-ubox-squashfs-sysupgrade.bin 
Image not in /tmp, copying...
Sysupgrade is not yet supported on ubox.
 
Saving config files...
Commencing upgrade. Closing all shell sessions.
Watchdog handover: fd=3
- watchdog -
killall: telnetd: no process killed
Sending TERM to remaining processes ... ubusd askfirst urngd logd rpcd dnsmasq netifd odhcpd uhttpd hostapd udhcpd ntpd 
[  273.003190] wlan: Stoping AP
[  273.008717] Invalid proberesp_p2p_index for mgmt frame ie.
[  273.014247] wlan: AP stopped
Sending KILL to remaining processes ... 
Switching to ramdisk...
[  278.092977] EXT4-fs (mmcblk0p2): re-mounted. Opts: data=ordered
Performing system upgrade...
[ 8288.416092] MTD: MTD device with name "rootfs_data" not found.
mount: mounting mtd:rootfs_data on /boot failed: No such file or directory
/lib/upgrade/do_stage2: line 31: rootpart_from_uuid: not found
/lib/upgrade/do_stage2: line 31: can't create : nonexistent directory
cat: write error: Broken pipe
umount: can't unmount /boot: Invalid argument
Upgrade completed
 
Rebooting system...
umount: can't unmount /dev: Resource busy
umount: can't unmount /tmp: Resource busy
[  279.316786] ci_hdrc ci_hdrc.0: remove, state 1
[  279.321280] usb usb3: USB disconnect, device number 1
[  279.326358] usb 3-1: USB disconnect, device number 2
[  279.331502] rndis_host 3-1:1.0 usb0: unregister 'rndis_host' usb-ci_hdrc.0-1, RNDIS device
[  279.340240] [RMNET:HI] rmnet_config_notify_cb(): Kernel is trying to unregister usb0
[  279.362981] [RMNET:HI] rmnet_config_notify_cb(): Kernel is trying to unregister usb0
[  279.373054] ci_hdrc ci_hdrc.0: USB bus 3 deregistered
[  279.390955] reboot: Restarting system

block2mtd 模拟MTD

fdisk查看emmc分区的信息:

root@OpenWrt:~# fdisk  -l
Disk /dev/mmcblk0: 7264 MB, 7616856064 bytes, 14876672 sectors
232448 cylinders, 4 heads, 16 sectors/track
Units: sectors of 1 * 512 = 512 bytes
 
Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/mmcblk0p1    320,0,1     575,3,16         20480     430079     409600  200M  c Win95 FAT32 (LBA)
/dev/mmcblk0p2    384,0,1     63,3,16         614400    7737343    7122944 3478M 83 Linux
/dev/mmcblk0p3    64,0,1      319,3,16       7737344    8146943     409600  200M  c Win95 FAT32 (LBA)
/dev/mmcblk0p4    320,0,1     1023,3,16      8146944   14876671    6729728 3286M 83 Linux
Disk /dev/mmcblk0rpmb: 4 MB, 4194304 bytes, 8192 sectors
128 cylinders, 4 heads, 16 sectors/track
Units: sectors of 1 * 512 = 512 bytes
 
Disk /dev/mmcblk0rpmb doesn't contain a valid partition table
Disk /dev/mmcblk0boot1: 16 MB, 16777216 bytes, 32768 sectors
512 cylinders, 4 heads, 16 sectors/track
Units: sectors of 1 * 512 = 512 bytes
Disk /dev/mmcblk0boot1 doesn't contain a valid partition table
Disk /dev/mmcblk0boot0: 16 MB, 16777216 bytes, 32768 sectors
512 cylinders, 4 heads, 16 sectors/track
Units: sectors of 1 * 512 = 512 bytes
 
Disk /dev/mmcblk0boot0 doesn't contain a valid partition table

打开内核的mtd,block2mtd的支持,执行如下命令

#设置mtd2block的分区
root@OpenWrt:/# echo "/dev/mmcblk0p3,8192" > /sys/module/block2mtd/parameters/block2mtd 
[ 1938.086585] Creating 1 MTD partitions on "/dev/mmcblk0p3":
[ 1938.092141] 0x000000000000-0x00000c800000 : "/dev/mmcblk0p3"
[ 1938.098764] block2mtd: mtd0: [/dev/mmcblk0p3] erase_size = 8KiB [8192]

root@OpenWrt:/# ls /dev/mtd* -l
crw-------    1 root     root       90,   0 Jan  1 00:00 /dev/mtd0
crw-------    1 root     root       90,   1 Jan  1 00:00 /dev/mtd0ro
brw-------    1 root     root       31,   0 Jan  1 00:02 /dev/mtdblock0
 
root@OpenWrt:/# cat /proc/mtd 
dev:    size   erasesize  name
mtd0: 0c800000 00002000 "/dev/mmcblk0p3"

#格式化mtdblock0
root@OpenWrt:/# mkfs.ext4 /dev/mtdblock0 
mke2fs 1.44.5 (15-Dec-2018)
/dev/mtdblock0 contains a vfat file system
Proceed anyway? (y,N) y
Creating filesystem with 204800 1k blocks and 51200 inodes
Filesystem UUID: 49faec10-c3b3-4716-962d-717f2ed5fa68
Superblock backups stored on blocks: 
    8193, 24577, 40961, 57345, 73729
 
Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done 
#烧录rootfs squashfs镜像
root@OpenWrt:~# mtd write root.squashfs /dev/mtdblock0
Unlocking /dev/mtdblock0...
 Writing from root.squashfs to /dev/mtdblock0 ...

这样操作就把磁盘的p3分区模拟成了mtd分区,所以可以使用mtd相关命令来对/dev/mtdblock0进行操作。

本文章由作者:佐须之男 整理编辑,原文地址: OpenWrt使用block2mtd工具模拟mtd升级EMMC分区
本站的文章和资源来自互联网或者站长的原创,按照 CC BY -NC -SA 3.0 CN协议发布和共享,转载或引用本站文章应遵循相同协议。如果有侵犯版权的资 源请尽快联系站长,我们会在24h内删除有争议的资源。欢迎大家多多交流,期待共同学习进步。

相关推荐