當(dāng)前位置:首頁(yè) > 芯聞號(hào) > 充電吧
[導(dǎo)讀]整體框架:1)在Linux kernel的源代碼中,對(duì)如何啟動(dòng)應(yīng)用程序有著明確的定義。首先我們需要掛載根文件系統(tǒng),只有正確掛載了根文件系統(tǒng),才能夠從根文件系統(tǒng)中讀出應(yīng)用程序。我們啟動(dòng)的第一個(gè)程序就是i

整體框架:


1)在Linux kernel的源代碼中,對(duì)如何啟動(dòng)應(yīng)用程序有著明確的定義。首先我們需要掛載根文件系統(tǒng),只有正確掛載了根文件系統(tǒng),才能夠從根文件系統(tǒng)中讀出應(yīng)用程序。我們啟動(dòng)的第一個(gè)程序就是init程序。init進(jìn)程完成了對(duì)應(yīng)用程序的各項(xiàng)配置(進(jìn)程ID、執(zhí)行時(shí)機(jī)、命令、終端、下一個(gè)執(zhí)行的進(jìn)程等),并最終依據(jù)配置執(zhí)行了應(yīng)用程序。 2)要執(zhí)行應(yīng)用程序,首先進(jìn)行配置。配置文件inittab里有著對(duì)應(yīng)用程序的詳細(xì)配置,這些都是C文件。init進(jìn)程讀出配置、分析配置并配置應(yīng)用程序、配置C庫(kù)(用到很多C庫(kù)里的函數(shù))。最后執(zhí)行程序。 3)Busybox是一個(gè)遵循GPL v2協(xié)議的開源項(xiàng)目。Busybox將眾多的UNIX命令集合進(jìn)一個(gè)很小的可執(zhí)行程序中,可以用來(lái)替換GNU fileutils、shellutils等工具集。Busybox中各種命令與相應(yīng)的GNU工具相比,所能提供的選項(xiàng)較少,但是能夠滿足一般應(yīng)用。Busybox為各種小型的或者嵌入式系統(tǒng)提供了一個(gè)比較完全的工具集。更多詳細(xì)介紹參考README。

我們執(zhí)行命令的時(shí)候?qū)嶋H是執(zhí)行busybox 命令

我們查看軟連接


內(nèi)核檢測(cè)根文件系統(tǒng)并啟動(dòng)init

內(nèi)核啟動(dòng)的最后一步就是啟動(dòng)init進(jìn)程,代碼在init/main.c/init_post函數(shù)

static?int?noinline?init_post(void)
{
????free_initmem();
????unlock_kernel();
????mark_rodata_ro();
????system_state?=?SYSTEM_RUNNING;
????numa_default_policy();

????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);

????if?(ramdisk_execute_command)?{
????????run_init_process(ramdisk_execute_command);
????????printk(KERN_WARNING?"Failed?to?execute?%sn",
????????????????ramdisk_execute_command);
????}

????/*
?????*?We?try?each?of?these?until?one?succeeds.
?????*
?????*?The?Bourne?shell?can?be?used?instead?of?init?if?we?are
?????*?trying?to?recover?a?really?broken?machine.
?????*/
????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.");
}

內(nèi)核啟動(dòng)init進(jìn)程的過程如下: (1)打開標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤設(shè)備open("/dev/console") 嘗試打開/dev/console設(shè)備文件,如果成功即為init進(jìn)程標(biāo)準(zhǔn)輸入設(shè)備。(void) sys_dup(0); (void) sys_dup(0);將文件描述符0復(fù)制給文件描述符1、2,所以標(biāo)準(zhǔn)輸入、輸出、錯(cuò)誤都對(duì)應(yīng)同一個(gè)文件(設(shè)備) (2)如果execute_command變量指定了要運(yùn)行的程序,啟動(dòng)它。

  if?(execute_command)?{
    run_init_process(execute_command);
  }

其中execute_command為命令行參數(shù),在我們uboot傳給內(nèi)核的參數(shù)中,init設(shè)置了init=/linuxrc,所以這里的execute_command就等于/linuxrc。
?如果傳值成功則執(zhí)行run_init_process,否則打印printk(KERN_WARNING “Failed to execute %s. ?Attempting “”defaults…n”, execute_command);
?并接著往下執(zhí)行,接著檢測(cè)其他位置的init進(jìn)程,若成功則執(zhí)行,失敗則接著往下檢測(cè),直到找到合適的init進(jìn)程或者沒找到則打印panic(“No init found. ?Try passing init= option to kernel.”);

那么這里我們可以先使用nand erase root擦除root分區(qū),也就是說擦除根文件系統(tǒng),然后啟動(dòng)只有bootloader和kernel的系統(tǒng)。在結(jié)果是否和代碼中說明的一致,結(jié)果Linux kernel在啟動(dòng)過程中,打印出了如下的信息:

VFS:?Mounted?root?(yaffs?filesystem).??
Freeing?init?memory:?140K
Warning:?unable?to?open?an?initial?console.
Failed?to?execute?/linuxrc.??Attempting?defaults...
Kernel?panic?-?not?syncing:?No?init?found.??Try?passing?init=?option?to?kernel.

首先是VFS:掛載了根文件系統(tǒng),可能大家會(huì)問,不是剛剛已經(jīng)擦除了根文件系統(tǒng),為什么說這里掛載了?
?這是因?yàn)楫?dāng)我們擦除了根文件系統(tǒng)的root分區(qū)后,Linux kernel認(rèn)為它是任意格式的根文件系統(tǒng)(其實(shí)分區(qū)里面什么都沒有),而默認(rèn)的又是yaffs格式,所以這里說掛載了yaffs格式的根文件系統(tǒng)。
?這里的warning難道不是和我們init_post函數(shù)中的printk(KERN_WARNING “Warning: unable to open an initial console.n”);相對(duì)應(yīng)嗎?
?同理,F(xiàn)ailed to execute /linuxrc. ?Attempting defaults…和printk(KERN_WARNING “Failed to execute %s. ?Attempting “”defaults…n”, execute_command);相對(duì)應(yīng)。
?Kernel panic - not syncing: No init found. ?Try passing init= option to kernel.和panic(“No init found. ?Try passing init= option to kernel.”);相對(duì)應(yīng)。
?so=>這證明我們的分析是正確的。

Busybox init進(jìn)程的啟動(dòng)過程

其中與構(gòu)建根文件系統(tǒng)關(guān)系密切的是控制臺(tái)的初始化、對(duì)inittab文件的解釋執(zhí)行。

內(nèi)核啟動(dòng)init進(jìn)程時(shí)已經(jīng)打開“/dev/console”設(shè)備作為控制臺(tái),一般情況下Busybox init程序就使用/dev/console。
?但是如果內(nèi)核啟動(dòng)init進(jìn)程的同時(shí)設(shè)置了環(huán)境變量CONSOLE或console,則使用環(huán)境變量所指定的設(shè)備。
?在Busybox init程序中,還會(huì)檢查這個(gè)設(shè)備是否可以打開,如果不能打開則使用”/dev/null”。

/etc/inittab文件的相關(guān)文檔和示例代碼都在Busybox的examples/inittab文件中,我們來(lái)一探究竟

查看inittab文件得知inittab格式:

Format?for?each?entry:
#:::#id:????????The?id?field?is?used?by?BusyBox?init?to?specify?the?controlling?tty?for?the?specified?process?to?run?on.??
#runlevels:??The?runlevels?field?is?completely?ignored.
#action:?????Valid?actions?include:???sysinit,?respawn,?askfirst,?wait,?once,
#????????????????????????????????????????????restart,?ctrlaltdel,?and?shutdown.

#process:????Specifies?the?process?to?be?executed?and?it's?command?line.
/*******************************解析************************************/
從默認(rèn)的new_init_action反推出默認(rèn)的配置文件:
#?inittab格式:
#:::#?id?=>?/dev/id,用作終端:stdin,stdout,stderr:printf,?scanf,?err(即標(biāo)準(zhǔn)輸入、輸出、錯(cuò)誤設(shè)
#?備),如果省略,則使用與Init進(jìn)程一樣的控制臺(tái)。
#?runlevels?:?忽略?
#?action??????:執(zhí)行時(shí)機(jī)?sysinit,?respawn,?askfirst,?wait,?once,
#????????????????????????restart,?ctrlaltdel,?and?shutdown.
#?process?????:應(yīng)用程序或腳本,如果前有“-”字符,這個(gè)程序被稱為“交互的”。

在init_main函數(shù)中,調(diào)用了parse_inittab函數(shù)來(lái)讀取配置文件inittab。如果根文件系統(tǒng)中沒有/etc/inittab文件,Busybox init程序?qū)⑹褂媚J(rèn)的inittab條目。這里我們可以通過默認(rèn)的配置語(yǔ)句,倒推出默認(rèn)的配置文件內(nèi)容。

DIR:?init.c-parse_inittab函數(shù)
     /*?Reboot?on?Ctrl-Alt-Del?*/
????????new_init_action(CTRLALTDEL,?"reboot",?"");
????????/*?Umount?all?filesystems?on?halt/reboot?*/
????????new_init_action(SHUTDOWN,?"umount?-a?-r",?"");
????????/*?Swapoff?on?halt/reboot?*/
????????if?(ENABLE_SWAPONOFF)?new_init_action(SHUTDOWN,?"swapoff?-a",?"");
????????/*?Prepare?to?restart?init?when?a?HUP?is?received?*/
????????new_init_action(RESTART,?"init",?"");
????????/*?Askfirst?shell?on?tty1-4?*/
????????new_init_action(ASKFIRST,?bb_default_login_shell,?"");
????????new_init_action(ASKFIRST,?bb_default_login_shell,?VC_2);
????????new_init_action(ASKFIRST,?bb_default_login_shell,?VC_3);
????????new_init_action(ASKFIRST,?bb_default_login_shell,?VC_4);
????????/*?sysinit?*/
????????new_init_action(SYSINIT,?INIT_SCRIPT,?"");
/*******************************解析************************************/
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount?-a?-r
::shutdown:/sbin/swapoff?-a
::restart:/sbin/init
::askfirst:-/bin/sh
tty2::askfirst:-/bin/sh
tty3::askfirst:-/bin/sh
tty4::askfirst:-/bin/sh?
::sysinit:/etc/init.d/rcS

這里涉及到了一個(gè)函數(shù) new_init_action 。 它實(shí)際上的工作就是把各個(gè)程序的執(zhí)行時(shí)機(jī)、命令行、控制臺(tái)參數(shù)分別賦值給結(jié)構(gòu)體,并把這些結(jié)構(gòu)體組成一個(gè)單鏈表。這也就是我們所說的配置。 它的聲明是:static void new_init_action(int action, const char *command, const char *cons);這三個(gè)參數(shù)不正是inittab配置文件中的配置命令嗎?他們分別對(duì)應(yīng)于來(lái)看看new_init_action函數(shù):

DIR:init.c-new_init_action函數(shù)

static?void?new_init_action(int?action,?const?char?*command,?const?char?*cons)
{
????struct?init_action?*new_action,?*a,?*last;

????if?(strcmp(cons,?bb_dev_null)?==?0?&&?(action?&?ASKFIRST))
????????return;

????/*?Append?to?the?end?of?the?list?*/
????for?(a?=?last?=?init_action_list;?a;?a?=?a->next)?{
????????/*?don't?enter?action?if?it's?already?in?the?list,
?????????*?but?do?overwrite?existing?actions?*/
????????if?((strcmp(a->command,?command)?==?0)
?????????&&?(strcmp(a->terminal,?cons)?==?0)
????????)?{
????????????a->action?=?action;
????????????return;
????????}
????????last?=?a;
????}

????new_action?=?xzalloc(sizeof(struct?init_action));
????if?(last)?{
????????last->next?=?new_action;
????}?else?{
????????init_action_list?=?new_action;
????}
????strcpy(new_action->command,?command);
????new_action->action?=?action;
????strcpy(new_action->terminal,?cons);
????messageD(L_LOG?|?L_CONSOLE,?"command='%s'?action=%d?tty='%s'n",
????????new_action->command,?new_action->action,?new_action->terminal);
}

/*?Set?up?a?linked?list?of?init_actions,?to?be?read?from?inittab?*/
struct?init_action?{
?  struct?init_action?*next;
  ?int?action;
  ?pid_t?pid;
  ?char?command[INIT_BUFFS_SIZE];
  ?char?terminal[CONSOLE_NAME_SIZE];
  };

new_init_action函數(shù)用于配置,參數(shù)為執(zhí)行時(shí)機(jī)、命令行、控制臺(tái)。
?結(jié)構(gòu)體指針new_action開始指向上一個(gè)配置過的程序(其存儲(chǔ)在結(jié)構(gòu)體,參數(shù)是上一個(gè)程序的執(zhí)行時(shí)機(jī)、命令行、控制臺(tái)),這里首先進(jìn)行了一個(gè)If判斷,如果控制臺(tái)等于bb_dev_null(宏定義等于 /dev/null)且action為ASKFIRST那么直接返回,不進(jìn)行任何配置。
?接著這個(gè)for循環(huán)算是這個(gè)函數(shù)的一個(gè)重點(diǎn)吧,首先令結(jié)構(gòu)體指針init_action_list賦值給a和last。
?這里的init_action_list(宏定義為NULL)開始為NULL,后來(lái)指向第一個(gè)配置的程序。
?也就是說,遍歷所有配置過的程序,如果這個(gè)程序之前被配置過(命令行和控制臺(tái)同時(shí)等于當(dāng)前遍歷的程序),那么執(zhí)行時(shí)機(jī)action被重新賦值為當(dāng)前值。
?通俗的說,這個(gè)for為了避免程序重復(fù)配置,查找之前配置過的程序有沒有當(dāng)前要配置的程序,如果有,則只改變其執(zhí)行時(shí)機(jī)action。命令行和控制臺(tái)不變。
?如果沒有,接下來(lái)為new_action重新分配內(nèi)存,并且給它賦值,令它的各項(xiàng)信息等于當(dāng)前的程序。在上面的if語(yǔ)句中,last->next=new_action,也就是說,將所有程序的配置結(jié)構(gòu)體連成一個(gè)單鏈表。

new_init_action函數(shù)講解完畢。

經(jīng)過上面的講解,我們明白了Linux根文件系統(tǒng)中,對(duì)于程序的配置是在parse_inittab函數(shù)完成的,它打開配置文件inittab,將程序信息一一填入結(jié)構(gòu)體init_action,并將它們連接成單鏈表?,F(xiàn)在配置已經(jīng)完成,下一步是執(zhí)行了。接著看init_main中的代碼是怎樣執(zhí)行應(yīng)用程序的:

busybox->?init_main
????????????parse_inittab
????????????????file?=?fopen(INITTAB,?"r");?//打開配置文件/etc/inittab

????????????????new_init_action?????//?①?創(chuàng)建一個(gè)init_action結(jié)構(gòu),填充
????????????????????????????????????//?②?把這個(gè)結(jié)構(gòu)放入init_action_list鏈表
????????????run_actions(SYSINIT);
????????????????waitfor(a,?0);??????//?執(zhí)行應(yīng)用程序,等待它執(zhí)行完畢
????????????????????run(a)??????????//?創(chuàng)建process子進(jìn)程
????????????????????waitpid(runpid,?&status,?0);?//?等待它結(jié)束
????????????????delete_init_action(a);//?在init_action_list鏈表里刪除?????????????
????????????run_actions(WAIT);
????????????????waitfor(a,?0);??????//?執(zhí)行應(yīng)用程序,等待它執(zhí)行完畢
????????????????????run(a)??????????//?創(chuàng)建process子進(jìn)程
????????????????????waitpid(runpid,?&status,?0);?//?等待它結(jié)束
????????????????delete_init_action(a);//?在init_action_list鏈表里刪除?
????????????run_actions(ONCE);
????????????????run(a);
????????????????delete_init_action(a);
????????????while(1)?{
????????????????run_actions(RESPAWN);
????????????????????if?(a->pid?==?0)?{
????????????????????????a->pid?=?run(a);
????????????????????}
????????????????run_actions(ASKFIRST);
????????????????????if?(a->pid?==?0)?{
????????????????????????a->pid?=?run(a);
????????????????????????????????打印:Please?press?Enter?to?activate?this?console.
????????????????????????????????等待回車
????????????????????????????????創(chuàng)建子進(jìn)程
????????????????????}
????????????????wpid?=?wait(NULL);??//?等待子進(jìn)程退出
????????????????while?(wpid?>?0)?{
????????????????????a->pid?=?0;?????//?退出后,就設(shè)置pid=0
????????????????}
????????????}

在/etc/inittab文件的控制下,init進(jìn)程的行為總結(jié)如下: ① 在系統(tǒng)啟動(dòng)前期,init進(jìn)程首先啟動(dòng)為sysinit、wait、once的3類子進(jìn)程。 ② 在系統(tǒng)正常運(yùn)行期間,init進(jìn)程首先啟動(dòng)為respawn、askfirst的兩類子進(jìn)程。 ③ 在系統(tǒng)退出時(shí),執(zhí)行為shutdown、restart、ctrlaltdel的三類子進(jìn)程(之一或全部) 從而我們可以總結(jié)出來(lái)最小的根文件系統(tǒng)由5部分組成: 1./dev/console or/dev/null 2.init => busybox 3./etc/inittab 4.配置文件指定的程序 5.C庫(kù) busybox的配置、編譯和安裝 打開busybox自帶的INSTALL文件查看我們?cè)撛鯓优渲谩⒕幾g和安裝busybox。

Building:
=========

The?BusyBox?build?process?is?similar?to?the?Linux?kernel?build:

??make?menuconfig?????#?This?creates?a?file?called?".config"
??make????????????????#?This?creates?the?"busybox"?executable
??make?install????????#?or?make?CONFIG_PREFIX=/path/from/root?install

The?full?list?of?configuration?and?install?options?is?available?by?typing:

??make?help

1.配置 進(jìn)入busybox文件夾make menuconfig生成配置文件.config

2.編譯

由于我們文件系統(tǒng)是給嵌入式板子用的,先修改Busybox的Makefile,使用交叉編譯器。

修改前

ARCH?????????=?$(SUBARCH)
CROSS_COMPILE????=

修改后

ARCH?????????=?$(SUBARCH)
CROSS_COMPILE????=?arm-linux-

然后make3.安裝 注意:如果你是在虛擬機(jī)上安裝busybox,安裝不可直接執(zhí)行make INSTALL,必須在虛擬機(jī)下自己創(chuàng)建一個(gè)文件夾,將安裝路徑指向這個(gè)文件夾的路徑。再執(zhí)行make CONFIG_PREFIX=dir_path install否則會(huì)破壞系統(tǒng)。 注:除bin/busybox外,其他文件都是到bin/busybox的符號(hào)連接。busybox是所有命令的集合體,這些符號(hào)連接文件可以直接運(yùn)行。比如在開發(fā)板上,運(yùn)行“l(fā)s”命令和”busybox ls”命令是一樣的。

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉