bootmain.c void readsect(void *dst, uint offset)
トップページ
jupiteroak.hatenablog.com
bootmain.c
https://github.com/mit-pdos/xv6-public/blob/master/bootmain.c#L59
void readsect(void *dst, uint offset) { // Issue command. waitdisk(); outb(0x1F2, 1); // count = 1 outb(0x1F3, offset); outb(0x1F4, offset >> 8); outb(0x1F5, offset >> 16); outb(0x1F6, (offset >> 24) | 0xE0); outb(0x1F7, 0x20); // cmd 0x20 - read sectors // Read data. waitdisk(); insl(0x1F0, dst, SECTSIZE/4); }
readsect関数は、引数offsetが指定するハードディスク上のセクタから、引数dstを先頭アドレスとするメモリ領域へ、512バイトのデータをロードします。
引数 dst
ロード先となるメモリ領域の先頭アドレスです。
引数 offset
ロード元となるセクタを指定するセクタ番号(28bitLBAの値)です。
処理の内容
- ハードディスクが使用できる状態であることを確認する
- 読み込むデータサイズを1セクタに指定する
- 読み込み開始位置となるセクタ番号のbit7-0を設定する
- 読み込み開始位置となるセクタ番号のbit15-8を設定する
- 読み込み開始位置となるセクタ番号のbit23-16を設定する
- セクタ番号、ハードディスクドライブの選択、アドレッシングモードの選択を設定する
- ハードディスクドライブへ読み込みコマンドを発行する
- ハードディスクが使用できる状態であることを確認する
- ハードディスクのセクタから読み込んだデータ(512バイト)をロードする
ハードディスクが使用できる状態であることを確認する
waitdisk();
waitdisk関数を呼び出して、ハードディスクが使用できる状態であることを確認します。
ハードディスクが使用できる状態であれば、この関数から処理が戻ってきます。
読み込むデータサイズを1セクタに指定する
outb(0x1F2, 1);
out命令(ポート出力命令)でポートアドレス0x1F2を指定することにより、ATAホストコントローラが持つSector Count Registerへの書き込みを行なっています。Sector Count Registerは、読み込み・書き出しを行う際のデータサイズをセクタ単位で指定するために使用されるレジスタです。
設定値は1なので、readsect関数の処理において、読み込みを行うデータサイズは1セクタ(512バイト)となります。
読み込み開始位置となるセクタ番号のbit7-0を設定する
outb(0x1F3, offset);
out命令(ポート出力命令)でポートアドレス0x1F3を指定することにより、ATAホストコントローラが持つLBAlo Registerへの書き込みを行なっています
LBAlo Registerには、読み込み開始位置となるセクタを指定するセクタ番号offset(28bitLBA値)のうちbit7-0の値を設定します。
読み込み開始位置となるセクタ番号のbit15-8を設定する
outb(0x1F4, offset >> 8);
out命令(ポート出力命令)でポートアドレス0x1F4を指定することにより、ATAホストコントローラが持つLBAmid Registerへの書き込みを行なっています
LBAmid Registerには、読み込み開始位置となるセクタを指定するセクタ番号offset(28bitLBA)のうちbit15-8の値を設定します。
offsetの値を8bit右シフト演算により、セクタ番号offset(28bitLBA値)のbit15-8の値を取り出しています。
読み込み開始位置となるセクタ番号のbit23-16を設定する
outb(0x1F5, offset >> 16);
out命令(ポート出力命令)でポートアドレス0x1F5を指定することにより、ATAホストコントローラが持つLBAhi Registerへの書き込みを行なっています。
LBAhi Registerには、 読み込み開始位置となるセクタを指定するセクタ番号offset(28bitLBA)のうちbit23-16の値を設定します。
offsetの値を16bit右シフト演算により、セクタ番号offset(28bitLBA値)のbit23-16の値を取り出しています。
セクタ番号、ハードディスクドライブの選択、アドレッシングモードの選択を設定する
outb(0x1F6, (offset >> 24) | 0xE0);
out命令(ポート出力命令)でポートアドレス0x1F6を指定することにより、ATAホストコントローラが持つDrive / Head Registerへの書き込みを行なっています。
Drive / Head Registerは、読み込み・書き出しの開始位置となるセクタの指定、読み込み・書き出し対象となるハードディスクドライブの選択、アドレッシングモードの選択に使用されるレジスタです。
Drive / Head Registerのbit3-0には、読み込み開始位置となるセクタを指定するセクタ番号offset(28bitLBA)のうちbit27-24の値を設定します。
Drive / Head Registerのbit4には、マスタードライブを使用する場合は0、スレイブドライブを使用する場合は1を設定します。
Drive / Head Registerのbit5には、常に1を設定します。
Drive / Head Registerのbit6には、LBA アドレッシングモードを使用する場合は1を、CHSアドレッシングモードを使用する場合は0を設定します。
Drive / Head Registerのbit7には、常に1を設定します。
設定値は、(offset >> 24) | 0xE0 (offsetのbit27-24の値と0xE0(0b 1110 0000)の論理和)です。
よって、Drive / Head Registerのbit3-0にはoffsetのbit27-24の値が、bit4には0の値が(マスタードライブを選択)、bit6には1の値が(LBA アドレッシングモード)が設定されます。
ハードディスクドライブへ読み込みコマンドを発行する
outb(0x1F7, 0x20);
out命令(ポート出力命令)でポートアドレス0x1F7を指定することにより、ATAホストコントローラが持つCommand Registerへの書き込みを行なっています。
Command Registerは、ATAコマンドを送信するために使用されるレジスタです。
ハードディスクからの読み込み処理を行う際は、Command Registerに読み込みコマンド0x20(READ SECTORS command)を設定します。
ハードディスクが使用できる状態であることを確認する
waitdisk();
データの読み込みが完了して、ハードディスクが使用できる状態になっているか確認します。
ハードディスクが使用できる状態であれば、この関数から処理が戻ってきます。
ハードディスクのセクタから読み込んだデータ(512バイト)をロードする
insl(0x1F0, dst, SECTSIZE/4);
insl関数を呼び出して、offsetで指定したセクタのデータ512バイトを、アドレスdstから始まるメモリ領域にロードします。
insl関数内のinsl命令(ポート出力命令)でI/Oポートアドレス0x1F0を指定することにより、ATAホストコントローラが持つData Registerから、4バイトのデータを読み取ります。
セクタのデータ512バイトを読み取るには、insl関数内においてinsl命令を、512/4 = SECTSIZE/4 = 128回繰り返す必要があるので、第3引数にSECTSIZE/4を設定しています。