女人被狂躁到高潮视频免费无遮挡,内射人妻骚骚骚,免费人成小说在线观看网站,九九影院午夜理论片少妇,免费av永久免费网址

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式軟件
[導(dǎo)讀]一直以來寫linux驅(qū)動,都是按照固定格式,定義一個初始化和退出函數(shù),書上告訴我這兩個函數(shù)會被調(diào)用,至于為什么會被調(diào)用,在哪調(diào)用,一直不清楚。

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

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

void init(void)

{

init_a();

init_b();

}

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

init_c();

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

void init_a(void)

{

}

__initlist(init_a, 1);

它是通過這個宏來實(shí)現(xiàn)初始化函數(shù)列表的呢?

先來看__initlist的定義:

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

#define __initlist(fn, lvl) /

static initlist_t __init_##fn __init = { /

magic: INIT_MAGIC, /

callback: fn, /

level: lvl }

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

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

extern u32 __initlist_start;

extern u32 __initlist_end;

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

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

在一個連接器腳本文件里

. = ALIGN(4);

.initlist : {

__initlist_start = .;

*(.initlist)

__initlist_end = .;

}

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

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

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

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

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

rest_init();

static void rest_init(void)

{

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

unlock_kernel();

cpu_idle();

}

創(chuàng)建了一個內(nèi)核線程,主函數(shù)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();

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

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內(nèi)存管理的事了。

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

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

#define module_init(x) __initcall(x);

因?yàn)?/p>

#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

更直白點(diǎn),假設(shè)閣下driver所對應(yīng)的模塊的初始化函數(shù)為int gpio_init(void),那么module_init(gpio_init)實(shí)際上等于:

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

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

這里的函數(shù)指針變量聲明比較特殊的地方在于,將這個變量放在了一名為".initcall6.init"節(jié)中。接下來結(jié)合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中的初始化函數(shù)何時被調(diào)用了:在系統(tǒng)啟動過程中start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()。

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

#define module_init(initfn) \

static inline initcall_t __inittest(void) \

{ return initfn; } \

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

這段宏定義關(guān)鍵點(diǎn)是后面一句,通過alias將initfn變名為init_module。前面那個__inittest的定義其實(shí)是種技巧,用來對initfn進(jìn)行某種靜態(tài)的類型檢查,如果閣下將模塊初始化函數(shù)定義成,比如,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將模塊初始化函數(shù)統(tǒng)一別名為init_module,這樣以后insmod時候,在系統(tǒng)內(nèi)部會調(diào)用sys_init_module()去找到init_module函數(shù)的入口地址。

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

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

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護(hù)是驅(qū)動電源設(shè)計(jì)中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機(jī)驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計(jì)工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉