4

OK、これは私には本当に奇妙です。シミュレートされたCANバスドライバーがあります。これはLinuxカーネルモジュールです。次に、ファイル記述子を開いてメッセージを送信することでドライバーにアクセスするテストアプリケーションをユーザースペースで実行していioctl()ます。

現在、CANバスドライバーは、x86プラットフォームで実行するために採用しているものです(組み込みのColdfireシステムで実行されていました)。組み込みシステムでは、メモリI / O領域にアクセスできるようにするためにrequest_mem_region()/を使用する必要がありました。これを行う必要はありませんが、できるだけ多くのコードを共通に保ちたいと思います。ioremap()

ここにいくつかの有用な定義があります:

#define MCF_MBAR    0x10000000

extern unsigned int Base[];
extern unsigned int can_range[];

  //This is the CAN registers on coldfire, just unused on my x86 desktop
Base[minor] = (MCF_MBAR + 0x1c0000); 
can_range[minor] = 0x180;

次に、初期化中にこれを実行していました。

if(NULL == request_mem_region(Base[minor], can_range[minor], "CAN-IO")) {
    return -EBUSY;
}

can_base[minor] = ioremap(Base[minor], can_range[minor]);

これを正しく理解していれば...ここで行っているのは、割り当てられていないメモリアドレスの範囲の予約を要求し、成功した場合は、それらにアクセスできるようにすることだけです。

現在マップされているアドレスを次の方法で確認しましたcat /proc/iomem

00000000-0000ffff : reserved
00010000-0009fbff : System RAM
0009fc00-0009ffff : reserved
000a0000-000bffff : Video RAM area
000c0000-000c8fff : Video ROM
000e2000-000e6fff : Adapter ROM
000f0000-000fffff : reserved
000f0000-000fffff : System ROM
00100000-1ffeffff : System RAM
00200000-0071038b : Kernel code
0071038c-00ad8a7f : Kernel data
00b58000-00c52fff : Kernel bss
                          <--  101C0000-101C0180 : This is where I'd be mapping memory
1fff0000-1fffffff : ACPI Tables
e0000000-e0ffffff : 0000:00:02.0
e0000000-e0bfffff : vesafb
f0000000-f001ffff : 0000:00:03.0
f0000000-f001ffff : e1000
f0400000-f07fffff : 0000:00:04.0
f0400000-f07fffff : vboxguest
f0800000-f0803fff : 0000:00:04.0
f0804000-f0804fff : 0000:00:06.0
f0804000-f0804fff : ohci_hcd
f0806000-f0807fff : 0000:00:0d.0
f0806000-f0807fff : ahci
fee00000-fee00fff : Local APIC
fffc0000-ffffffff : reserved

その記憶を使っているものは何もないように見えるので、ここでは大丈夫だと思います。カーネルモジュールを正常にロードし、テストプログラムを実行すると失敗し、再度実行すると機能します。新しくロードされた後に最初に実行するたびに、失敗します... 2回目、3回目、n回目、それは機能します:

mike@linux-4puc:~> ./a.out 
  Starting driver test
  Error 'Device or resource busy' opening CAN device
mike@linux-4puc:~> ./a.out 
  Starting driver test
  We opened successfully

これが私の非常に単純なユーザースペースプログラムの一部です:

int fd;
char* dev = "/dev/can0";

printf("Starting driver test\n");

if ((fd = open(dev, O_RDWR)) < 0) {
    printf("Error '%s' opening CAN device", strerror(errno));
    close(fd);
    return -1;
}

なぜこれが起こっているのかについてのアイデアはありますか?ドライバーからコードを削除すると、request_mem_region()すべてが機能するので、私は愚かなことをしているだけだと思います...しかし、なぜそれが失敗するのですか?

4

1 に答える 1

2

これがあなたにとってまったくうまくいくことに少し驚いています。には、システムRAMの物理アドレス範囲内の値request_mem_region()が渡されます。(初期の)エラーリターンは、カーネルがこの物理メモリ領域をメモリプールにすでにインストールしていることを示していると思います。ドライバーがエラー終了したとき(またはモジュールがアンロードしたとき)、適切なクリーンアップと呼び出しを実行しようとしますか?これにより、次の回避策が成功する可能性がありますか?0x101C00000x001000000x1ffeffffrelease_mem_region()request_mem_region()

通常、ドライバーはその物理アドレス範囲を「使用可能」にする(つまり、仮想アドレスにマッピングするための物理アドレス範囲を宣言する)過程にあるため、使用されていない(つまり、現在カーネルにrequest_mem_region()不明アドレス範囲を指定します。スペース)。

代わりに次のようなものを使用するとどうなりますか

#define MCF_MBAR    0x90000000

その物理アドレス空間が実際に使用されていないと仮定しますか?

release_mem_region()ところで、ドライバーが最初の使用後に呼び出している場合、ドライバーにはバグがあります。ドライバーは、実際に取得したリソースのみを解放する必要があります。エラーが返された場合request_mem_region()、メモリリソースは取得されませんでした。したがって、呼び出す理由はありませんrelease_mem_region()(そして、ドライバーは常に割り当てエラーを受け取ります_init())。正しく動作しているLinuxデバイスドライバーを調べると、ルーチンでgoto割り当てられたリソースを巻き戻し、コードで割り当てを解除する前に有効性チェックを行うための複雑なエラー終了スキーム(ステートメントを使用)が見つかる可能性があります。_init()_exit()

于 2012-09-24T02:00:07.850 に答える