【linux驅動筆記】linux模塊機制淺析

 

1.   模塊module

操做系統分微內核和宏內核,微內核優勢,可使操做系統僅做不多的事,其它事情如網絡處理等都做爲應用程序來實現,微內核精簡的同時,必然帶來性能的降低。而linux的宏內核設計,保證了設計性能,但linux做爲一個通用操做系統,必然會兼容不少硬件,而linux自己的宏內核設計,致使了若是同時兼容全部的硬件,其編譯代碼將龐大無比,爲了解決這個問題,linux效仿微內核,採用了模塊這一天才思想。當內核配置make menuconfig時,能夠選擇M,將驅動做爲模塊來加載,其生成的文件後綴爲*.ko. kernel object,內核對象。採用模塊設計,解決了上述問題,可是本質上來講,模塊加載進內核後,仍是運行在內核態,因此驅動的bug有可能引發系統崩潰,這是在驅動設計時須要特別注意的。html

1.1.  模塊實例

#include <linux/init.h>linux

#include <linux/module.h>web

 

static int hellokernel_init(void)網絡

{函數

   

    printk("Hello driver!\n");工具

    return 0;性能

}ui

 

static void hellokernel_exit(void)spa

{操作系統

    printk("Bye driver!\n");

}

 

module_init(hellokernel_init);

module_exit(hellokernel_exit);

 

上面都的module_initmodule_exit都幹了什麼,當加載模塊insmod 和卸載模塊rmmod時又幹了什麼,下面將說明。

 

1.2.  module_init,module_exit

\include\linux\Init.h 中有:

#ifndef MODULE

#define module_init(x)  __initcall(x);

#define __initcall(fn) device_initcall(fn)

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

 

#define module_exit(x)  __exitcall(x);

#define __exitcall(fn) \

  static exitcall_t __exitcall_##fn __exit_call = fn

#else

  /* Each module must use one module_init(). */

#define module_init(initfn)           \

  static inline initcall_t __inittest(void)    \

  { return initfn; }             \

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

 

/* This is only required if you want to be unloadable. */

#define module_exit(exitfn)           \

  static inline exitcall_t __exittest(void)    \

  { return exitfn; }             \

  void cleanup_module(void) __attribute__((alias(#exitfn)));

#endif

 

 

從上述處理能夠看出,當以非模塊編譯時,module_init等經過以下路徑被執行,其被靜態編譯進內核。

#define __define_initcall(fn, id) \

   static initcall_t __initcall_##fn##id __used \

   __attribute__((__section__(".initcall" #id ".init"))) = fn

 

而上述用__define_initcall(fn, id)定義的函數都是在linux內核啓動時被執行的。

start_kernelrest_initkernel_initkernel_init_freeabledo_basic_setupdo_initcalls

 

 

而若是是模塊編譯時,爲動態編譯

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

這段代碼的做用是給咱們的加載函數定義一個別名,別名就是init_module

 

 

1.3.  加載模塊

hello.ko拷貝到/home/tang/wk-tzp/prj/nfs/fs/ramdisk_fs/lib/modules/3.10.53的目錄或者其子目錄下,

必須拷貝到對應的版本號如3.10.53下,不然會出問題。

 

insmod hello.ko

 

 

insmod是個應用程序,在嵌入式中,這些應用包括lspwd等都來自於大名鼎鼎的busybox

所以須要閱讀busybox的源代碼,才能知道insmod究竟幹了什麼。

busybox-1.22.1\modutilsinsmod.c中:有:

insmod_mainbb_init_module

   

   

try_to_mmap_module //經過mmap函數將 xxx.ko文件內容映射到內存中。

init_module(image, image_size, options) //是宏syscall(__NR_init_module, mod, len, opts),調用linux系統調用

// image:指向***.ko文件內容開始,image_size***.ko模塊文件大小,options爲參數

 

arch/arm/include/asm/unistd.h中,有#define __NR_init_module     (__NR_SYSCALL_BASE+128)

linux/arch/arm/kernel/calls.S有:

/* 125 */  CALL(sys_mprotect)

       CALL(sys_sigprocmask)

       CALL(sys_ni_syscall)     /* was sys_create_module */

       CALL(sys_init_module)

       CALL(sys_delete_module)

可見,__NR_init_module   對應 sys_init_module,因此insmod最終調用sys_init_module

Module.c (src\kernel) 中有:

SYSCALL_DEFINE3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs)

Syscalls.h (src\include\linux) 中有:#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

#define SYSCALL_DEFINEx(x, sname, ...)              \

   SYSCALL_METADATA(sname, x, __VA_ARGS__)          \

   __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

 

#define __SYSCALL_DEFINEx(x, name, ...)               \

    asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));  \

 

由上述可見,SYSCALL_DEFINE3(init_module…定義了 sys_init_module函數。

 

繼續調用:

SYSCALL_DEFINE3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs)

load_moduledo_init_moduledo_one_initcall(mod->init)ret = fn();即執行了module_init(hello_init)中定義的函數

hello_init

 

 

1.4.  卸載模塊

rmmod hello, 不能用 rmmod hello.ko

 

仍然從應用層開始,rmmod是由工具箱busybox實現的,

rmmod.c (busybox-1.22.1\modutils): int rmmod_main(int argc UNUSED_PARAM, char **argv)

bb_delete_module // 宏定義爲syscall(__NR_delete_module, mod, flags),執行linux系統調用sys_delete_module

 

insmod討論的同樣,最後會執行以下的語句

Module.c (src\kernel) 中有:

SYSCALL_DEFINE2(delete_module, const char __user *, name_user, unsigned int, flags)

mod->exit(); //module_exit(exit_func)定義的函數exit_func

1.5.  細節

src\Makefilemake modules  : 目標是modules, 編譯好後須要安裝在製做的文件系統

make  modules_install  INSTALL_MOD_PATH=~/fs/ramdisk_fs

 

 

THIS_MODULE: http://www.cnblogs.com/ziziwu/archive/2012/07/06/2578283.html

 

insmod/modprobe    rmmod   lsmod modinfo

       insmod  hellokernel.ko  irq=100 pstr=china fish=1,2,3

       echo 200 > /sys/module/hellokernel/parameters/irq   

       echo 10,20,30 > /sys/module/hellokernel/parameters/fish

權限問題:

  0:在/sys/module/模塊名/paramters/文件

  經過修改這個文件完成對變量的內容修改

  問題:會佔用內存的資源

 

  權限爲0:就不會有一個文件存在,只能在模塊  加載的時候才能修改

 

1.6.  函數集合

insmod/modprobe   

rmmod  

lsmod

modinfo

 

1.7.  文獻

http://www.cnblogs.com/fanzhidongyzby/p/3730131.html

歡迎轉載,轉載時需保留做者信息,謝謝。

郵箱:tangzhongp@163.com

博客園地址:http://www.cnblogs.com/embedded-tzp

Csdn博客地址:http://blog.csdn.net/xiayulewa

相關文章
相關標籤/搜索