USB3.0ドライバ開発の道

1.3K Views

December 01, 20

スライド概要

MikanOS(x86-64パソコン用OS)のUSBホストコントローラドライバを開発するにあたり,遭遇した罠を集めました。

profile-image

サイボウズ・ラボ株式会社で教育向けのOSやCPU、コンパイラなどの研究開発をしています。

シェア

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

USB3.0ドライバ開発の道 USBホストコントローラドライバの難所紹介 2020/11/13 ラボ勉強会 @uchan_nos

2.

MikanOSのUSBドライバ開発の罠たち この資料はMikanOSのUSBホストコントローラドライバを開発す るにあたり,遭遇した罠ポイントを集めたもの  MikanOS: @uchan_nosが開発している教育用OS  ソースコード https://github.com/uchan-nos/mikanos/ 罠ポイントは思い付いた主なものを載せた  これがすべてではない みんなもレッツUSBドライバ開発!

3.

罠リスト QEMUのCRCRのバグ No Opコマンドがエラー 送信イベントが来ない USBデバイスの初期化エラー xHCを始動するとフリーズ 一部機種でデバイス不可視

4.

罠リスト QEMUのCRCRのバグ No Opコマンドがエラー 送信イベントが来ない USBデバイスの初期化エラー xHCを始動するとフリーズ 一部機種でデバイス不可視

5.

Command Ring xHCにコマンドを送るためのキュー CRCR Command Ring OSがpush,xHCがpop 要素はTRBという16バイトの構造体  TRB最終ワードのビット0がcycle bit OSは末尾にLink TRBを配置し,コマン ドリングを1周させる  周回するたびにcycle bitを反転 CRCRがcommand ringの先頭を指す xHCが消費者 TRB TRB 1 1 … OSが生産者 TRB Link TRB 1 0

6.

CRCR: Command Ring Control Register xHCI for USB Requirement Specificationより Command Ring PointerにCRの先頭アドレスを設定 CRR (Command Ring Running) はCR動作中に1になるはず 他のフィールドは0が読み出されることになっている  RCS: Reading this flag always returns ‘0’.  CS: Reading this bit shall always return ‘0’.  CA: Reading this bit always returns ‘0’.  Command Ring Pointer: Reading this field always returns ‘0’.

7.

CRCR.CRRで動作チェック Command ringにTRBをpushし,ドアベルレジスタに書き込む →xHCがcommand ringから取得開始する(CRR=1になる) 当時の僕「上手くコマンドが認識されないなあ… そうだ,CRCR.CRRをチェックしてみよう」 QEMUで実験 まったくCRR=1にならない

8.
[beta]
QEMUのバグ
https://github.com/qemu/qemu/blob/3c8c36c9087da957f580a9bb5ebf7814a753d1c6/hw/usb/hcd-xhci.c#L2867-L2872

static uint64_t xhci_oper_read(void *ptr, hwaddr reg, unsigned size) {
XHCIState *xhci = ptr;
uint32_t ret;
switch (reg) {
…
case 0x18: /* CRCR low */
ret = xhci->crcr_low & ~0xe;
break;
case 0x1c: /* CRCR high */
ret = xhci->crcr_high;
break;
…

~0xe = 1 1 1 0 0 0 1

QEMUではCRCR.CRRをマスクしてしまっている!
加えて,0になるべきフィールドをマスクしてない

9.

罠リスト QEMUのCRCRのバグ No Opコマンドがエラー 送信イベントが来ない USBデバイスの初期化エラー xHCを始動するとフリーズ 一部機種でデバイス不可視

10.

No Opコマンドがエラーになる No Opコマンド:Command ringの動作確認用コマンド このコマンドがうまく動く → Command ringが正しくセットアップされている No Opコマンドを送るとTRB Errorが返ってくる 仕様を読んでも辻褄が合わないぞ?

11.

QEMUにNo Opコマンドが無い QEMUにNo Opコマンドが実装されていないだけだった hikaliumさんがその後パッチ投稿  https://github.com/qemu/qemu/commit/dc2c037fd23ea3dcf2e13afda22c1c64ab56f96b

12.

罠リスト QEMUのCRCRのバグ No Opコマンドがエラー 送信イベントが来ない USBデバイスの初期化エラー xHCを始動するとフリーズ 一部機種でデバイス不可視

13.

USBデバイスとエンドポイント エンドポイント=通信チャネル USBデバイスは最大16個のEPを持つ  必ずEP0=Default Control Pipeを持つ  EP0を使ってその他のEPの構成情報を得る xHC側にTransfer Ringを用意し,EPと接続 xHC スロット スロット TR TR TR EPは4種類 転送種別 転送方向 転送の特徴 Control Bidirectional 各種ディスクリプタを読むなど Isochronous Out/In 時間当たりの転送量を保証 Bulk Out/In 記憶装置などの大容量転送 Interrupt Out/In 小容量の定期的な転送 EP EP EP USBデバイス

14.

Transfer Ring USBデバイスに対する送受信のキュー  構造はcommand ringと同じ  エンドポイント毎に1つのTR No Op TRBを送信しても送信完了イベ Endpoint Context xHCが消費者 Transfer Ring TRB TRB ントが返ってこない 1 1 … TRBのIOC (Interrupt on Completion) を1にしなければならないのだった OSが生産者 TRB Link TRB 1 0

15.

罠リスト QEMUのCRCRのバグ No Opコマンドがエラー 送信イベントが来ない USBデバイスの初期化エラー xHCを始動するとフリーズ 一部機種でデバイス不可視

16.

USBデバイスの初期化フロー 1. デバイス接続を検知(PORTSC.CCS=1) 2. ポートをリセット 3. スロットを割り当て(Enable Slotコマンド)  スロット:xHCが利用するメモリ上の構造体 4. アドレスを割り当て(Address Deviceコマンド)  アドレス幅は7ビット  0~127 Address Deviceコマンド:デバイスにアドレスを割り当てる どんな設定をしてもUSB Transaction Errorになる…

17.

Address Deviceコマンドのエラー原因 ポートリセット後,デバイスはデフォルトアドレス0を持つ 同一アドレスを持つ複数のデバイスが存在するとダメ 1. 複数のデバイスを接続して並行に初期化しようとする  初期化が終わらないとデバイス種別を判定できないため, USBキーボードに限定するとしても全デバイスの初期化が必要 2. アドレス0を持つデバイスが複数発生する 3. Address Deviceコマンドがエラー ポートリセット~Address Deviceコマンドまでは 直列に実行する必要がある!

18.

罠リスト QEMUのCRCRのバグ No Opコマンドがエラー 送信イベントが来ない USBデバイスの初期化エラー xHCを始動するとフリーズ 一部機種でデバイス不可視

19.

xHCを始動させるとシステムフリーズ 1. xHCをリセット 2. メモリ構造を生成し初期化 3. xHCのレジスタを設定  メモリ構造のアドレスを設定したり 4. xHCの動作を開始  USBCMDのRun/Stopビットに1を書く Run/Stopに1を書いた少し後に,システム全体がフリーズ 例外ハンドラで文字を書いている途中で止まる(上図)  シャットダウンではなく,止まる  forループの途中なのでプログラムのミスは疑いにくい (同じロジックを繰り返し実行している)

20.

HC BIOS Owned Semaphore システムがフリーズする=バスロック系? プログラム外に原因がありそう。BIOS? 仕様書をふと眺めているとUSB Legacy Support Capabilityに HC BIOS Owned Semaphoreなるビットを発見  “The BIOS sets this bit to establish ownership of the xHC.”  調べてみると,このビットが1になっていた 隣にHC OS Owned Semaphoreというビットもある  “System software sets this bit to request ownership of the xHC.” これらを適切に設定したらフリーズしなくなった!

21.

罠リスト QEMUのCRCRのバグ No Opコマンドがエラー 送信イベントが来ない USBデバイスの初期化エラー xHCを始動するとフリーズ 一部機種でデバイス不可視

22.

一部の機種でUSBデバイスが検出されない osdev-jpメンバーからUSBマウス,キーボードが使えない報告  報告があった機種の1つはAcer Aspire E1-572-A54D  発売日は2013年6月  CPU: i5-4200U (Haswell) 搭載されているxHCのデバイスコードは0x9c31  #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 https://github.com/torvalds/linux/blob/3650b228f83adda7e5ee532e2b90429c03f7b9ec/drivers/usb/host/xhci-pci.c#L37  Lynx Point-LPはUSB3.0が普及し始めた頃のチップセット Linuxにusb_enable_intel_xhci_ports()という関数がある  Intel製チップセットの場合だけ呼ばれる  USB3_PSSENやXUSB2PRという謎のレジスタへ書き込み

23.

USB3_PSSENとXUSB2PR Intel 9あたりの時代のチップセットに載ってるレジスタ  USB3_PSSEN: USB 3.0 Port SuperSpeed Enable Register  XUSB2PR: xHC USB 2.0 Port Routing Register USB3_PSSENのビットに1を書くと,SuperSpeedが有効に XUSB2PRのビットに1を書くと,EHC→xHCに制御権が移動 EHCIにしか対応しないOSに配慮した過渡期の仕様 USBポート群 XUSB2PR EHC xHC

24.

xHCI仕様書には載っていない xHCI仕様書に”5.2 PCI Configuration Registers (USB)”という節が 一応は存在する でもUSB3_PSSEN/XUSB2PRに関する記述は無い チップセット固有の,しかも過渡期の仕様だから? 2つのレジスタをLinuxと同様に設定したらうまく動いた! PCIコンフィグレー ション空間 BAR USB3_PSSEN XUSB2PR xHCI仕様の範疇 xHCレジスタ 空間 メモリ上の データ構造群