Linux內核中一些重要的數據結構(一)

本文中分析linux kernel 中的比較重要的,在開發驅動過程中會碰到,萬丈高樓平地起嘛。

文中內容條目清單:

1、數據類型相關

2、module_init和module_exit

3、EXPORT_SYMBOL和EXPORT_SYMBOLGPL


具體內容:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1、數據類型相關

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

LCD控制器初始化過程中有個數據轉換

#define PICOS2KHZ(a) (1000000000UL/(a))
#define KHZ2PICOS(a) (1000000000UL/(a))
其中“UL”代表含義:
1不加UL的話, 默認地它的類型是int, 這是一個有符號類型,而內核中爲了限制說這個值是個無符號的值,就明確地標出UL,表示C標準中關於一個整數是如何決定它類型的優先級表:

後綴             類型
無               int
                   long int
                   long long int

u or U        unsigned int
                   unsigned long int
                   unsigned long long int

l or L           long int
                    long long int

ul or UL      unsigned long int
                    unsigned long long int

ll or LL        long long int

ull or ULL    

                    unsigned long long int


注意, 在上表中,比如對u, 則編譯器依次判斷常量值是否在unsigned int表示範圍內, 是類型就是unsigned int,
否則, 是否在unsigned long int表示範圍內, 是類型就是unsigned long int,否則, 是否在unsigned long long int表示範圍內, 是類型就是unsigned long long int.其餘一樣道理.
更詳細請參考C99標準:
ISO/IEC 9899:1999(草案) 6.4.4.1 Integer constants

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

module_init

module_exit

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

裝載時(insmod),調用module_init(...)中說明的函數。
卸載時(rmmod),調用module_exit(...)中說明的函數。

lsmod 查看被加載的驅動列表

 
數據聲明@kernel\include\linux\init.h
#define __init        __section(.init.text) __cold notrace
#define __initdata    __section(.init.data)
#define __initconst    __section(.init.rodata)
#define __exitdata    __section(.exit.data)
#define __exit_call    __used __section(.exitcall.exit)

#define __exit          __section(.exit.text) __exitused __cold
分析module_init,

如果某驅動想以func作爲該驅動的入口,則可以如下聲明:module_init(func);被上面的宏處理過後,變成__initcall_func6 __used加入到內核映像的".initcall"區。內核的加載的時候,會搜索".initcall"中的所有條目,並按優先級加載它們,他的執行優先級爲普通的6。值越小越優先被加載,被聲明爲pure_initcall的最先加載。

#define module_init(x)    __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define __define_initcall(level,fn,id) \
    static initcall_t __initcall_##fn##id __used \
    __attribute__((__section__(".initcall" level ".init"))) = fn

#define pure_initcall(fn)        __define_initcall("0",fn,0)
#define core_initcall(fn)        __define_initcall("1",fn,1)
#define core_initcall_sync(fn)        __define_initcall("1s",fn,1s)
#define postcore_initcall(fn)        __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn)    __define_initcall("2s",fn,2s)
#define arch_initcall(fn)        __define_initcall("3",fn,3)
#define arch_initcall_sync(fn)        __define_initcall("3s",fn,3s)
#define subsys_initcall(fn)        __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn)    __define_initcall("4s",fn,4s)
#define fs_initcall(fn)            __define_initcall("5",fn,5)
#define fs_initcall_sync(fn)        __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn)        __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn)        __define_initcall("6",fn,6)
#define device_initcall_sync(fn)    __define_initcall("6s",fn,6s)
#define late_initcall(fn)        __define_initcall("7",fn,7)
#define late_initcall_sync(fn)        __define_initcall("7s",fn,7s)

如果某驅動想以func作爲該驅動的入口,則可以如下聲明:module_init(func);被上面的宏處理過後,變成__initcall_func6 __used加入到內核映像的".initcall"區。內核的加載的時候,會搜索".initcall"中的所有條目,並按優先級加載它們,普通驅動程序的優先級是6。其它模塊優先級列出如下:值越小,越先加載。


#define module_exit(x)    __exitcall(x);
#define early_initcall(fn)        module_init(fn)
#define core_initcall(fn)        module_init(fn)
#define postcore_initcall(fn)        module_init(fn)
#define arch_initcall(fn)        module_init(fn)
#define subsys_initcall(fn)        module_init(fn)
#define fs_initcall(fn)            module_init(fn)
#define device_initcall(fn)        module_init(fn)
#define late_initcall(fn)        module_init(fn)

linux kernel中有很大一部分代碼是設備驅動代碼,這些驅動代碼都有初始化和反初始化函數,這些代碼一般都只執行一次,爲了有更有效的利用內存,這些代碼所佔用的內存可以釋放出來。
linux就是這樣做的,對只需要初始化運行一次的函數都加上__init屬性。在kernel初始化後期,釋放所有這些函數代碼所佔的內存空間

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

EXPORT_SYMBOL

EXPORT_SYMBOL_GPL

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  1. EXPORT_SYMBOL(符號名);  
  2. EXPORT_SYMBOL_GPL(符號名)
導出的符號可以被其他模塊使用,不過使用之前一定要聲明一下。EXPORT_SYMBOL_GPL()只適用於包含GPL許可權的模塊。

用法:就是在一個文件中定義符號,這個用EXPORT_SYMBOLEXPORT_SYMBOL_GPL聲明,可以其他函數中通過extern 聲明調用的對應符號名,那麼在此函數中即可被調用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章