web-dev-qa-db-ja.com

デバイスドライバーを作成する際のLinuxでの__iomemの使用は何ですか?

___iomem_がioremap()の戻り値の型を格納するために使用されていることを確認しましたが、ARMアーキテクチャで_u32_を使用しました。うまく機能します。

では、ここで___iomem_はどのような違いをもたらしますか?そして、どのような状況でそれを正確に使用する必要がありますか?

19
Virendra Kumar

多くの型キャストは「うまく機能する」だけです。ただし、これはそれほど厳密ではありません。 _u32_を_u32 *_にキャストして逆参照することを妨げるものは何もありませんが、これはカーネルAPIに準拠しておらず、エラーが発生しやすくなっています。

___iomem_は、カーネルで発生する可能性のあるコーディング障害を見つけるために使用されるツールである Sparse によって使用されるCookieです。スパースを有効にしてカーネルコードをコンパイルしない場合、___iomem_はとにかく無視されます。

Sparseを使用するには、最初にインストールしてから、make呼び出しに_C=1_を追加します。たとえば、モジュールを構築するときは、次を使用します。

_make -C $KPATH M=$PWD C=1 modules
_

___iomem_は次のように定義されます。

_# define __iomem        __attribute__((noderef, address_space(2)))
_

すべてのI/Oアクセスに___iomem_のようなCookieを追加(および要求)することは、より厳密にプログラミングエラーを回避する方法です。通常は仮想メモリを使用しているため、絶対アドレスを使用してI/Oメモリ領域との間で読み取り/書き込みを行う必要はありません。したがって、

_void __iomem *ioremap(phys_addr_t offset, unsigned long size);
_

通常、I/O物理アドレスoffsetの仮想アドレスを、バイト単位で指定された長さsizeで取得するために呼び出されます。 ioremap()は___iomem_ cookieを含むポインターを返すため、これはmay nowreadl()/writel()などのインライン関数で使用されます(ただし___iomem_アドレスを受け入れるより明示的なマクロioread32()/iowrite32()などを使用することが望ましいようになりました。

また、noderef属性は、___iomem_ポインターを逆参照しないようにするためにSparseによって使用されます。逆参照は、I/Oが実際にメモリマップされている一部のアーキテクチャで機能するはずですが、他のアーキテクチャはI/Oにアクセスするために特別な命令を使用し、この場合、逆参照は機能しません。

例を見てみましょう:

_void *io = ioremap(42, 4);
_

スパースは幸せではありません:

_warning: incorrect type in initializer (different address spaces)
    expected void *io
    got void [noderef] <asn:2>*
_

または:

_u32 __iomem* io = ioremap(42, 4);
pr_info("%x\n", *io);
_

スパースも幸せではありません:

_warning: dereference of noderef expression
_

最後の例では、ioremap()がその値を___iomem_変数に返すため、最初の行は正しいです。しかし、その後、私たちはそれを尊重します、そして私たちはそうするべきではありません。

これはスパースを幸せにします:

_void __iomem* io = ioremap(42, 4);
pr_info("%x\n", ioread32(io));
_

結論:必要な場合は常に___iomem_を(戻り値の型またはパラメーター型として)使用し、スパースを使用して確実に使用してください。また、___iomem_ポインターを逆参照しないでください。

編集:___iomem_の開始とそれを使用する関数についてのすばらしい LWN記事 です。

39
eepp