Tsurugidake's diary

プログラミング学習の記録,備忘録

Linuxで書くOS自作入門 2日目

「30日でできる!OS自作入門」の2日目
環境はUbuntu, アセンブラはNASMで開発中

アセンブリの更新

  • プログラム本体部分が意味を持つ命令で置き換えられた.
  • ラベルが追加された.
  • レジスタ名が記述されるようになった.
  • 新しいアセンブリ命令
    • ORG 機械語をメモリ中の指定された部分に読み込む origin
    • JMP 指定のラベルやアドレスにジャンプする jump
    • MOV 代入文 レジスタやアドレス,即値を指定可能 MOV AX,0でAXに0を代入 move
  • 今まで空き部分を0で埋めるために使用していたRESB命令は警告が出るので,TIMES命令によって置き換えることにした.
    • TIMES 指定回数直後の命令を繰り返す
      RESB 18TIMES 18 DB 0

Makefileの作成

Win版のMakefileをもとに,Linuxで動作するように書き換えた.本では,独自ツールedimg.exeなどが登場するが,これらに頼らず自分でディスクイメージを作成する.今日の範囲ではブートセクタの部分とそれ以外の部分をcatで結合しているだけである.

ここでは,ファイル名を変更し,ブートセクタのアセンブリipl.asm,それ以外のアセンブリtail.asmとしている.

default  :
  make img

ipl.bin : ipl.asm Makefile
  nasm ipl.asm -o ipl.bin -l ipl.lst

tail.bin : tail.asm Makefile
  nasm tail.asm -o tail.bin -l tail.lst

helloos.img : ipl.bin tail.bin Makefile
  cat ipl.bin tail.bin > helloos.img

asm :
  make -r ipl.bin

img :
  make -r helloos.img

run :
  make img
  qemu-system-i386 helloos.img

clean :
   -rm ipl.bin
   -rm tail.bin
   -rm ipl.lst
   -rm tail.lst

src_only :
  make clean
  rm helloos.img

ブートセクタの簡単な解釈

ブートセクタ部分に関してはアセンブリが読めるようになってきたため,ここでアセンブリが何をしているのか読んで見る.その前に用語を整理する.

  • ブートセクタ ディスクの最初のセクタ.そもそもセクタはディスクの読み書きの最小単位であり,512バイトである.最初にここを読み込むことによって,OSは起動する.
  • FAT12フォーマット フロッピーディスクのフォーマット形式
     ORG      0x7c00

機械語翻訳はされない,アセンブラのための命令.ブートセクタは0x00007c00 - 0x00007dffに読み込まれるので,これを明示化している1.絶対アドレスを正しく計算するために使っているのだと思う.

     JMP      entry
        DB       0x90
        DB       "HELLOIPL"     ; ブートセクタの名前を自由に書いてよい(8バイト)
        DW       512                ; 1セクタの大きさ(512にしなければいけない)
        DB       1              ; クラスタの大きさ(1セクタにしなければいけない)
        DW       1              ; FATがどこから始まるか(普通は1セクタ目からにする)
        DB       2              ; FATの個数(2にしなければいけない)
        DW       224                ; ルートディレクトリ領域の大きさ(普通は224エントリにする)
        DW       2880           ; このドライブの大きさ(2880セクタにしなければいけない)
        DB       0xf0           ; メディアのタイプ(0xf0にしなければいけない)
        DW       9              ; FAT領域の長さ(9セクタにしなければいけない)
        DW       18             ; 1トラックにいくつのセクタがあるか(18にしなければいけない)
        DW       2              ; ヘッドの数(2にしなければいけない)
        DD       0          ; パーティションを使ってないのでここは必ず0
        DD       2880           ; このドライブ大きさをもう一度書く
        DB       0,0,0x29       ; よくわからないけどこの値にしておくといいらしい
        DD       0xffffffff     ; たぶんボリュームシリアル番号
        DB       "HELLO-OS   "   ; ディスクの名前(11バイト)
        DB       "FAT12   "     ; フォーマットの名前(8バイト)
        TIMES    18 DB 0            ; とりあえず18バイトあけておく

FAT12フォーマットフロッピーディスクのための記述であり,BPB(BIOS Parameter Block)と呼ばれるらしい.FATボリュームの認識のための記述.明確に定められた部分が多い.
ここに詳しく書いてあった.ELM FATファイル システムのしくみと操作法

entry:
        MOV      AX,0        ; レジスタ初期化
        MOV      SS,AX
        MOV      SP,0x7c00
        MOV      DS,AX
        MOV      ES,AX
        MOV      SI,msg

最初の命令,JMP entryによってジャンプして最初に実行されるこのプログラムをブートストラッププログラムと呼ぶ.最初はレジスタの初期化が行われている.特筆すべきはスタックポインタSPはブートセクタの開始位置0x7c00に,ソースインデックスSIは表示文字列を指すラベルmsgが代入されている.

putloop:
        MOV      AL,[SI]
        ADD      SI,1            ; SIに1を足す
        CMP      AL,0
        JE       fin
        MOV      AH,0x0e         ; 一文字表示ファンクション
        MOV      BX,15           ; カラーコード
        INT      0x10           ; ビデオBIOS呼び出し
        JMP      putloop

ソースインデックスSIの指すアドレス部分をALに読み込み,0x0eをAHに読み込んだ後,INT 0x10命令を使うことによって文字が表示される.文字列が終わるってALがゼロになるまでループしている.
ここに詳しく書いてあった.(AT)BIOS - os-wiki

fin:
        HLT                      ; 何かあるまでCPUを停止させる
        JMP      fin              ; 無限ループ

HLTは次の外部割り込みが発生するまでCPUを停止させる命令でこれを無限ループしている.これ無しで実行するとCPUが動き続けるらしく,ファンがうるさくなった.

msg:
        DB       0x0a, 0x0a        ; 改行を2つ
        DB       "Hello, world! "
        DB       0x0a           ; 改行
        DB       0

メッセージ部分.好きな文字を書ける.

     TIMES    0x7dfe-0x7c00-($-$$) DB 0     ; 0x7dfeまでを0x00で埋める命令

ブートセクタの最後0x7dffから最後の2バイトを除いた0x7dfeまでを0で埋める.

     DB       0x55, 0xaa

最後の2バイトをこれにすることによって,有効なブートセクタであることを示す.