3

組み込みシステムのメモリにアクセスするプログラムを実装しようとしています。いくつかの制御レジスタにアクセスする必要があるため、ioctl が最適な方法だと思います。fops に ioctl を追加しました。

struct file_operations aes_fops = {
  read: aes_read,
  write: aes_write,
  unlocked_ioctl: aes_ioctl,
  open: aes_open,
  release: aes_release
};

そして、機能を設定しました:

int aes_ioctl(struct inode *inode,  
     struct file *file, 
     unsigned int ioctl_num,    
     unsigned long ioctl_param){

     printk(KERN_INFO "in ioctl\n");
....
}

しかし、私はこの機能の中に入っていません。これが私のユーザー空間コードです。私がこれを完全に間違っているかどうかを理解するのを手伝ってください。

int main(int argc, char* argv[]){
    int fd = fopen("/dev/aes", "r+");
    ioctl(fd, 0, 1);
    fclose(fd);
}

古いバージョンの Linux が変更された組み込みシステム用にコンパイルしているため、一部のコードは明らかに古いカーネル用です。

4

3 に答える 3

7

コードの問題は、使用しているリクエスト番号です - 0。カーネルには、内部使用のために予約されたリクエスト番号があります。カーネルはリクエスト番号を構造体と見なし、それをフィールドに分割して、適切なサブシステムを呼び出します。

Documentation/ioctl/ioctl-number.txt を参照してください (Linux 3.4.6 以降):

Code  Seq#(hex) Include File            Comments
========================================================
0x00    00-1F   linux/fs.h              conflict!
0x00    00-1F   scsi/scsi_ioctl.h       conflict!
0x00    00-1F   linux/fb.h              conflict!
0x00    00-1F   linux/wavefront.h       conflict!
0x02    all     linux/fd.h
0x03    all     linux/hdreg.h
...

現在の状況に応じて、新しい ioctls() を追加するためのカーネル ガイドラインに従う必要があります。

If you are adding new ioctl's to the kernel, you should use the _IO
macros defined in <linux/ioctl.h>:

    _IO    an ioctl with no parameters
    _IOW   an ioctl with write parameters (copy_from_user)
    _IOR   an ioctl with read parameters  (copy_to_user)
    _IOWR  an ioctl with both write and read parameters.

Documentation/ioctl/ioctl-decoding.txtこれらの数値がどのように構成されているかについての詳細は、カーネル独自のドキュメントを参照してください。

実際には、コード 1 を選択すると、 から0x100まで開始することを意味し0x1ff、問題はありません。

于 2012-08-21T04:10:27.323 に答える
3

構造の設定はaes_fops正しいですか?私はそれがそのように行われたのを見たことがありません。私が持っているすべてのコードは次のとおりです。

.unlocked_ioctl = aes_ioctl,

それよりも:

unlocked_ioctl: aes_ioctl,

構造内のコロン (セットアップにあるように) フィールドは、個々のフィールドを初期化するのではなく、私が知る限り (および定義中に)ビット フィールドに使用されます。

つまり、次のことを試してください。

struct file_operations aes_fops = {
    .read            = aes_read,
    .write           = aes_write,
    .unlocked_ioctl  = aes_ioctl,
    .open            = aes_open,
    .release         = aes_release
};

注: gcc は構造体フィールドの初期化のバリアントをかつて許可していたようですが、gcc 2.5 以降では廃止されています ( GCC のドキュメントから直接ここを参照してください)。これを行うには、適切な方法 (つまり、ISO 標準によって承認された方法) を使用する必要があります。

于 2012-08-21T03:19:29.797 に答える
2

返されたエラーを知らなければ、言うのは難しいです...私の最初は、ファイル記述子に対するアクセス許可です。私は以前に同様の問題を見たことがあります。まず、ioctlの戻り値を確認すると、失敗に関する詳細情報を取得できます。

#include <errno.h>
int main(int argc, char* argv[])
{
    long ret;     
    int fd = fopen("/dev/aes", "r+");
    ret = ioctl(fd, 0, 1);
    if (ret < 0)
        printf("ioctl failed. Return code: %d, meaning: %s\n", ret, strerror(errno));
    fclose(fd); 
} 

戻り値を確認してください。これは、検索するための何かを提供するのに役立ちます。なぜチェックするのですか?投稿の下部を参照してください... 次に、権限の問題であるかどうかを確認するには、次のコマンドを実行します。

ls -l /dev/aes

次のようなものが表示された場合:

crw------- 1 root root 10, 57 Aug 21 10:24 /dev/aes

次に、次を発行します。

sudo chmod 777 /dev/aes

そして、もう一度試してください。私はそれがあなたのために働くに違いない。(rootは私のバージョンのmodの所有者であるため、root権限で実行したことに注意してください)

権限がすでにOKの場合は、さらにいくつかの提案があります。

1)私にとって、fopen/fcloseの使用は奇妙です。あなたは本当にする必要があるだけです:

int fd = open("/dev/aes");
close(fd);

私のシステムでは、コードをそのままコンパイルすることすらできません。

2)IOCTLパラメータリストが古く、コンパイルするカーネルバージョンがわかりませんが、最近のカーネルは次の形式を使用しています。

long aes_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param){   

iノードの削除とリターンタイプの変更に注意してください。システムでコードを実行したときに、これらの変更を加えました。

頑張ってください!

注:「ioctlにアクセスしていない」ときにリターンを確認する必要があるのはなぜですか?例を挙げましょう:

//Kernel Code:
//assume include files, other fops, exit, miscdev struct, etc. are present

long hello_ioctl(struct file *file, unsigned long ioctl_num, unsigned long ioctl_param) {
    long ret = 0;
    printk("in ioctl");
    return ret;
}

static const struct file_operations hello_fops = {
    owner: THIS_MODULE,
    read: hello_read,
    unlocked_ioctl: hello_ioctl,
};

static int __init hello_init(void) {
    int ret;
    printk("hello!\n");
    ret = misc_register(&hello_dev); //assume it worked...
    return ret;
}

ユーザースペースコード:

//assume includes

void main() {
  int fd;
  long ret;
  fd = open("/dev/hello");
  if(fd) {
    c = ioctl(fd, 0, 1);
    if (c < 0)
      printf("error: %d, errno: %d, meaning: %s\n", c, errno, strerror(errno));
    close(fd);
  }
  return;
}

では、出力は何ですか?/ dev / helloのファイルパーミッションが悪いと仮定しましょう(つまり、ユーザースペースプログラムは/ dev / helloにアクセスできません)。

dmesg | テールショー:

[ 2388.051660] Hello!

したがって、ioctlに「参加」しなかったようです。プログラムからの出力は何ですか?

error: -1, errno: 9, meaning: Bad file descriptor

たくさんの便利な出力。明らかに、ioctl呼び出しは、私たちが望んでいたことではなく、何かを実行しました。権限を変更して再実行すると、新しいdmesgが表示されます。

[ 2388.051660] Hello!
[ 2625.025339] in ioctl
于 2012-08-21T14:45:19.607 に答える