コードをきれいにしましょう:Linuxで64ビットハードウェアレジスタを操作する

多くの場合、ドライバーを作成するプログラマーは、64ビット形式のデータを交換する際にいくつかの困難を経験します。 いくつかの状況を見てみましょう。

参加する代わりに


実際、64ビットレジスタの操作画面では、いくつかの問題が隠されています。

まず 、64ビットレジスタを使用する機器のメンテナンスは、64ビットコアと32ビットコアの両方で利用できる必要があります。

第二に 、すべての64ビットレジスタが1つのコマンドで記述できるわけではありません。これは、ハードウェアでの実装の微妙な違いによるものです。

第三に 、確立された標準とプロトコルに関連して、64ビットの数値を2つの32ビットの数値と比較する必要がある場合があります。

自転車の発明を回避し、コードをより簡潔に、より簡潔に、より美しくする方法を見てみましょう。

64ビットデータ交換


もちろん、多くの人がwritel()readl()など、機器のレジスタを読み書きするためのよく知られたコマンドにreadl()

これらは、従来のバイト、ダブルバイト、および4バイトのレジスタ操作をカバーしています。 一度に8バイトを読み書きする必要がある場合はどうしますか?

一部の64ビットアーキテクチャでは、 writeq()およびreadq()コマンドがreadq()ます。

従来、32ビットプラットフォームと64ビットプラットフォームを採用するプログラマーは、コードで似たようなものを作成していました。
 static inline void writeq(u64 val, void __iomem *addr) { writel(val, addr); writel(val >> 32, addr + 4); } 

そしてそれに応じて読書。
 static inline u64 readq(void __iomem *addr) { u32 low, high; low = readl(addr); high = readl(addr + 4); return low + ((u64)high << 32); } 


そして、そのようなコピーが数百ではないとしても数十あると想像してください。 自転車の発明を避けるために、特別なファイルには/ linux / io-64-nonatomic-hi-lo.hが 含まれ、/ linux / io-64-nonatomic-lo-hi.hがカーネルに追加されました

これらのファイルの機能は何ですか:
  1. 特定の関数は、アトミックにではなく呼び出しを実行します。
  2. 上記に関連して、カーネルには2つのファイルがあります。ジュニア-シニアとその逆-シニア-ジュニアを記録するためです。
  3. どちらのファイルも、「最初に起きた人はスニーカーだ」という原則に従って、 writeq()readq()宣言します。 最初に、それらがすでに定義されているかどうかがチェックされますか? そうでない場合は、再定義します。 したがって、ヘッダーファイルが含まれる順序が重要です。
  4. 式8 = 4 + 4によって明らかに行われる処理。

したがって、4 + 4という形式の呼び出しのみを理解する機器がある場合は、 lo_hi_writeq()およびlo_hi_readq()またはhi_lo_writeq()およびhi_lo_readq()ます。 理想的なケースでは、 writeq()およびreadq()です。

64ビット数の比較


場合によっては、オプション8の64ビット数とオプション4 + 4の数を比較する必要があります。

額に直接ソリューション:
 u32 hi = Y, lo = Z; u64 value = X, tmp; tmp = (Y << 32) | X; return value == tmp; 

さて、あなたは32ビットアーキテクチャ上にどれだけのコードがあるのか​​理解しています。

このケースは、次の2つの比較に分けることができます。
 return (value >> 32) == hi && (u32)value == lo; 

簡単に思えますが、1つ問題があります。 カーネルには、特定のプラットフォームに直接依存するタイプ、つまりphys_addr_tresource_size_tdma_addr_tなどがあります。

このコードを書いたらどうなると思いますか:
 u32 hi = Y, lo = Z; resource_size_t value = X; return (value >> 32) == hi && (u32)value == lo; 

もちろん、64ビットアーキテクチャでは、すべて問題ありません。 しかし、32ビット版では、コンパイラーはシフトvalue >> 32について文句を言います。

コンパイラが満足し、ユーザーがlower_32_bits()ないようにするために、次のマクロがカーネルに追加されました: lower_32_bits()および
upper_32_bits() 、それぞれ下位および上位4バイト。

その結果、比較は次のようになります。
 return upper_32_bits(value) == hi && lower_32_bits(value) == lo; 


これらの操作はアトミックではないことを忘れないでください!

Source: https://habr.com/ru/post/J271433/


All Articles