Operating Systems Development Series
Bootloaders 4
by Mike, 2008, 2009

はじめに

ようこそ!前回のチュートリアルでは、セクタをロードして実行する方法について説明しました。また、アセンブリ言語のRingsとBIOS Parameter Block (BPB)を詳しく見てきました。

このチュートリアルでは、FAT12 ファイルシステムを解析し、セカンドステージローダを名前でロードするために学んだことをすべて使用するつもりです。

このチュートリアルには多くのコードが含まれています。また、このチュートリアルには数学も含まれています。

準備はいいですか?

cli と hlt

なぜ私がデモプログラムの最後に "cli "と "hlt "という命令を使うのか、不思議に思うかもしれません。それは、とても簡単なことです。もし、何らかの方法でプログラムを停止させる方法がなければ、CPUはあなたのプログラムを超えてランダムな命令を実行するだけです。最終的にはTriple Faultになります。

割り込みをクリアする(cli)理由は、割り込みが実行されるからです(したがって、システムはハルトされません)。これでは問題が発生する可能性があります。つまり、hlt命令があるだけで(cliなしで)CPUがTriple Faultになる可能性があるのです。

このため、私はいつもすべてのデモをcliとhltで終わらせています。

ファイルシステム - 理論

そろそろファイルシステムの話をしようかな :)

ファイルシステムとは、仕様書以外の何物でもありません。ディスク上に「ファイル」という概念を作り出す手助けをします。

ファイルとは、何かを表現するデータの集まりです。このデータは、私たちが望むものであれば何でも構いません。 それはすべて、データをどのように解釈するかによります。

ご存知のように、1セクタは512バイトの大きさです。ファイルが512バイトを超えると、セクタを増やさなければなりません。すべてのファイルが均等に512バイトであるわけではないので、残りのバイト(ファイルが使用しないバイト)を埋める必要があります。 ブートローダにしたことと同じようなものです。

ファイルが複数のセクタにまたがっている場合、FATファイルシステムではこれらのセクタをクラスタと呼びます。 たとえば、カーネルは多くのセクタにまたがる可能性があります。カーネルをロードするには、それがあるクラスタ(セクタ)をロードする必要があります。

ファイルが異なるクラスタの異なるセクタにまたがっている場合 (隣接していない場合)、そのファイルは断片化されていると言われます。ファイルの異なる部分を収集する必要があります。

ファイルシステムには多くの種類があります。FAT12、FAT16、FAT32、NTFS、ext(Linux)、HFS(古いMACで使用)など広く使われているものもあれば、特定の企業だけが社内用に使用しているファイルシステム(GFS - Google File Systemのようなもの)もあります。

OSの開発者の多くは、FATファイルシステム(あるいは全く新しいもの)のバージョンを作っています。 しかし、これらは通常、最も一般的なファイルシステム(FATやNTFSなど)ほど良くはありません。

さて、これでファイルシステムについては少しわかったと思います。私たちはそのシンプルさのためにFAT12を使うつもりです。 もし私たちが決めたら、いつでも別のものを使うことができます :)

FAT12 ファイルシステム - 理論

FAT12は1977年にリリースされた最初のFAT(File Allocation Table)ファイルシステムで、Microsoft Disk BASICで使用されています。 FAT12は一般にフロッピーディスク用にリリースされた古いファイルシステムなので、いくつかの制限事項がありました。
  • FAT12は階層的なディレクトリをサポートしていません。つまり、ディレクトリは1つだけです-ThrRoot Directory
  • クラスタアドレスは12ビットしかなく、クラスタの最大数は4096に制限されています。
  • ファイル名は12ビットの識別子としてFATに格納されます。クラスタアドレスは、ファイルの開始クラスタを表します。
  • クラスタサイズに制限があるため、可能な最大ファイル数は4,077です。
  • ディスクサイズは、16ビットのセクター数としてのみ格納され、サイズは32MiBに制限されます。
  • FAT12では、パーティションの識別に "0x01 "という値を使用する
これらは大きな制限です。では、なぜFAT12が必要なのでしょうか?

FAT16は、FAT12と異なり、16ビットのクラスタ(ファイル)アドレスを使用するため、ディレクトリや64,000以上のファイルをサポートする。しかし、FAT16とFAT12は非常によく似ています。

ここでは、FAT12を使用することにします。後でFAT16を使うかもしれませんし、FAT32を使うかもしれません:)。(FAT32はFAT12/16とかなり違うので、後でFAT16を使うことになるかもしれません)

FAT12 FileSystem - Disk Storage

FAT12とその仕組みについてもっと理解するためには、典型的なフォーマット済みディスクの構造を見てみるのがよいでしょう。
Boot Sector Extra Reserved Sectors File Allocation Table 1 File Allocation Table 2 Root Directory (FAT12/FAT16 Only) Data Region containng files and directories.

これは典型的なFAT12ディスクのフォーマットで、ブートセクタからディスクの一番最後のセクタまでです。

この構造を理解することは、ファイルを読み込んだり検索したりする際に重要です。

ディスクには2つのFATがあることに注意してください。FATは予約セクタ(ない場合はブートローダ)のすぐ後に位置しています。

また、Root DirectoryはすべてのFATの直後にあることにも注意してください。これはつまり...

FATごとのセクタ数と予約セクタを合計すれば、最初のセクタをRootディレクトリに確保することができるのです。Root Directoryで単純な文字列(ファイル名)を検索すれば、ディスク上のファイルの正確なセクタを効率的に見つけることができます :)

もっと詳しく見てみましょう...

Boot Sector

このセクションには、BIOSパラメータブロックとブートローダが含まれています。そう--私たちの。BIOSパラメーターブロックには、ディスクを説明するのに役立つ情報が含まれています。

Extra Reserved Sectors

BPBのbpbReservedSectorsメンバーを覚えていますか?余分な予約セクタは、ブートセクタのすぐ後にここに格納されます。

File Allocation Tables (FATs)

クラスタはディスク上の連続したセクタを表し、各クラスタのサイズは通常 2 KB から 32 KiB であることを覚えておいてください。ファイル ピースは、リンクリストのような一般的なデータ構造を使って (1 つのクラスターから別のクラスターに) リンクされます。

FATは2つあります。ただし、1つはデータ復旧のために最初の1つをコピーしたもので、通常は使用されません。

ファイルアロケーションテーブル(FAT)は、これらのクラスタにマッピングするエントリのリストです。 これらのクラスタにデータを格納するのに役立つ重要な情報を識別するのに役立ちます。

各エントリーは、クラスタを表す12ビットの値である。FATは、どのクラスタが使用されているかを識別するために、これらのエントリを持つリンクリストのような構造になっています。

このことをより良く理解するために、可能な値を見てみましょう。

  • 域マーク フリークラスタ:0x00
  • マーク 予約クラスタ:0x01
  • このクラスタは使用中であり、値は次のクラスタを表す:0x002~0xFEF
  • 予約値:0xFF0~0xFF6
  • 不良クラスタに対応する値:0xFF7
  • このクラスタがファイルの最後であることを示す値:0xFF8~0xFFF
FATはこれらの値の配列に過ぎません。ルートディレクトリの開始セクタを見つけたら、FATを調べてどのクラスタを読み込むかを決めます。どうやって?単純に値を調べればいいんです。値が0x02から0xfefの間であれば、この値はファイルに対して次にロードすべきクラスタを表しています。

もう少し詳しく見てみましょう。クラスタは、ご存知のように、一連のセクタを表します。 クラスタが表すセクタの量は、BIOS パラメータ・ブロックから定義されます。

bpbBytesPerSector: DW 512 bpbSectorsPerCluster: DB 1
この場合、各クラスタは1セクタです。ステージ2の最初のセクタを取得したら(ルート・ディレクトリから取得します)、このセクタをFATの開始クラスタ番号として使用します。開始クラスタが見つかったら、FATを参照してクラスタを決定します(FATは単なる32ビット番号の配列です。この番号と上記のリストを比較して、何をすべきかを決めるだけです)。 さて、ここが私たちにとって重要なところです :)

ルートディレクトリは、ファイルやディレクトリに関する情報を32バイトの値で表したテーブルです。 この32バイトの値は、次のようなフォーマットで使用します。

  • Bytes 0-7 : DOS File name (Padded with spaces)
  • Bytes 8-10 : DOS File extension (Padded with spaces)
  • Bytes 11 : File attributes. This is a bit pattern:
    • Bit 0 : Read Only
    • Bit 1 : Hidden
    • Bit 2 : System
    • Bit 3 : Volume Label
    • Bit 4 : This is a subdirectory
    • Bit 5 : Archive
    • Bit 6 : Device (Internal use)
    • Bit 6 : Unused
  • Bytes 12 : Unused
  • Bytes 13 : Create time in ms
  • Bytes 14-15 : Created time, using the following format:
    • Bit 0-4 : Seconds (0-29)
    • Bit 5-10 : Minutes (0-59)
    • Bit 11-15 : Hours (0-23)
  • Bytes 16-17 : Created year in the following format:
    • Bit 0-4 : Year (0=1980; 127=2107
    • Bit 5-8 : Month (1=January; 12=December)
    • Bit 9-15 : Hours (0-23)
  • Bytes 18-19 : Last access date (Uses same format as above)
  • Bytes 20-21 : EA Index (Used in OS/2 and NT, dont worry about it)
  • Bytes 22-23 : Last Modified time (See byte 14-15 for format)
  • Bytes 24-25 : Last modified date (See bytes 16-17 for format)
  • Bytes 26-27 : First Cluster
  • Bytes 28-32 : File Size
重要な部分は太字にしました。他はマイクロソフトが追加したジャンクで、FAT12ドライバを作るときに、もっと後で追加すればいいんです。

ちょっと待ってください!DOSのファイル名は11バイトに制限されているのを覚えていますか?これが理由です。

  • Bytes 0-7 : DOS File name (Padded with spaces)
  • Bytes 8-10 : DOS File extension (Padded with spaces)
0から10までは、うーん...11バイトですね。11バイト未満のファイル名をつけると、データ入力がうまくいかなくなります(上に表示されている32バイトの入力テーブル)。もちろん、これは悪いことです :)このため、ファイル名を文字で埋め、11バイトであることを保証する必要があるのです。

前回のチュートリアルで、ファイル名には内部ファイル名と外部ファイル名があることを説明しましたが、今回説明したファイル名の構造は内部ファイル名です。11バイトに制限されているので、"Stage2.sys "というファイル名は次のようになります。

"STAGE2 SYS" (Note the padding!)

FAT12の検索と読み込み - 理論編

さて、上記をすべて読み終えたら、私が「FAT12」と言うのに飽きたことでしょう :)

さてさて。この情報はどのように役立つのでしょうか?

BIOS Parameter Block (BPB)をたくさん参照するつもりです。以下は、以前のチュートリアルで作成したBPBを参照するためのものです。

bpbBytesPerSector: DW 512 bpbSectorsPerCluster: DB 1 bpbReservedSectors: DW 1 bpbNumberOfFATs: DB 2 bpbRootEntries: DW 224 bpbTotalSectors: DW 2880 bpbMedia: DB 0xF0 bpbSectorsPerFAT: DW 9 bpbSectorsPerTrack: DW 18 bpbHeadsPerCylinder: DW 2 bpbHiddenSectors: DD 0 bpbTotalSectorsBig: DD 0 bsDriveNumber: DB 0 bsUnused: DB 0 bsExtBootSignature: DB 0x29 bsSerialNumber: DD 0xa0a1a2a3 bsVolumeLabel: DB "MOS FLOPPY " bsFileSystem: DB "FAT12 "
各メンバーの詳細な説明については、前回のチュートリアルを参照してください。

私たちがやろうとしていることは、セカンドステージのローダーをロードすることです。具体的にどのようなことをするのか見てみましょう。

ファイル名で始める

まず最初にすべきことは、良いファイル名を作ることです。覚えておいてください。ルートディレクトリを破壊しないように、ファイル名は正確に11バイトでなければなりません。

私はセカンドステージに "STAGE2.SYS "を使っています。その内部ファイル名の例は、上のセクションで見ることができます。

第2ステージの作成

さて、Stage2 はブートローダとは別個のプログラムです。Stage2はDOSのCOMプログラムに非常によく似たものになります。

Stage2が今やっていることは、メッセージを表示して停止することだけです。ブートローダで既に見たことがあるものばかりです。

; Note: Here, we are executed like a normal ; COM program, but we are still in Ring 0. ; We will use this loader to set up 32 bit ; mode and basic exception handling ; This loaded program will be our 32 bit Kernel. ; We do not have the limitation of 512 bytes here, ; so we can add anything we want here! org 0x0 ; offset to 0, we will set segments later bits 16 ; we are still in real mode ; we are loaded at linear address 0x10000 jmp main ; jump to main ;*************************************************; ; Prints a string ; DS=>SI: 0 terminated string ;************************************************; Print: lodsb ; load next byte from string from SI to AL or al, al ; Does AL=0? jz PrintDone ; Yep, null terminator found-bail out mov ah, 0eh ; Nope-Print the character int 10h jmp Print ; Repeat until null terminator found PrintDone: ret ; we are done, so return ;*************************************************; ; Second Stage Loader Entry Point ;************************************************; main: cli ; clear interrupts push cs ; Insure DS=CS pop ds mov si, Msg call Print cli ; clear interrupts to prevent triple faults hlt ; hault the system ;*************************************************; ; Data Section ;************************************************; Msg db "Preparing to load operating system...",13,10,0
NASMでアセンブルするには、バイナリプログラムとしてアセンブルし(COMプログラムはバイナリです)、フロッピーディスクイメージにコピーすればよいのです。例えば
nasm -f bin Stage2.asm -o STAGE2.SYS copy STAGE2.SYS A:\STAGE2.SYS
PARTCOPYは必要ありません :)

ステップ1:ルート・ディレクトリ・テーブルの読み込み

さて、いよいよStage2.sysのロードです。ここでは、ディスク情報のためのBIOSパラメータブロックとともに、Rootディレクトリテーブルを参照することになります。

ステップ1:ルートディレクトリのサイズを取得する

さて、まず最初にルートディレクトリのサイズを取得する必要があります。

ルートディレクトリのサイズを取得するには、ルートディレクトリのエントリ数を掛け合わせます。簡単そうですね......。)

Windowsでは、FAT12でフォーマットされたディスクにファイルやディレクトリを追加すると、Windowsが自動的にそのファイル情報をルートディレクトリに追加するので、それを気にする必要はありません。これによって、物事はずっとシンプルになります。

ルート・エントリーの数をセクタあたりのバイト数で割ると、ルート・エントリーが何セクタを使用しているかがわかります。

以下はその例です。

mov ax, 0x0020 ; 32 byte directory entry mul WORD [bpbRootEntries] ; number of root entrys div WORD [bpbBytesPerSector] ; get sectors used by root directory
ルート・ディレクトリ・テーブルは、ファイル情報を表す32バイトの値(エントリ)のテーブルであることを思い出してください。

よっしゃー、ルートディレクトリにロードするセクタの数がわかったぞ。では、ロードする開始セクタを探しましょう :)

ステップ2:ルートディレクトリの開始を取得

これも簡単です。まず、FAT12でフォーマットされたディスクをもう一度見てみましょう。
Boot Sector Extra Reserved Sectors File Allocation Table 1 File Allocation Table 2 Root Directory (FAT12/FAT16 Only) Data Region containng files and directories.

ルートディレクトリは、FATと予約セクタの直後にあることに注意してください。 つまり、FATと予約セクタを足せば、ルートディレクトリが見つかるということです。

例えば...

mov al, [bpbNumberOfFATs] ; Get number of FATs (Useually 2) mul [bpbSectorsPerFAT] ; number of FATs * sectors per FAT; get number of sectors add ax, [bpbReservedSectors] ; add reserved sectors ; Now, AX = starting sector of root directory
かなり簡単でしょう?さて、セクタをメモリ上のある場所に読み込むだけです。
mov bx, 0x0200 ; load root directory to 7c00:0x0200 call ReadSectors

ルートディレクトリ - 完全な例

このサンプルコードはチュートリアルの最後にあるブートローダから直接取ったものです。 これはルートディレクトリをロードします。
LOAD_ROOT: ; compute size of root directory and store in "cx" xor cx, cx xor dx, dx mov ax, 0x0020 ; 32 byte directory entry mul WORD [bpbRootEntries] ; total size of directory div WORD [bpbBytesPerSector] ; sectors used by directory xchg ax, cx ; compute location of root directory and store in "ax" mov al, BYTE [bpbNumberOfFATs] ; number of FATs mul WORD [bpbSectorsPerFAT] ; sectors used by FATs add ax, WORD [bpbReservedSectors] ; adjust for bootsector mov WORD [datasector], ax ; base of root directory add WORD [datasector], cx ; read root directory into memory (7C00:0200) mov bx, 0x0200 ; copy root dir above bootcode call ReadSectors

ステップ 2: Find Stage 2

さて、ルートディレクトリのテーブルがロードされました。上のコードを見ると、0x200 にロードしています。 さて、ファイルを探します。

32バイトのルートディレクトリのテーブルをもう一度見てみましょう(SectionRoot Directory Table.最初の11バイトはファイル名を表していることを思い出してください。また、各ルートディレクトリのエントリは32バイトであるため、32バイトごとに次のエントリの先頭になり、次のエントリの最初の11バイトを指し示すことも覚えておいてください。

したがって、ファイル名を比較し、次のエントリ (32 バイト) にジャンプし、セクタの最後に達するまで再度テストする必要があります。 たとえば...

; browse root directory for binary image mov cx, [bpbRootEntries] ; the number of entrys. If we reach 0, file doesnt exist mov di, 0x0200 ; Root directory was loaded here .LOOP: push cx mov cx, 11 ; eleven character name mov si, ImageName ; compare the 11 bytes with the name of our file push di rep cmpsb ; test for entry match pop di je LOAD_FAT ; they match, so begin loading FAT pop cx add di, 32 ; they dont match, so go to next entry (32 bytes) loop .LOOP jmp FAILURE ; no more entrys left, file doesnt exist :(
次のステップに進みましょう...

ステップ3: FATのロード

ステップ1: スタートクラスタの取得

ルート・ディレクトリがロードされ、ファイルのエントリが見つかりました。その開始クラスタを得るにはどうしたらよいでしょうか?
  • 26〜27バイト目 :最初のクラスタ
  • 28〜32バイト目 : ファイルサイズ
これは見覚えがあるはずです :)開始クラスタを取得するには、ファイルエントリのバイト26を参照してください。
mov dx, [di + 0x001A] ; di contains starting address of entry. Just refrence byte 26 (0x1A) of entry ; Yippe--dx now stores the starting cluster number
この開始クラスタは、ファイルをロードする際に重要です。

ステップ2:FATのサイズを取得する

もう一度、BIOSパラメータブロックを見てみましょう。具体的には...
bpbNumberOfFATs: DB 2 bpbSectorsPerFAT: DW 9
では、両方のFATに存在するセクタ数を調べるにはどうすればいいのでしょうか?FATごとのセクタ数を掛ければいいんです :)簡単そうに見えますが ...。
xor ax, ax mov al, [bpbNumberOfFATs] ; number of FATs mul WORD [bpbSectorsPerFAT] ; multiply by number of sectors per FAT ; ax = number of sectors the FATs use!
いや、気にしないでください、簡単です^^。

ステップ3:FATをロードする

さて、読み込むべきセクタ数がわかったところで。ただ、えーと...読むだけです :)
mov bx, 0x0200 ; address to load to call ReadSectors ; load the FAT table
よっしゃーーーさて、FATの話は終わりましたが(完全ではありません!)、ステージ2にロードしてみましょう

FAT - 完全な例

以下は、ブートローダから直接取得した完全なコードです。
LOAD_FAT: ; save starting cluster of boot image mov si, msgCRLF call Print mov dx, WORD [di + 0x001A] mov WORD [cluster], dx ; file's first cluster ; compute size of FAT and store in "cx" xor ax, ax mov al, BYTE [bpbNumberOfFATs] ; number of FATs mul WORD [bpbSectorsPerFAT] ; sectors used by FATs mov cx, ax ; compute location of FAT and store in "ax" mov ax, WORD [bpbReservedSectors] ; adjust for bootsector ; read FAT into memory (7C00:0200) mov bx, 0x0200 ; copy FAT above bootcode call ReadSectors

LBAとCHS

イメージをロードする際に必要なのは、FATを参照しながら各クラスタをロードすることです。

しかし、まだ議論していない小さな問題が1つあります。さて、FATからクラスタ番号を取得しました。しかし、それをどのように使うのでしょうか?

問題は、このクラスタがリニアアドレスを表しているのに対し、セクタをロードするためには、セグメント/トラック/ヘッドアドレスが必要だということです。(インタラプト0x13)

ディスクにアクセスする方法は2つあります。シリンダー/ヘッド/セクター(CHS)アドレスによる方法と、論理ブロック・アドレッシング(LBA)による方法です。

LBAは、ディスク上のインデックス付きの位置を表します。LBAは、セクタがLBA 0から順番に番号付けされていることを表しています。

LBAとCHSの間の変換方法を知っておく必要があります。

Converting CHS to LBA

CHSからLBAへの変換式は次のとおりです

LBA = (cluster - 2 ) * sectors per cluster
これはとても簡単なことです。
sub ax, 0x0002 ; subtract 2 from cluster number xor cx, cx mov cl, BYTE [bpbSectorsPerCluster] ; get sectors per cluster mul cx ; multply

LBAからCHSへの変換

これは少し複雑ですが、それでも非常に簡単です。
absolute sector = (LBA % sectors per track) + 1 absolute head = (LBA / sectors per track) % number of heads absolute track = LBA / (sectors per track * number of heads)
これがその例です。
LBACHS: xor dx, dx ; prepare dx:ax for operation div WORD [bpbSectorsPerTrack] ; divide by sectors per track inc dl ; add 1 (obsolute sector formula) mov BYTE [absoluteSector], dl ; these forumlas are very simular... xor dx, dx ; prepare dx:ax for operation div WORD [bpbHeadsPerCylinder] ; mod by number of heads (Absolue head formula) mov BYTE [absoluteHead], dl ; everything else was already done from the first formula mov BYTE [absoluteTrack], al ; not much else to do :) ret
それほど難しくはないと思います :)

クラスタをロードする

さて、Stage 2のロードでは、まずFATからクラスタを参照する必要があります。そして、クラスタ番号をLBAに変換して、読み込むことができます。
mov ax, [cluster] ; cluster to read pop bx ; buffer to read into call ClusterLBA ; convert cluster to LBA xor cx, cx mov cl, [bpbSectorsPerCluster] ; sectors to read call ReadSectors ; read in cluster push bx

次のクラスタを取得

これが厄介なんです。

さて、FATのエントリにある各クラスタ番号は12ビットであることを思い出してください。これは問題で、1バイトで読み込むとクラスタ番号の一部しかコピーしていないことになります!このため、クラスタ番号の一部を読み込む必要があります。

このため、WORD(2バイト)の値を読み込まなければならない。

それでも、また、問題にぶつかる。12ビットの値から)2バイトコピーするということは、次のクラスタエントリの一部をコピーすることになります。 例えば、これがあなたのFATだと想像してください。

Note: Binary numbers seperated in bytes. Each 12 bit FAT cluster entry is displayed. | | 01011101 0111010 01110101 00111101 0011101 0111010 0011110 0011110 | | | | | | | |1st cluster | |3rd cluster-| | |-0 cluster ----| |2nd cluster---| |4th cluster----|

すべての偶数クラスタが最初のバイトのすべてをコピーし、2番目のバイトの一部をコピーしていることに注意してください。また、すべての奇数クラスターは最初のバイトの一部をコピーしますが、2番目のバイトのすべてをコピーすることに注意してください!偶数クラスターは最初のバイトのすべてをコピーしますが、2番目のバイトのすべてをコピーします。

さて、それではFATから2バイト(ワード)の値を読みましょう(これが我々のクラスタです)。

もしクラスタが偶数なら、次のクラスタに属するので上位4ビットをマスクしてください。

奇数なら4ビット下にシフトする(最初のクラスタが使っていたビットを捨てる)例えば...

; compute next cluster mov ax, WORD [cluster] ; identify current cluster from FAT ; is the cluster odd or even? Just divide it by 2 and test! mov cx, ax ; copy current cluster mov dx, ax ; copy current cluster shr dx, 0x0001 ; divide by two add cx, dx ; sum for (3/2) mov bx, 0x0200 ; location of FAT in memory add bx, cx ; index into FAT mov dx, WORD [bx] ; read two bytes from FAT test ax, 0x0001 jnz .ODD_CLUSTER ; Remember that each entry in the FAT is a 12 but value. If it represents ; a cluster (0x002 through 0xFEF) then we only want to get those 12 bits ; that represent the next cluster .EVEN_CLUSTER: and dx, 0000111111111111b ; take low twelve bits jmp .DONE .ODD_CLUSTER: shr dx, 0x0004 ; take high twelve bits .DONE: mov WORD [cluster], dx ; store new cluster cmp dx, 0x0FF0 ; test for end of file jb LOAD_IMAGE ; we are not done yet--go to next cluster

まとめ

うわー、このチュートリアルは書くのが大変でした。というのも、このような複雑なトピックを細部まで説明するのは難しいのですが、それでも非常に分かりやすいものにしようとしたからです。うまく書けたでしょうか?)

もし、このチュートリアルをより良くするための提案があれば、ぜひ教えてください :)

さて...これで終わりです。さようなら、ブートローダ!

次のチュートリアルでは、Stage 2 の構築を開始します。A20について話し、プロテクトモードについてもっと詳しく見ていきます。