色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

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

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

3天內不再提示

詳解嵌入式Linux設備驅動篇module_init

Q4MP_gh_c472c21 ? 來源:未知 ? 作者:李倩 ? 2018-04-18 14:50 ? 次閱讀

一直以來寫linux驅動,都是按照固定格式,定義一個初始化和退出函數,書上告訴我這兩個函數會被調用,至于為什么會被調用,在哪調用,一直不清楚。

偶然的一個機會,看到blob里面的代碼,里面有一個初始化函數列表。按照一般的編程想法,各部分的初始化函數會在一個固定的函數里調用比如:

void init(void)

{

init_a();

init_b();

}

如果再加入一個初始化函數呢,那么再init_b()后面再加一行:

init_c();

這樣確實能完成我們的功能,但這樣有一定的問題,就是不能獨立的添加初始化函數,每次添加一個新的函數都要修改init函數,blob中的初始化函數就是完全獨立的,只要用一個宏來修飾一下:

void init_a(void)

{

}

__initlist(init_a, 1);

它是通過這個宏來實現初始化函數列表的呢?

先來看__initlist的定義:

#define __init __attribute__((unused, __section__(".initlist")))

#define __initlist(fn, lvl) /

static initlist_t __init_##fn __init = { /

magic: INIT_MAGIC, /

callback: fn, /

level: lvl }

看來就是定義了一個結構體,存了初始化函數的指針,沒什么特別的。請注意:__section__(".initlist")

這個屬性起什么作用呢?它告訴連接器這個變量存放在.initlist區段,如果所有的初始化函數都是用這個宏,那么每個函數會有對應的一個initlist_t結構體變量存放在.initlist區段,也就是說我們可以在.initlist區段找到所有初始化函數的指針。怎么找到.initlist區段的地址呢?

extern u32 __initlist_start;

extern u32 __initlist_end;

這兩個變量起作用了,__initlist_start是.initlist區段的開始,__initlist_end是結束,通過這兩個變量我們就可以訪問到所有的初始化函數了。

這兩個變量在那定義的呢?

在一個連接器腳本文件里

. = ALIGN(4);

.initlist : {

__initlist_start = .;

*(.initlist)

__initlist_end = .;

}

這兩個變量的值正好定義在.initlist區段的開始和結束地址,所以我們能通過這兩個變量訪問到所有的初始化函數。

與此類似,內核中也是用到這種方法,所以我們寫驅動的時候比較獨立,不用我們自己添加代碼在一個固定的地方來調用我們自己的初始化函數和退出函數,連接器已經為我們做好了。當然module_init還有其他的特性,比如:我們的初始化函數在完成初始化后,代碼占用的空間會被釋放,這又是為什么呢?今天晚了,下次再寫。

linux kernel中有很大一部分代碼是設備驅動代碼,這些驅動代碼都有初始化和反初始化函數,這些代碼一般都只執行一次,為了有更有效的利用內存,這些代碼所占用的內存可以釋放出來。

linux就是這樣做的,對只需要初始化運行一次的函數都加上__init屬性。在kernel初始化后期,釋放所有這些函數代碼所占的內存空間。它是怎么做到的呢?看過module_init和module_exit 的人知道,連接器把帶__init屬性的函數放在同一個section里,在用完以后,把整個section釋放掉。

口說無憑,我們看源碼,init/main.c中start_kernel是進入kernel的第一個c函數,在這個函數的最后一行是

rest_init();

static void rest_init(void)

{

kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);

unlock_kernel();

cpu_idle();

}

創建了一個內核線程,主函數init,代碼如下:

static int init(void * unused)

{

lock_kernel();

do_basic_setup();

prepare_namespace();

/*

* Ok, we have completed the initial bootup, and

* we're essentially up and running. Get rid of the

* initmem segments and start the user-mode stuff..

*/

free_initmem();

unlock_kernel();

紅色那行代碼就是用來釋放初始化代碼和數據的。

void free_initmem(void)

{

#ifndef CONFIG_XIP_ROM

if (!machine_is_integrator()) {

free_area((unsigned long)(&__init_begin),

(unsigned long)(&__init_end),

"init");

}

#endif

}

接下來就是kernel內存管理的事了。

********************************************************************************************************

在Linux底下寫過driver模塊的對這個宏一定不會陌生。module_init宏在MODULE宏有沒有定義的情況下展開的內容是不同的,如果這個宏沒有定義,基本上表明閣下的模塊是要編譯進內核的(obj-y)。

1.在MODULE沒有定義這種情況下,module_init定義如下:

#define module_init(x) __initcall(x);

因為

#define __initcall(fn) device_initcall(fn)

#define device_initcall(fn) __define_initcall("6",fn,6)

#define __define_initcall(level,fn,id) \

static initcall_t __initcall_##fn##id __used \

__attribute__((__section__(".initcall" level ".init"))) = fn

所以,module_init(x)最終展開為:

static initcall_t __initcall_##fn##id __used \

__attribute__((__section__(".initcall" level ".init"))) = fn

更直白點,假設閣下driver所對應的模塊的初始化函數為int gpio_init(void),那么module_init(gpio_init)實際上等于:

static initcall_t __initcall_gpio_init_6 __used __attribute__((__section__(".initcall6.init"))) = gpio_init;

就是聲明一類型為initcall_t(typedef int (*initcall_t)(void))函數指針類型的變量__initcall_gpio_init_6并將gpio_init賦值與它。

這里的函數指針變量聲明比較特殊的地方在于,將這個變量放在了一名為".initcall6.init"節中。接下來結合vmlinux.lds中的

.initcall.init : AT(ADDR(.initcall.init) - (0xc0000000 -0x00000000)) {

__initcall_start = .;

*(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)

__initcall_end = .;

}

以及do_initcalls:

static void __init do_initcalls(void)

{

initcall_t *call;

for (call = __initcall_start; call < __initcall_end; call++)

do_one_initcall(*call);

/* Make sure there is no pending stuff from the initcall sequence */

flush_scheduled_work();

}

那么就不難理解閣下模塊中的module_init中的初始化函數何時被調用了:在系統啟動過程中start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()。

2.在MODULE被定義的情況下(大部分可動態加載的driver模塊都屬于此, obj-m),module_init定義如下:

#define module_init(initfn) \

static inline initcall_t __inittest(void) \

{ return initfn; } \

int init_module(void) __attribute__((alias(#initfn)));

這段宏定義關鍵點是后面一句,通過alias將initfn變名為init_module。前面那個__inittest的定義其實是種技巧,用來對initfn進行某種靜態的類型檢查,如果閣下將模塊初始化函數定義成,比如,void gpio_init(void)或者是int gpio_init(int),那么在編譯時都會有類似下面的warning:

GPIO/fsl-gpio.c: In function '__inittest':

GPIO/fsl-gpio.c:46: warning: return from incompatible pointer type

通過module_init將模塊初始化函數統一別名為init_module,這樣以后insmod時候,在系統內部會調用sys_init_module()去找到init_module函數的入口地址。

如果objdump -t gpio.ko,就會發現init_module和gpio_init位于相同的地址偏移處。簡言之,這種情況下模塊的初始化函數在insmod時候被調用。

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

    關注

    98

    文章

    14476

    瀏覽量

    136429
  • Linux
    +關注

    關注

    87

    文章

    11292

    瀏覽量

    209329
  • 函數
    +關注

    關注

    3

    文章

    4327

    瀏覽量

    62573

原文標題:嵌入式Linux設備驅動篇module_init 詳解

文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    嵌入式Linux下的USB設備驅動技術

    嵌入式Linux下的USB設備驅動技術 Linux以其穩定、高效、易定制、硬件支持廣泛、源代碼開放等特點,已在
    發表于 05-08 08:30 ?1850次閱讀
    <b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b>下的USB<b class='flag-5'>設備</b><b class='flag-5'>驅動</b>技術

    linux內核使用鏈接腳本模仿module_init機制實戰

    編寫過設備驅動就會經常碰到module_init這個宏來定義驅動入口函數。這個宏定義了一個函數指針指向我們的驅動入口函數,等到上電的時候就將
    發表于 06-16 10:42 ?660次閱讀
    <b class='flag-5'>linux</b>內核使用鏈接腳本模仿<b class='flag-5'>module_init</b>機制實戰

    嵌入式Linux字符驅動LED燈設計

    嵌入式Linux字符驅動LED燈設計嵌入式Linux字符設備
    發表于 02-03 14:28

    嵌入式Linux應用開發詳解 光盤

    `本書立足于嵌入式Linux平臺,側重于實際開發應用,是一本結合嵌入式Linux技術最新發展潮流和編者多年開發經驗,精心編寫的嵌入式
    發表于 06-02 10:26

    嵌入式linux設備驅動開發詳解SD

    嵌入式linux設備驅動開發詳解SD,本資料大于20M,分2部分發
    發表于 11-05 17:21

    ARM嵌入式Linux系統開發詳解

    例介紹了Linux設備驅動、網絡設備驅動、Flash設備驅動
    發表于 09-14 08:57

    linux驅動設備驅動開發詳解

    1.《linux驅動設備驅動開發詳解》 基于linux4.0 是目前主流的
    發表于 11-08 08:03

    IAR實現類linux驅動模塊框架module_init的相關資料推薦

    其實在單片機上也能使用類linux驅動模塊框架module_init(init_fun),從而給驅動管理提供了新的方式。boot.icf文件
    發表于 01-27 06:38

    嵌入式Linux設備驅動開發

    嵌入式Linux設備驅動開發 Linux 設備驅動
    發表于 09-10 13:10 ?82次下載
    <b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b><b class='flag-5'>設備</b><b class='flag-5'>驅動</b>開發

    嵌入式Linux字符設備驅動的設計與應用

    描述了基于嵌入式Linux的字符設備驅動程序的設計方法和實現過程。以電機、數碼管、串口和mini鍵盤的驅動設計為例,詳細闡述了
    發表于 02-23 15:45 ?24次下載

    嵌入式Linux字符設備驅動的設計與應用

    描述了基于嵌入式Linux的字符設備驅動程序的設計方法和實現過程。以電機、數碼管、串口和mini鍵盤的驅動設計為例,詳細闡述了
    發表于 07-14 17:31 ?31次下載

    詳解嵌入式linux 啟動信息

    詳解嵌入式linux 啟動信息
    發表于 10-30 10:28 ?11次下載
    <b class='flag-5'>詳解</b><b class='flag-5'>嵌入式</b><b class='flag-5'>linux</b> 啟動信息

    基于嵌入式Linux LCD設備驅動分析

    基于嵌入式Linux LCD設備驅動分析
    發表于 10-30 16:20 ?14次下載
    基于<b class='flag-5'>嵌入式</b><b class='flag-5'>Linux</b> LCD<b class='flag-5'>設備</b><b class='flag-5'>驅動</b>分析

    linux驅動的入口函數module_init的加載和釋放

    幾乎每個linux驅動都有個module_init(與module_exit的定義在Init.h (/include/
    發表于 05-05 14:43 ?5699次閱讀
    <b class='flag-5'>linux</b><b class='flag-5'>驅動</b>的入口函數<b class='flag-5'>module_init</b>的加載和釋放

    IAR 實現類linux驅動模塊框架module_init(init_fun)

    其實在單片機上也能使用類linux驅動模塊框架module_init(init_fun),從而給驅動管理提供了新的方式。boot.icf文件
    發表于 12-03 13:36 ?0次下載
    IAR 實現類<b class='flag-5'>linux</b><b class='flag-5'>驅動</b>模塊框架<b class='flag-5'>module_init</b>(<b class='flag-5'>init</b>_fun)
    主站蜘蛛池模板: www.青青草.com| 在线AV国产传媒18精品免费| 国产69精品久久久久麻豆| 日本福利片午夜免费观着| 99久久re6热精品首页| 老湿司午夜爽爽影院榴莲视频| 亚洲一区免费在线观看| 精品夜夜澡人妻无码AV蜜桃| 亚洲精品久久国产高清| 国产大片51精品免费观看| 色偷偷亚洲男人天堂| 91在线一区二区| 欧美午夜精品一区二区蜜桃| beeg日本老师| 日本无码免费久久久精品| 超碰免费视频公开观看| 强姧伦久久久久久久久| x69老师x日本| 欧美日韩看看2015永久免费| 纯肉高H放荡受BL文库| 日韩一卡二卡三卡四卡免费观在线| 高清AV熟女一区| 色翁荡熄月月| 国产午夜免费不卡精品理论片| 香蕉动漫库| 国产午夜不卡在线观看视频666| 亚洲精品无码午夜福利在线观看| 黑色丝袜美腿美女被躁翻了| 一区不卡二区卡| 理论片在线观看片免费| brazzers情欲狂欢| 日韩亚洲欧美中文高清| 变形金刚7免费观看完整| 色偷偷男人的天堂a v| 国产色精品VR一区二区| 永久免费精品精品永久-夜色| 看看妇女的B免费看| xxx成熟xxx| 视频一区国产在线二区| 姐姐不~不可以动漫在线观看| 伊人狼人久久精品热9|