根檔案系統之init
title: 根檔案系統之init
tag: arm
date: 2018-11-12 18:53:23
---
引入
在Kernel原始碼分析中,瞭解到init_post
是在掛載根檔案系統之後執行應用程式
開啟標準輸入/輸出/錯誤
Linux首先開啟標準輸入scanf
,標準輸出printf
,標準錯誤err
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) printk(KERN_WARNING "Warning: unable to open an initial console.\n"); (void) sys_dup(0); //這個是複製的意思 (void) sys_dup(0);
這裡的sys_dup(0)
表示複製開啟的第0個檔案,也就是/dev/console
,也就是說準輸入scanf
,標準輸出printf
,標準錯誤err
都定位到/dev/console
這個檔案,這個檔案被稱為終端,他可以是串列埠或者液晶鍵盤組合等
執行init
程序
接下來會處理U-boot傳遞進來的命令列引數
//run_init_process 一般會正確執行不會返回的程式 if (execute_command) { run_init_process(execute_command); printk(KERN_WARNING "Failed to execute %s. Attempting " "defaults...\n", execute_command); } run_init_process("/sbin/init"); run_init_process("/etc/init"); run_init_process("/bin/init"); run_init_process("/bin/sh"); panic("No init found. Try passing init= option to kernel.");
我們搜尋下execute_command
,發現如下定義,很明顯和kernel原始碼分析
中的命令列引數類似
static int __init init_setup(char *str) { unsigned int i; execute_command = str; /* * In case LILO is going to boot us with default command line, * it prepends "auto" before the whole cmdline which makes * the shell think it should execute a script with such name. * So we ignore all arguments entered _before_ init=... [MJ] */ for (i = 1; i < MAX_INIT_ARGS; i++) argv_init[i] = NULL; return 1; } __setup("init=", init_setup);
也是設定一個段屬性固定的結構體
#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)
#define __setup_param(str, unique_id, fn, early) \
static char __setup_str_##unique_id[] __initdata = str; \
static struct obs_kernel_param __setup_##unique_id \
__attribute_used__ \
__attribute__((__section__(".init.setup"))) \
__attribute__((aligned((sizeof(long))))) \
= { __setup_str_##unique_id, fn, early }
也就是構造了一個和root=/dev/mtdblock3
類似的
static char __setup_str_init_dev_setup[] __initdata = "init=";
static struct obs_kernel_param __setup_init_dev_setup
__attribute_used__
__attribute__((__section__(".init.setup")))
__attribute__((aligned((sizeof(long)))))
={
__setup_str_init_dev_setup,root_init_setup,init_dev_setup,0
}
這個結構體的原型如下
struct obs_kernel_param
{
const char *str;
int (*setup_func)(char *);
int early;
};
也就是說execute_command=/linuxrc
,因為u-boot傳遞的引數是init=/linuxrc
,程式會使用run_init_process(execute_command);
來處理這個命令列
注意 函式run_init_process
一般會正確執行不會返回的程式,也就是說如果能夠正確執行u-boot傳遞的引數,將不會執行以下
run_init_process("/sbin/init"); //如果命令列引數不正確才會執行這個應用程式
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("No init found. Try passing init= option to kernel.");
小結測試
(一)
燒錄u-boot,燒錄Linux,擦除根檔案系統nand erase root
,也就是不放根檔案系統,系統會有如下提示
VFS: Mounted root (yaffs filesystem).
掛接了根檔案系統,但是flash是空的,預設識別為yaffs
Freeing init memory: 140K
Warning: unable to open an initial console.
flash是空的,無法啟動應用程式
Failed to execute /linuxrc. Attempting defaults...
錯誤指示--命令列
Kernel panic - not syncing: No init found. Try passing init= option to kernel.
因為格式化了flash,系統可以識別為任意的檔案系統,預設識別為yaffs
,但是由於沒有根檔案系統,所以無法開啟標準輸入輸出,按照程式碼所寫的提示錯誤
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
同時也就無法開啟init
程序,提示
panic("No init found. Try passing init= option to kernel.");
(二)
燒入根檔案系統,在u-boot下輸入y,下載檔案系統fs_mini.yaffs2
,然後啟動.輸入ps
看下啟動的應用程式
# ps
PID Uid VSZ Stat Command
1 0 3092 S init
2 0 SW< [kthreadd]
3 0 SWN [ksoftirqd/0]
4 0 SW< [watchdog/0]
5 0 SW< [events/0]
6 0 SW< [khelper]
55 0 SW< [kblockd/0]
56 0 SW< [ksuspend_usbd]
59 0 SW< [khubd]
61 0 SW< [kseriod]
73 0 SW [pdflush]
74 0 SW [pdflush]
75 0 SW< [kswapd0]
76 0 SW< [aio/0]
710 0 SW< [mtdblockd]
745 0 SW< [kmmcd]
767 0 3096 S -sh
769 0 3096 R ps
這裡init
就是啟動的第一個程序sh
也就是終端接收輸入以及列印的輸出
init
實現
在嵌入式Linux中的一些基礎命令例如ls,cp
等實際上也是一個個App
,這些基本命令一般由busybox
編譯得到一個名為busybox
的應用程式.然後ls,cd,cp
等命令一般是其連結.可以使用ls-l xxx
來檢視其連結屬性.可以先用which xxx
檢視其位置,然後看屬性
# ls -l /bin/ls
lrwxrwxrwx 1 1000 1000 7 Jan 6 2010 /bin/ls -> busybox
# ls
bin lib mnt sbin usr
dev linuxrc proc sys
etc lost+found root tmp
# busybox ls
bin lib mnt sbin usr
dev linuxrc proc sys
etc lost+found root tmp
其實,/sbin/init
也是到busybox
的連結
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
# which init
/sbin/init
# ls -l /sbin/init
lrwxrwxrwx 1 1000 1000 14 Jan 6 2010 /sbin/init -> ../bin/busybox