中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用Linux內核模塊

發布時間:2021-11-23 14:43:06 來源:億速云 閱讀:180 作者:iii 欄目:互聯網科技

這篇文章主要介紹“怎么使用Linux內核模塊”,在日常操作中,相信很多人在怎么使用Linux內核模塊問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么使用Linux內核模塊”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

一、模塊定義

Linux內核使用xx_initcall_xx(fn)的宏來定義內核模塊。

宏定義文件:include/linux/init.h,定義如下:

/* * Early initcalls run before initializing SMP. * * Only for built-in code, not modules. */#define early_initcall(fn)      __define_initcall(fn, early)/* * A "pure" initcall has no dependencies on anything else, and purely * initializes variables that couldn't be statically initialized. * * This only exists for built-in code, not for modules. * Keep main.c:initcall_level_names[] in sync. */#define pure_initcall(fn)       __define_initcall(fn, 0)#define core_initcall(fn)       __define_initcall(fn, 1)#define core_initcall_sync(fn)      __define_initcall(fn, 1s)#define postcore_initcall(fn)       __define_initcall(fn, 2)#define postcore_initcall_sync(fn)  __define_initcall(fn, 2s)#define arch_initcall(fn)       __define_initcall(fn, 3)#define arch_initcall_sync(fn)      __define_initcall(fn, 3s)#define subsys_initcall(fn)     __define_initcall(fn, 4)#define subsys_initcall_sync(fn)    __define_initcall(fn, 4s)#define fs_initcall(fn)         __define_initcall(fn, 5)#define fs_initcall_sync(fn)        __define_initcall(fn, 5s)#define rootfs_initcall(fn)     __define_initcall(fn, rootfs)#define device_initcall(fn)     __define_initcall(fn, 6)#define device_initcall_sync(fn)    __define_initcall(fn, 6s)#define late_initcall(fn)       __define_initcall(fn, 7)#define late_initcall_sync(fn)      __define_initcall(fn, 7s)

其中:early_initcall(fn)只針對內核的核心代碼,不能描述模塊。

從上面代碼可以看出,每個宏的實現都是__define_initcall(),其定義如下:

#define __define_initcall(fn, id) \    static initcall_t __initcall_##fn##id __used \    __attribute__((__section__(".initcall" #id ".init"))) = fn; \    LTO_REFERENCE_INITCALL(__initcall_##fn##id)    typedef int (*initcall_t)(void);

對于上面定義,需要關注以下幾點:

1、initcall_t:是一個函數指針類型,定義__initcall_##fn##id,指向fn

2、__used:在文件include/linux/compiler-gcc.h中定義為:# define __used __attribute__((__used__)),通知編譯器在目標文件中保留一個靜態函數,即使該函數未被使用。

3、__attribute__((__section__(".initcall" #id ".init"))):定義的函數指針位于.initcall*.init段中。

二、鏈接位置

在文件include/asm-generic/vmlinux.lds.h中,定義了宏INIT_CALLS,定義如下:

#define INIT_CALLS_LEVEL(level)                     \        VMLINUX_SYMBOL(__initcall##level##_start) = .;      \        *(.initcall##level##.init)              \        *(.initcall##level##s.init)             \#define INIT_CALLS                          \        VMLINUX_SYMBOL(__initcall_start) = .;           \        *(.initcallearly.init)                  \        INIT_CALLS_LEVEL(0)                 \        INIT_CALLS_LEVEL(1)                 \        INIT_CALLS_LEVEL(2)                 \        INIT_CALLS_LEVEL(3)                 \        INIT_CALLS_LEVEL(4)                 \        INIT_CALLS_LEVEL(5)                 \        INIT_CALLS_LEVEL(rootfs)                \        INIT_CALLS_LEVEL(6)                 \        INIT_CALLS_LEVEL(7)                 \        VMLINUX_SYMBOL(__initcall_end) = .;

在文件arch/arm64/kernel/vmlinux.lds.S 中,設置了宏INIT_CALLS.init.data段中的分布位置,內容如下:

    .init.data : {        INIT_DATA        INIT_SETUP(16)        INIT_CALLS        CON_INITCALL        SECURITY_INITCALL        INIT_RAM_FS    }

在Linux內核編譯鏈接后,會生成文件arch/arm64/kernel/vmlinux.lds。在該文件中將展開宏INIT_CALLS,并分配到.init.data段中,內容如下:

 .init.data : {...  __initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .;... }

注:在__initcall_start__initcall_end之間是按照從0到7的順序進行排列,對應pure_initcall(fn)late_initcall_sync(fn)

三、模塊加載

Linux內核模塊可以直接編譯到內核映像,在內核啟動時加載;也可以在系統啟動后,通過insmod命令加載到內核。

Linux內核啟動時,kernel_init線程會實現靜態編譯的內核模塊加載。

1、程序調用流程

## kernel/init/main.cstart_kernel()->    rest_init()->        kernel_thread(kernel_init, NULL, CLONE_FS) ## 1.創建內核線程kernel_init()->    kernel_init_freeable()->        do_basic_setup()->            do_initcalls()->      ## 2.模塊加載過程                do_initcall_level()->                    do_one_initcall()

2、do_initcalls()函數

函數功能:按順序掃描.init.data段中的每個等級,即:從__initcall0_start__initcall_end

## __initdata中的定義在static initcall_t *initcall_levels[] __initdata = {    __initcall0_start,     __initcall1_start,    __initcall2_start,    __initcall3_start,    __initcall4_start,    __initcall5_start,    __initcall6_start,    __initcall7_start,    __initcall_end,};static void __init do_initcalls(void){    int level;    for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)        do_initcall_level(level);}

3、do_initcall_level()函數

函數功能:在同一個等級中,按順序掃描.initcall*.init.initcall*s.init

static void __init do_initcall_level(int level){    ...    for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)        do_one_initcall(*fn);}

4、do_one_initcall()函數

函數功能:調用每個定義的模塊函數。

int __init_or_module do_one_initcall(initcall_t fn){    ...    if (initcall_debug)        ret = do_one_initcall_debug(fn);    else        ret = fn(); ##調用某個定義的initcall函數    ...    return ret;}

注:每個fn()對應第一部分模塊定義中的fn,例:device_initcall(fn)

四、模塊優先級

從上面函數的執行流程可以看出內核模塊加載優先級如下:

early_initcall(fn)               ## 優先級最高,后續優先級依次降低pure_initcall(fn)core_initcall(fn)core_initcall_sync(fn)postcore_initcall(fn)postcore_initcall_sync(fn)arch_initcall(fn)arch_initcall_sync(fn)subsys_initcall(fn)subsys_initcall_sync(fn)fs_initcall(fn)fs_initcall_sync(fn)rootfs_initcall(fn)device_initcall(fn)device_initcall_sync(fn)late_initcall(fn)late_initcall_sync(fn)          ## 優先級最低

Linux內核模塊的優先級決定了模塊的加載順序,在驅動開發時,需要關注有啟動順序要求的模塊定義。

到此,關于“怎么使用Linux內核模塊”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

冀州市| 三河市| 五大连池市| 哈尔滨市| 西和县| 留坝县| 军事| 贵南县| 青神县| 栾川县| 大庆市| 英超| 社旗县| 朝阳市| 神木县| 海门市| 高邑县| 浦北县| 锡林浩特市| 通渭县| 黑龙江省| 泽普县| 西青区| 泗洪县| 高州市| 班戈县| 南投市| 霸州市| 共和县| 天峻县| 双桥区| 平陆县| 鹿泉市| 乌恰县| 甘洛县| 乐安县| 德安县| 务川| 砚山县| 奉化市| 麦盖提县|