欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

linux內(nèi)核中do_initcalls函數(shù)的執(zhí)行邏輯分析

嵌入式小生 ? 來源:嵌入式小生 ? 2023-01-13 09:20 ? 次閱讀

一、導讀

linux內(nèi)核啟動過程中,會向終端打印出很多的日志信息,從這些信息中可以得到許多內(nèi)核的行為。如果在啟動階段出現(xiàn)了問題,那么很多的提示信息也會從終端打印出。

這些信息的輸出與具體模塊功能的執(zhí)行都歸功于一個函數(shù):do_initcalls,本文將主要分析這個函數(shù)的執(zhí)行邏輯,且從這個函數(shù)延伸到linux各個子系統(tǒng)初始化背后的機制。

本文所有源碼分析基于linux內(nèi)核版本:4.1.15

二、do_initcalls

do_initcalls由do_basic_setup()調(diào)用:

ebe49646-92da-11ed-bfe3-dac502259ad0.png

do_basic_setup()由kernel_init()代表的內(nèi)核init線程函數(shù)間接調(diào)用(在kernel_init_freeable()被調(diào)用)。

在調(diào)用do_basic_setup之前,處理器已經(jīng)被初始化了,CPU子系統(tǒng)已經(jīng)啟動并且運行,內(nèi)存和進程管理也工作正常,但是系統(tǒng)中的設備還沒有被初始化,故而do_basic_setup正作用于此,本文主要描述do_initcalls,所以不再進而分析其他的函數(shù)。

do_initcalls在/init/main.c文件中實現(xiàn):

staticvoid__initdo_initcalls(void)
{
intlevel;

for(level=0;level

函數(shù)中內(nèi)容比較少,是一個for循環(huán)結(jié)構(gòu),循環(huán)的對象是initcall_levels數(shù)組,該數(shù)組用于描述初始化調(diào)用的級別,定義如下:

externinitcall_t__initcall_start[];
externinitcall_t__initcall0_start[];
externinitcall_t__initcall1_start[];
externinitcall_t__initcall2_start[];
externinitcall_t__initcall3_start[];
externinitcall_t__initcall4_start[];
externinitcall_t__initcall5_start[];
externinitcall_t__initcall6_start[];
externinitcall_t__initcall7_start[];
externinitcall_t__initcall_end[];

staticinitcall_t*initcall_levels[]__initdata={
__initcall0_start,
__initcall1_start,
__initcall2_start,
__initcall3_start,
__initcall4_start,
__initcall5_start,
__initcall6_start,
__initcall7_start,
__initcall_end,
};

從上述代碼可見,initcall_levels數(shù)組中的元素為initcall_t類型的指針,回到do_initcalls()函數(shù)中,該函數(shù)的核心操作是:按順序從__initcall0_start開始,到__initcall_end結(jié)束的節(jié)段(稱為初始化調(diào)用段)中取出不同段之間的函數(shù),并執(zhí)行。

存在這幾個初始化調(diào)用段之間的函數(shù)都是內(nèi)核中各個模塊的初始化函數(shù),而這些函數(shù)是如何加入到初始化調(diào)用段中的呢?又是如何設置調(diào)用級別的,會在后文中描述到。

在do_initcalls()函數(shù)中,會根據(jù)initcall_levels初始化調(diào)用級別的數(shù)量調(diào)用do_initcall_level(),該函數(shù)實現(xiàn)如下:

staticvoid__initdo_initcall_level(intlevel)
{
initcall_t*fn;

strcpy(initcall_command_line,saved_command_line);
parse_args(initcall_level_names[level],
initcall_command_line,__start___param,
__stop___param-__start___param,
level,level,
&repair_env_string);

for(fn=initcall_levels[level];fn

從上述代碼可見,在函數(shù)的最后也是一個for循環(huán)結(jié)構(gòu),該循環(huán)的操作對象為函數(shù)指針,且會將對應的函數(shù)指針傳遞到do_one_initcall中,在該函數(shù)執(zhí)行函數(shù)指針所指向的函數(shù):

ec54107a-92da-11ed-bfe3-dac502259ad0.png

三、構(gòu)造section并添加函數(shù)

(3-1)構(gòu)造初始化調(diào)用section

在linux內(nèi)核中,不同架構(gòu)(ARCH)下的kernel目錄中,都會有一個名為vmlinux.lds.S的鏈接腳本,初始化調(diào)用section的構(gòu)造則在這個鏈接腳本中完成。

本文以ARM32架構(gòu)為例

在/arch/arm/kernel/vmlinux.lds.S中的鏈接腳本中,.init.data輸出節(jié)段則需要INIT_CALLS作為輸入節(jié)段:

ec7ceb1c-92da-11ed-bfe3-dac502259ad0.png

INIT_CALLS定義在/include/asm-generic/vmlinux.lds.h文件中:

eca878e0-92da-11ed-bfe3-dac502259ad0.png

而在內(nèi)核的makefile中有以下語句:

LDFLAGS_vmlinux+=-Tarch/$(ARCH)/kernel/vmlinux.lds.s

用于指定構(gòu)建linux內(nèi)核鏡像時所使用的鏈接腳本,基于此,則會構(gòu)造好初始化調(diào)用section。

當初始化調(diào)用section構(gòu)造完成后,是如何向該section中添加函數(shù)的呢?繼續(xù)往下看。

(3-2)向section中添加函數(shù)

向section中添加函數(shù)的本質(zhì)操作則是__define_initcall(),定義如下:

ecd103aa-92da-11ed-bfe3-dac502259ad0.png

并且linux內(nèi)核基于__define_initcall()封裝出了多個宏定義接口,供內(nèi)核中各個模塊使用,接口如下:

ece83110-92da-11ed-bfe3-dac502259ad0.png

__define_initcall()宏定義的本質(zhì)則是定義一個initcall_t函數(shù)指針類型的變量并命名為__initcall_##fn##id,其中fn為賦值給該變量的函數(shù)名稱,id為初始化調(diào)用級別,然后將fn賦值給該變量。接著就是最為重要的技術(shù)點:使用__attribute__將該變量加入到命名為"initcall##id.init"的section中,其中id為初始化調(diào)用級別,所以將fn添加到初始化調(diào)用section中則是通過這一點實現(xiàn)。例如:如果有以下類似的代碼:

staticvoid__initshow_info(void)
{
printk("I'miriczhao
")
}

core_initcall(show_info);

經(jīng)過層層宏替換后,本質(zhì)上則變成:

staticinitcall_t__initcall_core_initcall1__used
__attribute__((__section__(".initcall1.init")))=show_info;

四、總結(jié)

綜上,linux內(nèi)核中使用基于__define_initcall封裝出的多個接口API初始化內(nèi)核的各個模塊,使用這些API接口會將指定的函數(shù)放到名稱為.initcall##id.init的section中,id為初始化調(diào)用級別,內(nèi)核中定義了14種調(diào)用級別:分別為1~7和1s~7s(linux 3.0后增加的擴展)。這些調(diào)用級別是按照先后順序依次排列的。

(4-1)linux內(nèi)核中,對于內(nèi)核的各個模塊的初始化,正是通過使用__define_initcall()的衍生宏定義API將初始化函數(shù)放置到__initcall##id.initsection中,不同模塊的初始化函數(shù)按照調(diào)用級別順序排列。在內(nèi)核啟動階段,這些放置到這個section中的函數(shù)指針將被do_initcalls()按順序依次調(diào)用,進而完成各個模塊的初始化操作。

linux內(nèi)核系統(tǒng)非常龐大,各個子系統(tǒng)也非常多,他們的初始化函數(shù)從源碼上是不需要在內(nèi)核啟動過程中去主動調(diào)用的,從設計上這一點也不現(xiàn)實,隨著內(nèi)核功能的增加,越來越復雜的驅(qū)動程序,從而linux內(nèi)核基于編譯器section技術(shù),設計了初始化調(diào)用機制,將各個模塊的初始化與linux內(nèi)核啟動主線分離。

(4-2)當使用基于__define_initcall封裝出的多個API接口時,函數(shù)指針放置到哪個子section由具體的宏定義API接口的level參數(shù)確定,較小的level參數(shù)對應的函數(shù)指針則被放置在前面。而位于同一個子section內(nèi)的函數(shù)指針順序不定,由編譯器按照編譯的順序隨機指定。所以,如果一個模塊的初始化函數(shù)想要越早被調(diào)用執(zhí)行,則需要有較小的調(diào)用級別。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 處理器
    +關(guān)注

    關(guān)注

    68

    文章

    19435

    瀏覽量

    231300
  • Arch
    +關(guān)注

    關(guān)注

    0

    文章

    18

    瀏覽量

    9694
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    316

    瀏覽量

    21749

原文標題:驚呆了,linux內(nèi)核中的這機制 | do_initcalls

文章出處:【微信號:嵌入式小生,微信公眾號:嵌入式小生】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    Linux內(nèi)核自解壓過程分析

    uboot完成系統(tǒng)引導以后,執(zhí)行環(huán)境變量bootm的命令;即,將Linux內(nèi)核調(diào)入內(nèi)存并調(diào)用do
    的頭像 發(fā)表于 12-08 14:00 ?1013次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>自解壓過程<b class='flag-5'>分析</b>

    linux內(nèi)核do_fork函數(shù)創(chuàng)建新進程

    前面已經(jīng)談了內(nèi)核加載與系統(tǒng)引導過程,下面我們來看看內(nèi)核do_fork() 函數(shù)是如何創(chuàng)建一個新的進程的。
    發(fā)表于 08-06 08:40

    Linux內(nèi)核源碼之我見——內(nèi)核源碼的分析方法

    ——找不到main函數(shù)。對于簡單的demo程序,我們可以從頭至尾的分析代碼的含義,但是分析內(nèi)核代碼這招就徹底失效了,因為沒有人能把Linux
    發(fā)表于 05-11 07:00

    簡單分析linux內(nèi)核的結(jié)構(gòu)體使用方法

    所謂linux驅(qū)動編程可以理解為linux內(nèi)核的編程。既然在內(nèi)核編程那就必須要符合內(nèi)核邏輯和各
    發(fā)表于 01-19 08:26

    邏輯代數(shù)與邏輯函數(shù)

    邏輯代數(shù)與邏輯函數(shù):本章主要討論分析和設計數(shù)字邏輯功能的數(shù)學。首先介紹邏輯代數(shù)
    發(fā)表于 09-01 09:11 ?0次下載

    Linux內(nèi)核GPIO操作函數(shù)的詳解分析

    本文檔的主要內(nèi)容詳細介紹的是Linux內(nèi)核GPIO操作函數(shù)的詳解分析免費下載。
    發(fā)表于 01-22 16:58 ?28次下載

    Linux內(nèi)核熱補丁安全隱患的探索

    修復的函數(shù)替換掉內(nèi)核存在問題的函數(shù)從而達到修復目的。 函數(shù)替換的思想比較簡單,就是在執(zhí)行
    的頭像 發(fā)表于 10-11 11:54 ?1812次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>熱補丁安全隱患的探索

    Linux內(nèi)核系統(tǒng)調(diào)用概述及實現(xiàn)原理

    本文介紹了系統(tǒng)調(diào)用的一些實現(xiàn)細節(jié)。首先分析了系統(tǒng)調(diào)用的意義,它們與庫函數(shù)和應用程序接口(API)有怎樣的關(guān)系。然后,我們考察了Linux內(nèi)核如何實現(xiàn)系統(tǒng)調(diào)用,以及
    的頭像 發(fā)表于 05-14 14:11 ?2266次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>系統(tǒng)調(diào)用概述及實現(xiàn)原理

    linux內(nèi)核啟動過程會執(zhí)行用戶空間的init進程

    linux內(nèi)核啟動過程的后期,在kernel_init()函數(shù)代表的init線程,會嘗試執(zhí)行用戶空間的init進程
    的頭像 發(fā)表于 10-14 09:12 ?1217次閱讀

    Linux內(nèi)核模塊參數(shù)傳遞與sysfs文件系統(tǒng)

    Linux應用開發(fā),為使應用程序更加靈活地執(zhí)行用戶的預期功能,我們有時候會通過命令行傳遞一些參數(shù)到main函數(shù),使得代碼
    發(fā)表于 06-07 16:23 ?2208次閱讀

    Linux內(nèi)核SoftIrq源代碼分析

    我們在分析linux內(nèi)核中斷剖析時,簡單的聊了一下SOFTIRQ, 而沒有進行深入分析. Linux內(nèi)核
    發(fā)表于 06-23 15:22 ?644次閱讀

    萬千設備,linux內(nèi)核如何知道?

    linux內(nèi)核設備的注冊由device_register()函數(shù)完成,這個函數(shù)linux設備驅(qū)動模型的核心
    的頭像 發(fā)表于 07-12 08:52 ?903次閱讀
    萬千設備,<b class='flag-5'>linux</b><b class='flag-5'>內(nèi)核</b>如何知道?

    Linux內(nèi)核如何使用結(jié)構(gòu)體和函數(shù)指針?

    我將結(jié)合具體的Linux內(nèi)核驅(qū)動框架代碼來展示Linux內(nèi)核如何使用結(jié)構(gòu)體和函數(shù)指針。
    的頭像 發(fā)表于 09-06 14:17 ?1088次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>如何使用結(jié)構(gòu)體和<b class='flag-5'>函數(shù)</b>指針?

    Linux驅(qū)動是如何掛載的

    | --- >do_initcalls | --- >do_initcall_level | --- >do_one_initcall 注意,這里就是驅(qū)動的初始化和驅(qū)動模塊的加載。 我們知道在 rest_
    的頭像 發(fā)表于 09-28 16:48 ?1084次閱讀
    <b class='flag-5'>Linux</b>驅(qū)動是如何掛載的

    bootm命令的執(zhí)行流程

    Bootm命令用來從memory啟動內(nèi)核,bootm命令的執(zhí)行流程如下圖所示。 在串口終端輸入bootm命令后,執(zhí)行do_bootm函數(shù)來完
    的頭像 發(fā)表于 12-04 17:33 ?1251次閱讀
    bootm命令的<b class='flag-5'>執(zhí)行</b>流程