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

相關文章
相關標籤/搜索