
在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)教程,感謝您的查閱。