2012-03-13 5 views
2

キャラクタデバイス "/ dev/coffee_bean"に書き込むシンプルなキャラクタドライバを作成しています。読み込み時に "Hi There!"という文字列が表示されます。コンソールで私は "cat/dev/coffee_bean"経由でデバイスから読み込み、代わりにシステムがクラッシュしてリセットします。ベローが私のソースコードです。手伝ってくれてありがとう。シンプルなキャラクタドライバのクラッシュ

#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/fs.h> 
#include <linux/cdev.h> 
#include <linux/kdev_t.h> 
#include <linux/types.h> 
#include <linux/completion.h> 
#include <linux/slab.h> 
#include <asm/uaccess.h> 
#include <linux/semaphore.h> 
MODULE_LICENSE("Dual BSD/GPL"); 

#define DEVICE_NAME "coffee_grinds" 
#define COUNT 4 
#define FIRST_MINOR 0 
#define CONST_QUANTUM 4000 
#define CONST_QSET 4000 

int test; 

module_param(test, int, S_IRUGO); 

struct my_char_structure{ 
    struct cdev my_cdev; 
    struct semaphore sem; 
    unsigned int access_key; 
    unsigned long size; 
}; 

static dev_t dev_num; 

int dev_open(struct inode *in_node, struct file *filp){ 
    struct my_char_structure *my_dev; 

    my_dev = container_of(in_node->i_cdev, struct my_char_structure, my_cdev); 
    filp->private_data = my_dev; 
    return 0; 
} 

int dev_release(struct inode *inode, struct file *filp){ 
    return 0; 
} 

ssize_t dev_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp){ 
    struct my_char_structure *my_dev = filp->private_data; 
    ssize_t retval = -ENOMEM; /* value used in "goto out" statements */ 
    char *my_string; 
    int counting; 
    printk(KERN_ALERT "Write was accessed, Lol"); 
    if (down_interruptible(&my_dev->sem)) 
     return -ERESTARTSYS; 
    my_string = kmalloc(count,GFP_KERNEL); 
    counting = copy_from_user(my_string,buff,count); 
    printk(KERN_ALERT "You wrote %s",my_string); 
    kfree(my_string); 
    up(&my_dev->sem); 

    printk(KERN_ALERT "We wrote %d bytes",counting); 
     return retval; 
    // Here is some experimental code 
} 

    ssize_t dev_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ 
     struct my_char_structure *my_dev = filp->private_data; 
     ssize_t retval = 0; 
     char *my_string; 

     printk(KERN_ALERT "Read was accessed Lol"); 

     if (down_interruptible(&my_dev->sem)) 
      return -ERESTARTSYS; 
     my_string = "Hi there!"; 
     copy_to_user(buff,my_string,10); 
     up(&my_dev->sem); 
     return retval; 

    } 

struct file_operations fops = { 
    .owner = THIS_MODULE, 
    .read = dev_read, 
    .write = dev_write, 
    .open = dev_open, 
    .release= dev_release, 
}; 

int start_mod(void){ 
    //Because we are dealing with a fictitious device, I want 
    //the driver to create my two devices with arbitrarly 
    //assigned major numbers. 
    static struct my_char_structure Dev; 
    static struct my_char_structure *my_dev = &Dev; 
    int err; 

    alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME); 

    sema_init(&(my_dev->sem),1); 

    cdev_init(&(my_dev->my_cdev), &fops); 
    my_dev->my_cdev.owner = THIS_MODULE; 
    my_dev->my_cdev.ops = &fops;// fops is my file operations struct 

    err = cdev_add(&my_dev->my_cdev, dev_num, COUNT); 
    if(err) 
     printk(KERN_ALERT "There was an error %d.",err); 
    printk(KERN_ALERT " insmod to major number %d",MAJOR(dev_num)); 

    return 0; 
} 

void end_mod(void){ 

    unregister_chrdev_region(dev_num, COUNT); 

} 

module_init(start_mod); 
module_exit(end_mod); 

答えて

2

あなたが今投稿した完全なコードを見ると、クラッシュの明白な原因はありません。あなたがやっていることは、他のドライバーで行われます。

ちょうどいくつかの観察。

エラーチェックはほとんどありません。それはあなたを噛んでしまいます。なぜなら、次のことの成功した実行は、前提条件として前のことが成功したことに依存するからです。

また、読み込み関数がクラッシュすることなく呼び出されると、0を返してオフセットを移動しないため、何も生成されません。ほとんどのプログラムは、ファイルの終わりとしてゼロリターンを解釈します。

これ以外の場合に渡されるバッファサイズを守らなければ、ユーザースペースが壊れます。 catプログラムでは、read(fd, buf, 5);(ユーザー空間にコピーする10バイトよりも5が小さいことに注意してください)を実行していない可能性があります。

ちなみに、copy_to_usercopy_from_userは、エラーのためにもテストして、-EFAULTをユーザ空間に返して、呼び出し元のアプリケーションに悪い領域を渡したことを伝える機能です。

クラッシュをデバッグするには、2つの従来のアプローチがあります。 1つはprintkステートメントを追加することです。ブランチがなく、印刷がバッファされないコードブロックでは、1つのprintステートメントがクラッシュ前に出力を生成し、別のprintステートメントが出力を生成しない場合、クラッシュはそれらの間のどこかにあります。

他の手法は、マシンレジスタ、命令ポインタを囲むバイト、コールトレースなどのクラッシュダンプを解釈することです。クラッシュの情報があれば、通常、クラッシュがどこにあるのかを突き止めることができます。マシンコードとレジスタの値が分かれば、Cの変数とデータ構造が何をしているのか推測できます。

幸運。

+0

Kazさん、ありがとうございました。プログラムをデバッグしましたが、クラッシュは自分の文字列にメモリを割り当てた方法によるものです。デバイスはもはやクラッシュしませんが、代わりにcopy_to_user()関数からのセグメンテーション違反が発生します。私は渡されたカウント変数を使用していないので、私はその欠陥があると思う。私のコードを見る時間をとってくれたバンドルありがとう! –

+1

しかし、書き込みルーチンに割り当てがあります。あなたはそれが読んでクラッシュしていると言った。書き込みルーチンの主な問題は、 'kmalloc'はブロックがどれくらい返ってくるかに非常に制限があることです。物理的に連続したページ(貴重なリソース)を返します。しかし、「読み込み」の議論は非常に大きくなる可能性があります。私。一般に、ユーザ空間からの値を 'kmalloc'サイズ(それが何をしているのかを知っているルート特権サーバプログラム以外のもの)を使うことは良い考えではありません。たくさんのメモリがあってもヌルリターンの準備をしてください。 – Kaz

+0

さて、私は "Hi There"のような小さなものをプリントアウトし、バイトをkmallocに割り当ててクラッシュからそれを止めたいだけです。今私は完全に機能するドライバを書くことを実装するために探しているわけではありません。私はちょうど最初に働くように読むことを望みます。これは私の最初のドライバで、読み書きを実装したものです。私は2週間前に勉強を始めました。 –

3

dev_readに達する前に状況が悪くなる可能性があります。あなたのKERN_ALERTメッセージがコンソールに表示されましたか?

明らかに、モジュールが初期化され、文字デバイスが登録されていて、オープンルーチンのような他の関数があるので、あなたのソースコードにあるわけではありません。デバイスからの読み取りがマシンをクラッシュさせるだけなので、バグはdev_readにあると思いますか?

sizeof(my_string)sizeof(char *)で、4または8です。ポインタのサイズを取っています。 64ビットカーネルを使用している場合は、!がなくても最大でHi thereになります。 :)

e.e.e.配列とポインタの違いのように、Cの基礎のチュートリアルの恩恵を受ける可能性があることは明らかです。

+0

ああ、私はポインタのサイズを取る前に間違いを犯しました、私はそれを忘れていました。私はソースの残りの部分に追加します。 –

1

コードを見るだけではわかりません。自分でエラーをチェックすることができます。条件が満たされていない場所では、KERN_ERRを使ってエラーを出力することができます。また、OUT(戻り値-1)を追加することで、クラッシュする可能性を最小限に抑えることができます。また、書き込み機能のみを作成し、正常に動作しているかどうかを確認し、dev_read機能の作成を開始してください。

関連する問題