XiaomiRouter自學(xué)之路(14-Openwrt文件系統(tǒng)讀取失敗問題解決)

題圖:gratisography

11-Openwrt配置編譯燒錄中,我們將編譯好的openwrt-ramips-mt7620-xiaomi-miwifi-mini-squashfs-sysupgrade.bin燒錄進(jìn)去后,發(fā)現(xiàn)系統(tǒng)可以正常啟動(dòng),但是出現(xiàn)了Kernel panic,Unable to mount root fs on unknown-block(0,0),貌似文件系統(tǒng)出現(xiàn)了問題。

查看openwrt的啟動(dòng)信息,找到MTD分區(qū)信息的位置,如下:

[    0.710000] 7 ofpart partitions found on MTD device spi32766.0
[    0.710000] Creating 7 MTD partitions on "spi32766.0":
[    0.720000] 0x000000000000-0x000000030000 : "u-boot"
[    0.730000] 0x000000030000-0x000000040000 : "u-boot-env"
[    0.730000] 0x000000040000-0x000000050000 : "factory"
[    0.740000] 0x000000050000-0x000000fd0000 : "firmware"
[    0.920000] 0x000000fd0000-0x000000fe0000 : "crash"
[    0.930000] 0x000000fe0000-0x000000ff0000 : "reserved"
[    0.930000] 0x000000ff0000-0x000001000000 : "Bdata"
[    0.940000] gsw: setting port4 to ephy mode
[    0.950000] ralink_soc_eth 10100000.ethernet eth0 (uninitialized): port 1 link up (10Mbps/Half duplex)
[    0.960000] ralink_soc_eth 10100000.ethernet: loaded mt7620 driver
[    0.960000] ralink_soc_eth 10100000.ethernet eth0: ralink at 0xb0100000, irq 5
[    0.970000] rt2880_wdt 10000120.watchdog: Initialized
[    0.980000] TCP: cubic registered
[    0.980000] NET: Registered protocol family 17
[    0.990000] bridge: automatic filtering via arp/ip/ip6tables has been deprecated. Update your scripts to load br_netfilter if you need this.
[    1.000000] 8021q: 802.1Q VLAN Support v1.8
[    1.010000] VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
[    1.020000] Please append a correct "root=" boot option; here are the available partitions:
[    1.020000] 1f00             192 mtdblock0  (driver?)
[    1.030000] 1f01              64 mtdblock1  (driver?)
[    1.030000] 1f02              64 mtdblock2  (driver?)
[    1.040000] 1f03           15872 mtdblock3  (driver?)
[    1.040000] 1f04              64 mtdblock4  (driver?)
[    1.050000] 1f05              64 mtdblock5  (driver?)
[    1.060000] 1f06              64 mtdblock6  (driver?)
[    1.060000] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[    1.060000] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

可以看到分成7個(gè)partition,對(duì)于partition的添加我在Linux mtd system里面已經(jīng)有說了三種方式,這邊使用的是dts添加的方式,該dts文件為target/linux/ramips/dts/XIAOMI-MIWIFI-MINI.dts,打開dts可以看到有如下內(nèi)容:

m25p80@0 {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "w25q128";
        reg = <0 0>;
        linux,modalias = "m25p80", "w25q128";
        spi-max-frequency = <10000000>;

        partition@0 {
            label = "u-boot";
            reg = <0x0 0x30000>;
        };

        partition@30000 {
            label = "u-boot-env";
            reg = <0x30000 0x10000>;
            read-only;
        };

        factory: partition@40000 {
            label = "factory";
            reg = <0x40000 0x10000>;
            read-only;
        };

        partition@50000 {
            label = "firmware";
            reg = <0x50000 0xf80000>;
        };

        partition@fd0000 {
            label = "crash";
            reg = <0xfd0000 0x10000>;
        };

        partition@fe0000 {
            label = "reserved";
            reg = <0xfe0000 0x10000>;
            read-only;
        };

        partition@ff0000 {
            label = "Bdata";
            reg = <0xff0000 0x10000>;
        };
    };

直接觀察這7個(gè)分區(qū),好像沒看到linux和rootfs,其實(shí)這兩部分被cat連接成一個(gè).img文件,存放在firmware分區(qū)里面,對(duì)于openwrt的firmware生成過程后期會(huì)專門寫一篇文章介紹。

既然分區(qū)文件系統(tǒng)什么都有了為什么rootfs沒有引導(dǎo)成功呢?再查看下u-boot下個(gè)文件所存到的地址是否與kernel下的地址一致呢?

08-U-boot啟動(dòng)數(shù)值具體說明里面有提到U-boot下文件的存儲(chǔ)位置,在include/configs/rt2880.h中有如下定義:

#define CFG_BOOTLOADER_SIZE 0x20000
#define CFG_CONFIG_SIZE     0x10000
#define CFG_FACTORY_SIZE    0x10000

#define CFG_ENV_ADDR        (CFG_FLASH_BASE + CFG_BOOTLOADER_SIZE)
#define CFG_FACTORY_ADDR    (CFG_FLASH_BASE + CFG_BOOTLOADER_SIZE + CFG_CONFIG_SIZE)
#define CFG_KERN_ADDR       (CFG_FLASH_BASE + (CFG_BOOTLOADER_SIZE + CFG_CONFIG_SIZE + CFG_FACTORY_SIZE))
#ifdef DUAL_IMAGE_SUPPORT
#define CFG_KERN2_ADDR      (CFG_FLASH2_BASE + (CFG_BOOTLOADER_SIZE + CFG_CONFIG_SIZE + CFG_FACTORY_SIZE))

發(fā)現(xiàn)u-boot階段對(duì)u-boot的大小定義為0x20000,而kernel那邊對(duì)u-boot的大小定義卻為0x30000,地址已經(jīng)錯(cuò)位了,我們將u-boot下的CFG_BOOTLOADER_SIZE改成0x30000后,對(duì)u-boot、openwrt進(jìn)行重新燒錄測(cè)試。

重新燒錄后,可以觀察到一切都正常,可以引導(dǎo)文件系統(tǒng)了,啟動(dòng)完按下Enter鍵進(jìn)入命令行模式,如下:

BusyBox v1.23.2 (2017-02-21 05:58:37 PST) built-in shell (ash)

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 -----------------------------------------------------
 CHAOS CALMER (Chaos Calmer, r49389)
 -----------------------------------------------------
  * 1 1/2 oz Gin            Shake with a glassful
  * 1/4 oz Triple Sec       of broken ice and pour
  * 3/4 oz Lime Juice       unstrained into a goblet.
  * 1 1/2 oz Orange Juice
  * 1 tsp. Grenadine Syrup
 -----------------------------------------------------
root@OpenWrt:/# 
root@OpenWrt:/# ls
bin      etc      mnt      proc     root     sys      usr      www
dev      lib      overlay  rom      sbin     tmp      var

現(xiàn)在已經(jīng)可以正常引導(dǎo)了,試著去分析下是為什么會(huì)出現(xiàn)內(nèi)核正常啟動(dòng),可是文件系統(tǒng)引導(dǎo)不成功呢?

看下新的啟動(dòng)信息中MTD的分區(qū)信息有了一些信息,如下:

[    0.700000] m25p80 spi32766.0: w25q128 (16384 Kbytes)
[    0.710000] 7 ofpart partitions found on MTD device spi32766.0
[    0.710000] Creating 7 MTD partitions on "spi32766.0":
[    0.720000] 0x000000000000-0x000000030000 : "u-boot"
[    0.730000] 0x000000030000-0x000000040000 : "u-boot-env"
[    0.730000] 0x000000040000-0x000000050000 : "factory"
[    0.740000] 0x000000050000-0x000000fd0000 : "firmware"
[    0.860000] 2 uimage-fw partitions found on MTD device firmware
[    0.870000] 0x000000050000-0x0000001668b5 : "kernel"
[    0.870000] 0x0000001668b5-0x000000fd0000 : "rootfs"
[    0.880000] mtd: device 5 (rootfs) set to be root filesystem
[    0.890000] 1 squashfs-split partitions found on MTD device rootfs
[    0.890000] 0x000000360000-0x000000fd0000 : "rootfs_data"
[    0.900000] 0x000000fd0000-0x000000fe0000 : "crash"
[    0.910000] 0x000000fe0000-0x000000ff0000 : "reserved"
[    0.910000] 0x000000ff0000-0x000001000000 : "Bdata"
[    0.920000] gsw: setting port4 to ephy mode

可以看到中間多了一些信息,上面有說過firmware里面其實(shí)包含了kernel和rootfs兩個(gè)部分,所以其實(shí)是有兩個(gè)partition在里面,內(nèi)核在調(diào)用add_mtd_partitions()函數(shù)里面會(huì)調(diào)用mtd分離函數(shù)mtd_partition_split(),看下函數(shù)的原型:

static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
{
    static int rootfs_found = 0;

    if (rootfs_found)
        return;

    if (!strcmp(part->mtd.name, "rootfs")) {
        int num = run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);

        if (num <= 0 && config_enabled(CONFIG_MTD_ROOTFS_SPLIT))
            split_rootfs_data(master, part);

        rootfs_found = 1;
    }

    if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
        config_enabled(CONFIG_MTD_SPLIT_FIRMWARE))
        split_firmware(master, part);

    arch_split_mtd_part(master, part->mtd.name, part->offset,
                part->mtd.size);
}

該函數(shù)會(huì)先判斷有沒有rootfs該partition,如果有直接對(duì)該partition進(jìn)行解析,如果沒有那就說明在firmware里面,所以會(huì)先調(diào)用split_firmware()函數(shù),簡(jiǎn)單說明該函數(shù)就是將firmware里面的kernel和rootfs分離出來,再對(duì)rootfs的partition進(jìn)行解析。

該函數(shù)具體做了以下幾件事:

  • 找type為MTD_PARSER_TYPE_FIRMWARE的分區(qū)解析器來分析。
  • "uimage-fw" 解析器讀出 firmware 分區(qū)的頭部,成功找到一個(gè) uImage。
  • 躍過uImage,緊接著成功找到 squashfs 的頭信息,于是找到了格式為 squashfs 的 rootfs。
  • 解析器在找到一個(gè)分區(qū)后,會(huì)調(diào)用 __mtd_add_partition() 將此分區(qū)添加到系統(tǒng)中。
  • __mtd_add_partition() 最后又調(diào)用 mtd_partition_split(),因?yàn)榇藭r(shí) rootfs已經(jīng)找到,所以會(huì)調(diào)用 split_rootfs_data() 找 rootfs_data 分區(qū)。
  • rootfs 為 squashfs 分區(qū),該格式的文件系統(tǒng)只讀,且頭信息里有標(biāo)記分區(qū)大小。所以很容易就可以找到 rootfs_data 的起始位置。

通過上面這么一分析其實(shí)我們就大概知道沒有引導(dǎo)文件系統(tǒng)的原因了:

1.kernel能夠啟動(dòng)那是因?yàn)閗ernel的啟動(dòng)與mtd分區(qū)是沒有關(guān)系的,只跟u-boot的引導(dǎo)地址有關(guān),又因?yàn)樵趗-boot階段,kernel所存儲(chǔ)的位于與啟動(dòng)的引導(dǎo)地址肯定是一致的,所以kernel正常啟動(dòng)。

2.rootfs的啟動(dòng)與mtd分區(qū)是有關(guān)的,因?yàn)楹竺媸峭ㄟ^讀取分區(qū)塊的內(nèi)容來載入數(shù)據(jù)的,所以當(dāng)所存放的地址和所要取的地址錯(cuò)誤時(shí),調(diào)用split_firmware()函數(shù)沒能找出rootfs所處的位置,沒能為rootfs建立分區(qū)塊,所以會(huì)提示Unable to mount root fs on unknown-block(0,0)無法掛載rootfs文件系統(tǒng)。

Openwrt文件系統(tǒng)讀取失敗問題解決的分析就到這邊,有感悟時(shí)會(huì)持續(xù)會(huì)更新。

注:以上內(nèi)容都是本人在學(xué)習(xí)過程積累的一些心得,難免會(huì)有參考到其他文章的一些知識(shí),如有侵權(quán),請(qǐng)及時(shí)通知我,我將及時(shí)刪除或標(biāo)注內(nèi)容出處,如有錯(cuò)誤之處也請(qǐng)指出,進(jìn)行探討學(xué)習(xí)。文章只是起一個(gè)引導(dǎo)作用,詳細(xì)的數(shù)據(jù)解析內(nèi)容還請(qǐng)查看XiaomiRouter相關(guān)教程,感謝您的查閱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容