x86 CPU

はてなブックマークに移行済み(20101229)


Other CPU



   [ GRUB ]

・GRUBのソースコードから、stage1の起動の様子を確認する

    GRUB installで、 インストール方法を紹介しています。
    最新のGRUBについては、 こちら からダウンロードできます。

    Linux kernel の起動時にはCとアセンブラが主役になっていますので、
    これを読み解くことでlinuxシステムの理解を深めます。

    起動時のプログラムは、基本的に 構造化プログラミングのため、逐次処理していきます。

    一般的な紹介ページにあるアセンブラとは違う点としては、
    起動時のアセンブラでは、ジャンプや条件文、繰り返し等のタイミングごとに
    使用するフラグの確認が必要なケースが多いことです。

    せっかくですので、最新版の「grub-1.97.2」を題材にしようと思います。

    解凍した後の「boot/i386/pc/boot.S」がstage1です。
    ディレクトリ構造から分かるように、x86 CPUではこちらを使います。
    pcディレクトリには、他にもファイルがあり、それぞれ、CD起動、FD起動、vfat起動、pxe起動です。
    「cdboot.S diskboot.S lnxboot.S pxeboot.S」

    「INSTALL」ファイルには、「* GCC 4.1.3 or later」を使用することが記載されています。
    「gcc -v」コマンドで確認したところ、「gcc version 4.3.2 (Debian 4.3.2-1.1)」でした。

    man gccのマニュアルを見ると、プリプロセッサ(前処理)するかどうかで、「.s」「.S」が使い分けられています。

      拡張子  
      概要  

      .s

         アセンブリ言語ソースです。アセンブラにかけられます。

      .S

         アセンブリ言語ソースです。プリプロセッサ、アセンブラにかけられます。

      .h

         プリプロセッサファイルです。通常はコマンドラインには現れません。

    まずは3つのヘッダファイルが読み込まれます。
    「<file>」と「"file"」の違いについては「man gcc」に説明があります。

    #include <grub/symbol.h>
    #include <grub/boot.h>
    #include <grub/machine/boot.h>


         #include <file>

         システムヘッダファイル

         #include "file"

         ユーザ定義のヘッダファイル

    システムヘッダファイルの概要です。

         include/grub/symbol.h    関数や変数のマクロ定義
         include/grub/boot.h    GRUBバージョンのためのマクロ定義
         include/grub/i386/coreboot/boot.h
         include/grub/i386/pc/boot.h
         起動のための定数マクロ定義

         例)ブートシグニチャの定数の設定
         #define GRUB_BOOT_MACHINE_SIGNATURE 0xaa55

      [ 概要 ]

    ・「boot.S」には、「CS:IP 0:0x7c00」とあります。
       有名な、kernelのスタート地点ですね。

    ・BPB(BIOS Paramater Block) = NTFS用の最初のセクタ(パーティションのセクタ数、MFT の位置等)

       ・HD用の「BPB」を回避する「jmp」があります。
         FDの場合は通常NTFSフォーマットは使わないため、「jmp」は不要です。

    ・HDが起動可能かどうかチェックする中で、
       LBAで失敗した場合は、CHSを使うという箇所があります。
       しかし、HD起動の場合は結局CHSだと失敗するようになっています。
       遠まわしですが、要はHD起動の場合CHSは使わないということを意味します。

    このあたりは、コメントから読むGRUB stage1で書いたとおりです。

    ・「GRUB_BOOT_MACHINE_KERNEL_ADDR」は、
       「include/grub/i386/pc/boot.h」にある以下の箇所で定義されています。

    これで、stage2に制御を移してstage1は終了です。

       /* The segment where the kernel is loaded. */
       #define GRUB_BOOT_MACHINE_KERNEL_SEG 0x800

       /* The address where the kernel is loaded. */
       #define GRUB_BOOT_MACHINE_KERNEL_ADDR (GRUB_BOOT_MACHINE_KERNEL_SEG << 4)

    0x800を4bit左シフトすると、0x8000になります。これがstage2のスタート地点になります。
    ちなみに、stage1.5の場合は0x2000を指定します。
    今はstageという表現は使わないようです。

       $ let x="0x800<<4";echo -n "0x";dc -e "10i 16o $x p"
       0x8000

    ・新しいGRUBソースコードはドキュメントが充実したようです。
       次回は実際のbinaryと比較しながら進めていきたいと思います。
・情報源



TOP