カスタムLinuxカーネルモジュールの作成


1.簡単なカーネルモジュールを開始する
 
私たちもハローワールドから始めましょう.ここでは、カーネルモジュールの基本フレームワークと、生成方法、ロード方法について説明します.くだらないことは言わないで、Coding:

  
  
  
  
  1. //////////hello.c 
  2. #include <linux/config.h> 
  3. #include <linux/module.h> 
  4.  
  5. #include <linux/kernel.h> /* printk()  */ 
  6.  
  7. static int init_module() 
  8.     printk("Hello,World!/n"); 
  9.     return 0; /*  , 0 */ 
  10.  
  11. static void cleanup_module() 
  12.     printk("Bye!/n"); 

コンパイルしましょう、もちろんgccです:gcc-c-o hello.o -I/usr/src/linux/include -D__KERNEL__ -DMODULE hello.c説明:-Iカーネルモジュールの作業環境のカーネルのヘッダファイルパスを指定します.指定しないと、通常kernelバージョンと一致しない警告が発生し、問題が発生することがあります.-Dマクロを定義し、カーネルモジュールは2つのマクロMacro:_を使用するKERNEL__ およびMODULE
モジュールファイルがあります.ロードしましょう.コマンドを使用します.insmod hello.o問題がなければ、今ロードに成功しました.カーネルモジュールがカーネルに入っているかどうかを確認し、コマンド:lsmodを使用して、出力リストにhelloモジュールがあるかどうかを確認します.では、ロード時に「Hello,World!」と出力するモジュールがあります.終了時に出力"Bye!「見ていません.コマンド:dmesgを使用して、出力メッセージに「Hello,World!「.今すぐ終了しましょう.このモジュールをカーネルから外して、コマンドを使用します:rmmod hello今モジュールhelloはカーネルから行って、コマンドdmesgで、「Bye!」を見ることができます.
はい、これもカーネルモジュールです.でももっと言えばstatic int init_module()はモジュールロード時にシステムが呼び出す関数で,Oh,man,構造関数のように見える.成功した場合は、0を返す必要があります.そうしないと、エラー番号です.
static void cleanup_module()は、モジュールのアンインストール時に呼び出される関数であり、構造関数の想像です.
カーネルプログラミングでは標準ライブラリは使用できません.カーネルモジュールではカーネル関数、すなわち/proc/ksymsで見つけられる関数しか使用できません.例えばprintf-->printk
OK、私たちはやはりMakefileに来て、毎回いつもの命令を避けるようにしましょう:#######################Makefile CC=gcc
KERNELSRC =/usr/src/linux-2.4////if different, change it.
CFLAGS  = -O2 -Wall -I$(KERNELSRC)/include -D__KERNEL__ -DMODULE
object    = test.osource    = test.c
$(object):  $(CC) $(CFLAGS) -c $(source)
.PHONY: cleanclean:  rm -f *.o
2.複雑な「Hello World」は簡単すぎて、モジュールファイルの生成方法、ロード方法、アンインストール方法について説明しました.モジュールのロードとアンインストール時の関数も分かりました.しかし、私たちはもっと知りたいです.複雑なものをください.
はい、ちょっと複雑なものをください.

  
  
  
  
  1. // TestModule.c 
  2. #define _NO__VERSION__ 
  3.  
  4. #include <linux/module.h> 
  5. #include <linux/version.h> 
  6. #include <linux/kernel.h> 
  7. #include <linux/types.h> 
  8. #include <linux/fs.h> 
  9. #include <linux/mm.h> 
  10. #include <linux/errno.h> 
  11. #include <asm/segment.h> 
  12. #include <linux/sched.h> 
  13. #include <asm/uaccess.h> 
  14.  
  15. #define DATA_LENGTH 10 
  16. /* Module parameters */ 
  17.  
  18. MODULE_AUTHOR("sss <[email protected]>"); 
  19. MODULE_DESCRIPTION("test driver"); 
  20. MODULE_LICENSE("GPL"); 
  21.  
  22.  
  23. char kernel_version[]=UTS_RELEASE; 
  24.  
  25. unsigned int test_major=0;  //  
  26.  
  27. ssize_t read_test(struct file *file, char *buf, size_t count, loff_t *f_ops) 
  28.  int left,i,*p; 
  29.  int data[DATA_LENGTH]; 
  30.  p=data; 
  31.  for(i=0;i<10;i++) 
  32.  data[i]=61; // ”= “ 。 
  33.  
  34.  for(left=count;left>0;left--) 
  35.  { 
  36.   //   
  37.   __copy_to_user(buf,p,1); 
  38.   buf++; 
  39.   p++; 
  40.  } 
  41.  return 0; // must reture 0; 
  42.  
  43. ssize_t write_test(struct file *file, const char *buf, size_t count, loff_t *f_ops) 
  44.  return 0; // must reture 0; 
  45.  
  46. static int open_test(struct inode *inode, struct file *file) 
  47.  MOD_INC_USE_COUNT; 
  48.  return 0; // must reture 0; 
  49.  
  50. static int release_test(struct inode *inode, struct file *file) 
  51.  MOD_DEC_USE_COUNT; 
  52.  return 0; // must reture 0; 
  53.  
  54.  
  55. //  ,  linux/fs.h  
  56. struct file_operations test_fops ={ 
  57.  read: read_test, 
  58.  write: write_test, 
  59.  open: open_test, 
  60.  release:release_test 
  61. }; 
  62.  
  63.  
  64. /* insmod, call it */ 
  65. int init_module(void
  66.  int result; 
  67.  result=register_chrdev(0,"test",&test_fops); 
  68.  if(result<0) 
  69.  { 
  70.   /*printf("can't get major number");*/ 
  71.   printk(KERN_INFO "test:Can't get major number/n"); 
  72.   return result; 
  73.  } 
  74.  if(test_major==0) 
  75.   test_major=result; 
  76.  printk("test major:%d/r/n",result); 
  77.  return 0;//  
  78.  
  79. /* rmmod, call it */ 
  80. void cleanup_module(void
  81.  unregister_chrdev(test_major,"test");//  ,  

このカーネルには文字デバイスが登録されており、file_を介してoperations構造は、その様々な操作を指定します.
さあ、makeさん、カーネルファイルをコンパイルして生成します.またロードしましょう.コマンド:dmesgで、得られたプライマリ・デバイス番号を見てください.(私のシステムでは268)コマンド:lsmodでカーネルがモジュールをロードしているかどうかを確認します.
3.テストしてみましょう.テストしてみましょう.テストの前に、デバイスファイルが作成されているかどうかを確認します./devの下にtestデバイスファイルがあるかどうかを確認し、ない場合は手動で作成します.前に見たメインデバイス番号で、コマンド「mknod test c 268 0」で作成したデバイスファイルを使用して、私のテストプログラムを開始しましょう.

  
  
  
  
  1. // TestApp.c 
  2. #include "stdio.h" 
  3. #include "sys/stat.h" 
  4. #include "fcntl.h" 
  5.  
  6. int main() 
  7.  char buf[20]={0,}; 
  8.  int i=0; 
  9.  int p = open("/dev/test",O_RDWR); 
  10.  if (p == -1) 
  11.  { 
  12.   printf("Can't open /dec/test /r/n"); 
  13.   exit(0); 
  14.  } 
  15.  // 
  16.  printf("buf addr:%ui/r/n",buf); 
  17.  // 
  18.  read(p,buf,10); 
  19.  for (i=0;i<10;i++) 
  20.  { 
  21.   printf("%s/r/n",buf+i); 
  22.  } 
  23.  close(p); 
  24.  // 
  25.  return 1; 

Makefileをもう1つ書いて、makeは実行ファイルを得て、私たちのテストを開始します.見えましたか、カーネルから正しい結果が得られました.
4.ちょっとしたまとめここでは、簡単な文字ドライバを示し、プログラムを使用してテストしました.私たちの主な仕事はopen,read,write,ioctlを実現することですシステム呼び出しの処理.これらの関数ポインタはfileoperations構造に割り当てられている.もちろん、これらの関数には固定的な形式があります.それに従ってください.
もう1つは,カーネル2.4と2.6のカーネルに対する処理が大きく変化したことである.ここで言うのはすべて2.4版です.
もう一つはバージョンの問題で、『Linux Device Driver』に紹介されています.この本はカーネルを書く人はみな勉強しなければならないかもしれない.
5.駆動の違いは何ですか.うん、これは言いにくい.ドライバはカーネルモジュールであってもよいが、カーネルモジュールはドライバではない.したがって、ドライバはカーネルモジュールのサブセットです.これはカーネルモジュールの役割に依存します.カーネルモジュールは、主にカーネルを容易に追加し、カーネル空間で動作させるためです.ドライバは、カーネルモジュールであり、カーネルモジュールのプロパティがありますが、最も主要な目的は「ハードウェアを定義された内部プログラミングインタフェースに応答させ、デバイスの動作の詳細を完全に隠す」ことです.主にハードウェアの可用性の問題を解決します.一般的には、ハードウェアと直接関係します.
ソース:http://blog.csdn.net/firststp/archive/2005/06/15/395009.aspx