2012年6月3日 星期日

建構第一個驅動(hello world)

驅動程式和模組之間的關係。而在模組程式中先決條件是在統一的核心核版($uname -r)
在核心版本不符合下其驅動不能被執行。
其相容性,其驅動程式與核心的相容性。用標準核心原始程式所建構的核心模組,就是標準核心模組,其不能在廠商的核心模組中使用。即使其模組程式相同,但在標準核心模組和特定廠商的核心模組中其所產生的模組格式也不同。

驅動模組的組成
image
1.標頭檔(必選)
   其中有二個是必要的
   1: #include <linux/module.h>

   2: #include <linux/init.h>


  module.h中含有模組中使用的symbol and define value。

  而在init.h中則有其module macro。





2.模組參數(可選)

   當其模組載入時,所傳給模組的參數。而模組可由其參數決定其所要執行的功能。

3.模組載入函數(必)

   在模組載入所執行的函數.

4.模組卸載函數(必)


  在模組卸載所執行的函數.

5.模組許可宣告.(必)

表示其受核心支援的程式。使用MODULE_LICENSE.


   1: MODULE_LICENSE("GPL");  //任一版本的GNU公開許可

   2: MODULE_LICENSE("GPL v2");  //版本2 的GNU公開許可

   3: MODULE_LICENSE("GPL and additional rights");  //GPL及其附加許可權

   4: MODULE_LICENSE("Dual DBS/GPL ");  //BSD/GPL

   5: MODULE_LICENSE("Proprietary");  //專有許可權


Hello World模組




   1: #include <linux/init.h>

   2: #include <linux/module.h>

   3:  

   4: static int hello_init(void)

   5: {

   6: printk(KERN_ALERT "Hello world\n");

   7: return 0;

   8: }

   9:  

  10: static void hello_exit(void)

  11: {

  12: printk(KERN_ALERT "goodbye world\n");

  13: }

  14:  

  15: module_init(hello_init);

  16: module_exit(hello_exit);

  17: MODULE_LICENSE("GPL")

在compiler其module時,必須滿足下列


  1. 編譯核心模組條件

    1. 版本問題,其核心及工具間的版本
    2. 必須要有一份核心的原始程式,且其版本與系統使用一致
    3. 核心的原始程式compiler過了.
  2. Makefile


         1: ifeq($(KERNELRELEASE),)

         2:     KERNELDIR ?= /linux-2.6.1.1/linux/2.6.1.1

         3:     PWD :=$(shell pwd)

         4: modules:

         5:     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

         6: modules_install:

         7:     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

         8: clear:

         9:     rm -rf *.o *.ko 

        10: else

        11:     obj -m: = hello.o

        12: endif
  3. Make file的執行過程


make會去判斷其KERNELRELEASE是否為空.設定其參數

執行4.5行來compiler module。而其$(MAKE) -C $(KERNELDIR) M=$(PWD) modules會進入linux-2.6.1.1/linux-2.6.1.1中讀makefile並設定變數(KERNELRELEASE)。然後再進入其模組所在的目錄中後再執行MAKE

會跑二次迴圈...執行obj -m :=hello.o==>hello.ko

模組的操作

提供了modutils.其主要有


  1. insmod

    1. 載入模組。其訊息會出現在終端中或是在/var/log/message中(demsg|tail)
    2. insmod 模組.ko 參數1=值1 參2=值2
    3. 其載入後系統影響有

      1. /proc/modules 在modules檔案中會增加資訊
      2. /proce/device(檔案只有裝置模組會出現
      3. /sys/module(增加一個目錄)
  2. rmmod

    1. 卸載
  3. modprobe

    1. 可載入'卸載(解決相依問題
  4. lsmod

    1. 列出已載入模組info
  5. modinfo

    1. 查詢模組的info

模組參數和模組之間的通訊

増加模組參數來控制模組內部邏輯,使模組在不同參數下有不同功能。

以module_param(參數名,參數資料類型,參數讀寫許可)


   1: static long a=1;

   2: static int b=1;

   3: module_param(a,long,S_IRUGO);

   4: module_param(b,int,S_IRUGO);


1.ELF檔案格式

image

其中.Section Table中記錄了ELF中所有段的資訊,(名稱、長度及屬性)

.symtab為符號表。映射函數到真實的記憶体位置。















2.模組間的通訊

image



















a.首先insmod載入模組2

b.核心為模組2分配空間,然後將.text; .data load memory

c.核心發現其模組2中的fun1,fun2 為export ,故把它們記錄在kernel symbol中

d.insmod模組1

e.核心為模組1分配空間,然後將.text; .data load memory

f.核心會在模組1中發現未定義的symbol,故會到kernel symbol table找,並找到且重定位.

3.code


   1: #include <linux/init.h>

   2: #include <lnux/module.h>

   3: #include "add_sub.h"

   4:  

   5: long add_int(int a,int b)

   6: {

   7: return a+b;

   8: }

   9:  

  10: long sub_int(int a,int b)

  11: {

  12: return a-b;

  13: }

  14: EXPORT_SYMBOL(add_int);

  15: EXPORT_SYMBOL(sub_int);

  16: MODULE_LICENSE("GPL");


   1: //add_sub.h

   2: #ifndef __ADD_SUB_H

   3: #define __ADD_SUB_H

   4: long add_int(int a,int b);

   5: long sub_int(int a,int b);

   6: #endif



   1: //test.h

   2: #include <linux/init.h>

   3: #include <linux/module.h>

   4: #include "add_sub.h"

   5:  

   6: //定義其模組間的參數,a,b

   7: static long a=1;

   8: static long b=1;

   9: static int AddOrSub=1;

  10:  

  11: static int test_inti(void) //載入函數

  12: {

  13:     long result=0;

  14:     printk("KERN_ALERT "test the module\n");

  15:     if(AddOrSub==1)

  16:          result=add_int(a,b);

  17:     else

  18:            result=sub_int(a,b);

  19: printk(KERN_ALERT "
the %s result is %ld",AddOrSub==1?"add":"sub",result);
  20: return 0;

  21: }

  22:  

  23: static void test_exit(void)

  24: {

  25: printk(KERN_ALERT "
test exit\n");
  26: }

  27:  

  28: module_init(test_inti);

  29: module_exit(test_exit);

  30: module_param(a,long,S_IRUGO);

  31: module_param(b,long,S_IRUGO);

  32: module_param(AddOrSub,int,S_IRUGO);

  33:  

  34: MODULE_LICENSE("
GPL");


   1: //Makefile

   2: ifeq($(KERNELRELEASE),)

   3:     KERNELDIR ?=/linux/2.6.29.4/linux/2.6.29.4

   4:     PWD := $(shell pwd)

   5:     PRINT_INC =($PWD)/../include

   6:     EXTRA_CFLAGS += -I $(PRINT_INC)

   7: modules:

   8:     $(MAKE) -I $(PRINTF_INC) -C $(KERNELDIR) M=$(PWD) modules

   9: modules_install:

  10:   $(MAKE) -C $(PRINTF_INC) M=$(PWD) modules_install

  11: clear:

  12:     rm -rf *.o *.ko

  13: .PHONY:modules modules_install clean

  14: else

  15:     #called from kernel build system

  16:     obj -m :=add_sub.o

  17: endif

  18:  

  19: //使用

  20: 1.insmod add_sub.ko

  21: 2.insmod test.ko a=1 b=1 AddOrSub=1

  22: //參數間不必逗號,以空白分邴

  23: 3.dmesg|tail 

  24: //查看var/log/messages內容

  25:  

  26:  

image



image



image

載入後:

image

image



image

將模組加入核心

1.撰寫驅動

2.將驅動程式放在linux核心原始程式相對的資料夾中.

3.在目錄的Kconfig檔案中增加其專案編譯選擇

4.在目錄中Makefiel檔增加其專案compiler statement.

沒有留言:

張貼留言