備忘録やめた

備忘録として使用していたけどやめた.このブログに載せてあるコードのライセンスは別途記載がない限りWTFPL OR NYSLです.

USBキーボードドライバを作成した

この記事は,自作OS Advent Calendar 2020 - Adventarの13日目の記事です.

USBキーボードドライバを実装しました.

主に読んだもの

www.intel.co.jp

xHCIの仕様書です.

booth.pm

USBキーボードドライバの作成手順が載っています.

www.usb.org

USB3.2の仕様書です.

forum.osdev.org

OSに関するフォーラムです.xHCIやUSBに関する質問は少ないですが,それでもいくつか存在します.

手順

以下では eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification May 2019 Revision 1.2 を単にxHCIの仕様書と呼称します.

xHCを探す

xHCはPCIバイスの一種です *1.xHCの検索方法は以下のページを参考にしてください.

wiki.osdev.org

PCI設定空間の内容を読み取る

BAR0(とBAR1)が,xHCIMMIO空間の基準アドレスとなります.

HCの所有権をBIOSからOSに移す

xHCIの仕様書の4.22.1に詳細があります.ただし,USBLEGSUPxECP + 00hに存在すると仕様書には書かれていますが,実際はこの位置に存在しないこともあります.USBLEGSUPxHCI Extended Capabilityというものの一つで,これはリンクリストの形態でメモリ上に存在します.USBLEGSUPxECP + 00hに存在せず,このリンクリストの途中に存在する場合がありますが,この場合にHCの所有権を移動させる必要があるかは不明です.

HCの初期化

xHCIの仕様書の4.2に手順が示されています.割り込みは任意と書かれていますが,割り込みを用いない場合でもイベントリングは必要です.

ポート,スロット,エンドポイントの初期化

xHCIの仕様書の4.3に手順が示されています.

キーボードからのキー入力の受信

これについては,紹介した「USB 3.0 ホストドライバ自作入門」の第6章に詳しく載っています.

注意するべき事柄

トランスファーリングは各エンドポイント毎に用意する

各エンドポイントは異なるトランスファーリングを扱うことになります.

物理アドレスも連続しているメモリが必要になる

「メモリ確保なんて仮想アドレスで連続していればいいだろ」と思っていた時期が僕にもありました.実際はそうではありません.ハードウェアはDMAによって物理メモリに対して直接値を読み書きします.場合によってはページ境界を跨ぐ場合も存在します.確保したメモリが物理メモリ上でも必ず連続するようなメモリアロケータを用意するべきです.

QEMUは始めから接続されているUSBデバイスのPort Status Change TRBを発行しない

通常のコンピュータでは,起動時に接続されているUSBデバイスに対するPort Status Change TRBが,HCが起動 (run) した後に発行されますが,QEMUは始めから接続されているデバイスに対するTRBを発行しません.HCを起動した後,各ポートの接続状況を確認する必要があります.

また,HCを起動した後にコマンドリングやイベントリングが正しく設定されているかを確認するには,コマンドリングにNoop TRBを発行すると良いです.このTRBはイベントリングにCommand Completion TRBを発行する以外,何も行ないません.間違えてトランスファーリングのNoop TRBを発行しないようにしてください.

ポート番号は1からはじまる

ポートのレジスタのオフセットは index - 1 となります.

便利なもの

QEMUデバッグ出力,トレーサ

詳細はこちらを確認してください.

uchan.hateblo.jp

DPRINTFとトレースをどちらも有効にしておくべきです.これらの有無によってバグ取りに掛ける時間が大幅に変わります.

QEMUソースコード

上記のデバッグ出力やトレーサとの合わせ技ですが,デバッグ出力やトレーサの出力をgrepを用いてソースコード内で検索すると,なぜそのメッセージが表示されたのか,そのメッセージはどのような意味を持つのかがすぐにわかります.これは非常に便利です.

作成物

github.com

kernel/src/device/pci/xhciに,xHCIやUSBを扱うコードがあります.

謝辞

現在,USBドライバを含む,多種多様なドライバの作成というテーマで,サイボウズ・ラボユースにおいて開発を行なっています.メンターの内田さんには,様々な質問に答えていただいたり,バグ取りを手伝っていただいたりしています.本当にありがとうございます.

*1:Class = 0x0C, Sub = 0x03, Interface = 0x30