VxWorks653でAHCIを実行した経験

はじめに



さまざまな航空機器用のアプリケーションとドライバーを開発しています。 Aviationは、VxWorks653、PikeOS、LynkOSなど、より厳しい信頼性要件(ARINC 653)を備えたOSを使用しています。 アビオニクス用のアプリケーションを開発する際、ATA経由で接続されたソリッドステートドライブ上のデータへのアクセスが遅いという問題がありました。 これは、低速のATAソフトウェアインターフェイスを使用したためです。 AHCIドライバーを実装することでこの問題を解決しました。



この記事では、AHCIの作業について簡単に説明します。





AHCIコントローラを備えたデバイスアーキテクチャ。





AHCIの説明



Advanced Host Controller Interface(AHCI)-シリアルATAプロトコルを使用してストレージデバイスを接続するために使用されるメカニズム。



AHCIモードでデバイスを操作するには、次の手順を実行します。





AHCIレジスタとのすべての対話は、PCIe BAR5ウィンドウを介して行われます。 ABAR(AHCIベースアドレス領域)と呼ばれます。





アドレス空間の割り当てABAR。



AHCIコントローラーを構成する



プロトコル仕様は、 www.intel.com / content / www / us / en / io / serial-ata / ahci.htmlで公開されています。

AHCIの現在の最新バージョンは1.3.1です



最初に、PCIeバス上のすべての大容量メモリコントローラーを探します。 クラスID 0x01(マスストレージデバイス)およびサブクラスID 0x06(シリアルATA)のデバイスに関心があります。



コントローラーの構成は、次のアクションで構成されています。





AHCI-ABARレジスタを介して、限られた数のアクションを実行できます-AHCIの動作の設定、バージョンの読み取りなど。 これらのレジスタを介してデータキャリアの設定およびデータ自体にアクセスすることはできません。



アクセスするには、コマンドの特別なリストが使用されます。 コマンドのリストは、計算機のRAMに保存されます。 これらのリストの物理アドレスは、AHCIコントローラーに書き込まれます。 AHCIコントローラ自体は、DMAを介して計算機のRAMにアクセスし、コマンドのリストを読み取り、実行し、RAMからメモリブロックを読み書きします。 メモリ割り当てアーキテクチャを次の図に示します。 OSの初期化中に、メモリに必要なアレイを割り当て、物理アドレスを計算し、初期化段階で、対応するABARレジスタにアドレスを記録する必要があります。





ABARのメモリ割り当て-HBA



充填管理構造



ABARの各ポートについて、2つの構造(コマンドのリストとFIS)を指定する必要があります。



コマンドのリストは2つの部分で構成されています-コマンドのリストの1つのヘッダー。

ヘッダーは、コマンドのリストのサイズ、FISのサイズ、およびコマンドのリストの物理アドレスへのリンクを示します。

コマンドのリストには、FISで指定されたコマンドの実行時に必要となるバッファーのアドレスとサイズが含まれています。





AHCIポート構造



コマンドヘッダーの形成:

opts = (20 >> 2) | (sg_count << 16);

pp->cmd_slot->opts = cpu_to_le32(opts);

pp->cmd_slot->status = 0;

pp->cmd_slot->tbl_addr = cpu_to_le32(pp->cmd_tbl & 0xffffffff);

pp->cmd_slot->tbl_addr_hi = 0;







ここで、CFLフィールドにはダブルワードでFISサイズ値(定数20)が入力されています。 PRDTLフィールドには、4 MBの使用済みバッファーの数が入力されます。





コマンドリストのヘッダー形式



コマンドの表の形成:

  #define MAX_DATA_BYTE_COUNT (4*1024*1024) sg_count = ((buf_len - 1) / MAX_DATA_BYTE_COUNT) + 1; for (i = 0; i < sg_count; i++) { ahci_sg->addr = cpu_to_le32((uint32_t) buf + i * MAX_DATA_BYTE_COUNT); ahci_sg->addr_hi = 0; ahci_sg->flags_size = cpu_to_le32(0x3fffff & (buf_len < MAX_DATA_BYTE_COUNT ? (buf_len - 1) : (MAX_DATA_BYTE_COUNT - 1))); ahci_sg++; buf_len -= MAX_DATA_BYTE_COUNT; } return sg_count;
      
      





この関数は、どのバッファがデータ転送に参加するかを示す構造を埋めます。 レコード内のバッファのサイズは4 MBを超えることはできないため、関数は、サイズが4 MBを超える場合、バッファをいくつかに分割します。





コマンドテーブルの形式



AHCIのドキュメントにはFISの説明はありません。 SATAの説明を参照してください。 FIS構造は、オペレーションコード(読み取りID、読み取り、書き込みなど)とパラメーター(オフセット、サイズなど)を記述します。





FIS構造



ドライブの識別情報を読み取ると、次のFISが生成されます。

  memset(fis, 0, 20); fis[0] = 0x27; fis[1] = 1 << 7; fis[2] = ATA_CMD_IDENT;
      
      







データブロックのレコードを要求すると、FISが生成されます。

  memset(fis, 0, 20); /* Construct the FIS */ fis[0] = 0x27; /* Host to device FIS. */ fis[1] = 1 << 7; /* Command FIS. */ fis[2] = ATA_CMD_WR_DMA; /* Command byte. */ /* LBA address, only support LBA28 in this driver */ fis[4] = ((unsigned char) (start))&0xff; fis[5] = ((unsigned char) (start>>8))&0xff; fis[6] = ((unsigned char) (start>>16))&0xff; fis[7] = (((unsigned char) (start>>24)) & 0x0f) | 0xe0; /* Sector Count */ fis[12] = (unsigned char) blocks & 0xff; fis[13] = ((unsigned char) (blocks>>8))&0xff;
      
      







データブロックの読み取りを要求すると、FISが生成されます。

  memset(fis, 0, 20); /* Construct the FIS */ fis[0] = 0x27; /* Host to device FIS. */ fis[1] = 1 << 7; /* Command FIS. */ fis[2] = ATA_CMD_RD_DMA; /* Command byte. */ /* LBA address, only support LBA28 in this driver */ fis[4] = ((unsigned char) (start))&0xff; fis[5] = ((unsigned char) (start>>8))&0xff; fis[6] = ((unsigned char) (start>>16))&0xff; fis[7] = (((unsigned char) (start>>24)) & 0x0f) | 0xe0; /* Sector Count */ fis[12] = (unsigned char) count & 0xff; fis[13] = ((unsigned char) (count >> 8))&0xff;
      
      







起動して実行



コントローラがABARを介して構成された後、メモリ内のすべてのリストが準備され、PORT_CMD_ISSUEに0x1を書き込んで、フラグがリセットされるまで待機します。 あなたはループで(私はちょうどそれをやった)または割り込みによって待つことができます。



PORT_CMD_ISSUEに書き込んだ直後に、コントローラーはDMAを介してプロセッサーRAMにアクセスし、期待されたアクションを実行します。



したがって、読み取り操作の結果として、コマンドのリストで指定されたバッファー内のメディアからデータを受け取ります。



おわりに



プロジェクトでAHCIを使用する前の読み取り/書き込み速度は次のとおりでした:〜100kb / s

プロジェクトでAHCIを使用した後、読み取り/書き込み速度は30/10 Mb / sになりました



All Articles