kexec on openwrt - linux boots linux, kernel boots kernel on openwrt

kexec on openwrt - linux boots linux, kernel boots kernel on openwrt

背景

对于嵌入式设备好比路由器,每次版本升级,老是须要image的升级,因此须要烧写Flash。这种方式速度慢,而且还可能损坏Flash里的引导image,形成设备没法启动,只能返厂维修。
若是可以作一个小系统,出厂时烧录到Flash里,而后它用来查询和下载新版本image到内存,从内存启动这个新的image,那么就不用再烧录Flash,而且能够把image升级放到云端控制。html

技术分析

能够经过添加功能到bootloader支持这种需求,可是修改原路由器bootloader开发难度比较大,而且将原bootloader替换掉也不容易恢复到原厂image。node

Linux里kexec-tools特性,支持linux启动linux,或kernel引导kernel,恰好能够被用到这里。咱们能够实现一个小的开启kexec特性的linux系统。而后经过它来下载和引导新的initramfs的全特性的linux系统。linux

kexec的原理是内核启动时会保留一段内存用来加载和解析新的linux系统,内核提供了kexec的系统调用,来加载制定段到物理内存。web

支持kexec特性的openwrt image

  1. 打开内核的kexec
$ make menuconfig
Utilities --> kexec-tools
  1. 加入kexec-tools用户空间工具
$ make menuconfig
Utilities --> kexec-tools
  1. 将sysupgrade.bin烧录到Flash里
$ sysupgrade -n openwrt-*-sysupgrade.bin

kexec用法

$ kexec -d --command-line="$(cat /proc/cmdlin)" -l vmlinux-initramfs.elf.gz
$ kexec -d -e

Note: kexec-tools在MIPS下–type只支持elf-mips, 而且elf必须通过gzip压缩bash

支持initramfs的openwrt image

  1. 修改openwrt配置文件以产生ramdisk
$ make menuconfig
Target Images --> ramdisk
  1. LEDE 17.01上须要修改KERNEL_SIZE,支持生成更大完整的initramfs, AA 12.09是不须要的
$ target/linux/mips/ramips/image/mt7621.mk
  1. LEDE 17.01上image位置:
llwang@compiler~/repos/master_for_lede-17.01/osdk_repos $ ls build_dir/target-mipsel_24kc_musl-1.1.16/linux-ramips_mt7621/
vmlinux-initramfs.elf
kernel.bin.dtb
  1. LEDE170.01上须要补丁bin.dtb,AA12.09不须要
$ ./staging_dir/host/bin/patch-dtb vmlinux-initramfs.elf ubnt-erx-kernel.bin.dtb
  1. 为了可以访问到Flash里的calibration data,须要修改preinit过程,加载caldata和挂载rootfs_data
llwang@compiler~/repos/master_for_AA-12.09/osdk_repos/package_repos/ok_base-files/lib/preinit $ cat 70_initramfs_test 
#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
# Copyright (C) 2010 Vertical Communications

initramfs_test() {
    echo "---> initramfs_test $INITRAMFS"
    if [ -n "$INITRAMFS" ]; then
        boot_run_hook initramfs
        preinit_ip_deconfig
    # OK_PATCH
    do_load_ath10k_board_bin
    mount "$(find_mtd_part rootfs_data)" /overlay -t jffs2
    mtd -qq unlock rootfs_data
    # end of OK_PATCH
        break
    fi
}
  1. 压缩elf文件
$ gzip -c vmlinux-initramfs.elf > initramfs.elf.gz

参考文献

  1. kexec on MIPS
  2. kexec manual
  3. kexec with lede
  4. Enhanced kexec patch
  5. Device Tree
  6. kexec ar71xx issue

遇到的问题

  1. No valid device tree found, kernel panic on Failed to find mtk,mt7621-sync node
    缘由: 系统device Tree没有加载正确
    openwrt在mips上dtb的处理以下:
    在vmlinux的elf里,预留了0x400, 16K的区域用来保存dtb信息,而后使用全局变量__image_dtb来索引这个区域,从而读取dtb新信息。而且在这个区域预存了特定字符"OWRTDTB:",生成image时使用。
    在生成vmlinux文件后,查找"OWRTDTB:"关键字,将dtb的bin,写入到这个区域。
    解决方案:在生成vmlinux.elf后,将dtb.bin补丁到elf文件里。
...
[    0.000000] No valid device tree found, continuing without //initialize device tree is incorrect
[    0.000000] PERCPU: Embedded 10 pages/cpu @81203000 s8608 r8192 d24160 u40960
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 65024
[    0.000000] Kernel command line:  kexec console=ttyS0,57600 rootfstype=squashfs,jffs2 rootfstype=squashfs,jffs2 //command line should be changed during build
...
[    0.000000] Kernel panic - not syncing: Failed to find mtk,mt7621-sysc node
[    0.000000] Rebooting in 1 seconds..
[    0.000000] Reboot failed -- System halted
...
  1. okos is unstable and gets panic sometimes after hot boot
    缘由:一些外围芯片好比usb controller, wmac正在处理中断过程当中被hot boot, 形成下次启动中断大量上报,内核stuck。
    解决方案:尽可能保证sysloader的简洁,裁剪掉不须要的外设驱动,只保留Flash的访问。
    修改sysloader的.config文件,剔除不须要的模块选择。工具

  2. Overlayfs not enabled in initramfs
    缘由:overlayfs是经过一个底层只读文件系统squashfs加上一个上层可写文件系统JFFS2/UBI构建出来的。
    在initramfs下不能使用squashfs下的再也不更新的rootfs.
    解决方案:修改preinit过程,挂载rootfs_data分区ui

  3. caldata加载失败
    缘由: preinit过程当中若是发现是initramfs就会跳过加载caldata和flash分区
    解决方案:为了可以访问到Flash里的calibration data,和挂载rootfs_data,须要修改preinit过程,加载caldata和挂载rootfs_dataspa

llwang@compiler~/repos/master_for_AA-12.09/osdk_repos/package_repos/ok_base-files/lib/preinit $ cat 70_initramfs_test 
#!/bin/sh
# Copyright (C) 2006 OpenWrt.org
# Copyright (C) 2010 Vertical Communications

initramfs_test() {
    echo "---> initramfs_test $INITRAMFS"
    if [ -n "$INITRAMFS" ]; then
        boot_run_hook initramfs
        preinit_ip_deconfig
    # OK_PATCH
    do_load_ath10k_board_bin
    mount "$(find_mtd_part rootfs_data)" /overlay -t jffs2
    mtd -qq unlock rootfs_data
    # end of OK_PATCH
        break
    fi
}

nicephil@gmail.com – 2017-12-3.net

相关文章
相关标签/搜索