ide.c void ideintr(void)
トップページ
jupiteroak.hatenablog.com
ide.c
https://github.com/mit-pdos/xv6-public/blob/master/ide.c#L103
void ideintr(void) { struct buf *b; // First queued buffer is the active request. acquire(&idelock); if((b = idequeue) == 0){ release(&idelock); return; } idequeue = b->qnext; // Read data if needed. if(!(b->flags & B_DIRTY) && idewait(1) >= 0) insl(0x1f0, b->data, BSIZE/4); // Wake process waiting for this buf. b->flags |= B_VALID; b->flags &= ~B_DIRTY; wakeup(b); // Start disk on next buf in queue. if(idequeue != 0) idestart(idequeue); release(&idelock); }
ideintr関数は、ハードディスクからバッファへデータを保存する処理や、ハードディスクへの書き出しが終わったバッファの状態を変更する処理を行います。
処理の内容
- クリティカルセクションの入口を定める
- IDEキューの先頭バッファのアドレスを保存する
- IDEキューの先頭を更新する
- 読み込みコマンドを発行後の場合はハードディスクのセクタから読み込んだデータ(512バイト)をバッファに保存する
- バッファの状態を示すフラグを変更する
- ハードディスクの読み込み・書き出し処理が完了するまで休止状態だったプロセスを実行可能状態にする
- IDEキュー内にバッファがある場合はidestart関数を呼び出す
- クリティカルセクションの出口を定める
クリティカルセクションの入口を定める
acquire(&idelock);
ハードディスクの読み込み処理・書き出し処理を排他制御するために、acquire関数を呼び出してロックを取得し、クリティカルセクションの入口とします。
IDEキューの先頭バッファのアドレスを保存する
if((b = idequeue) == 0){ release(&idelock); return; }
IDEキュー(ハードディスクからの読み込み処理やハードディスクへの書き出し処理がなされるのを保留してあるバッファのリスト)の先頭バッファ(buf構造体変数)を指定するアドレスを、buf構造体へのポインタbに保存します。(b = idequeue) == 0 が真となる場合→IDEキューにバッファがない場合は、release関数を呼び出して取得していたロックを解放し、リターンします。
読み込みコマンドを発行後の場合はハードディスクのセクタから読み込んだデータ(512バイト)をバッファに保存する
if(!(b->flags & B_DIRTY) && idewait(1) >= 0) insl(0x1f0, b->data, BSIZE/4);
buf構造体へのポインタbに保存しておいた、IDEキューの以前の先頭バッファについての処理です。
idestart関数内でバッファbについての読み込みコマンド、または、書き出しコマンドがハードディスクドライブへ発行され、ハードディスクドライブ側の読み込み処理、または、書き出し処理が完了し、割り込みが発生した後に、ideintr関数が呼び出され、今に至っています。
!(b->flags & B_DIRTY) && idewait(1) >= 0 が真となる場合→バッファbのflagsメンバbit2の値が0、かつ、idewait関数の戻り値が0の場合→バッファbが保存しているデータをハードディスクへ書き出す必要がない状態、かつ、ハードディスクドライブ側でエラーが検出されていない場合は、insl関数を呼び出します。
insl命令(ポート出力命令)でI/Oポートアドレス0x1F0を指定することにより、ATAホストコントローラが持つData Registerから、バッファb(先頭アドレスがb->data・サイズがBSIZE/4×4のメモリ領域)にデータを保存します。
バッファの状態を示すフラグを変更する
b->flags |= B_VALID; b->flags &= ~B_DIRTY;
この時点で、ハードディスクからバッファbへデータの読み込みが完了しているので、バッファbのflagsメンバの値を変更します。
B_VALID(#define B_VALID 0x2)をビット和代入することで、flagsメンバのbit1のみを1に設定します。バッファbのflagsメンバのbit1が1の時、バッファbがハードディスクから読み込んだデータを保存している状態であることを示しています。
また、ideintr関数が呼び出された時点で、バッファbからハードディスクへデータの書き出しが完了しているので、バッファbのflagsメンバの値を変更します。
~B_DIRTY(#define B_DIRTY 0x4)をビット積代入することで、flagsメンバのbit2のみを0に設定します。バッファbのflagsメンバのbit2が0の時、バッファbが保存しているデータをハードディスクへ書き出す必要がない状態であることを示しています。
ハードディスクの読み込み・書き出し処理が完了するまで休止状態だったプロセスを実行可能状態にする
wakeup(b);
wakeup関数を呼び出して、ハードディスクの読み込み処理・書き出し処理が完了するまでsleep状態(p->state = SLEEPING;)になっていたプロセス(iderw関数内でsleep関数を呼び出したプロセス)を、実行可能状態(p->state = RUNNABLE)にします。