12ステップで作る組込みOS自作入門
      6thステップ




                @sandai
【参考書籍】
12ステップで作る組込みOS自作入門
【内容】
1ステップずつ、実際に動かしながらプログラムを発展さ
せていく方式で無理なく学べる。OSやハードウェアに詳
しくない方にも理解できるよう
に十分な説明を提供

坂井 弘亮(著)
カットシステム(2010/5)

【税込価格】
4,410円

【サポートページ】
http://kozos.jp/books/makeos/
もくじ
1.エントリ・ポイント
2.ブートローダとOSの作成
3.まとめ
1.エントリ・ポイント
エントリ・ポイント
●   ELF形式のファイルのセグメント情報は読み取
    れるようになったので、これからセグメントを
    RAMに展開し処理を渡すことをする
    –   このときにどのアドレスから実行開始すれば良いか
        を指示しなければならない
●   この実行開始アドレスを、一般的にスタート・
    アドレス又はエントリ・ポイントと呼ぶ
    –   ELF形式ではエントリ・ポイントと言う
ELF形式のエントリ・ポイント
●   ELF形式のファイルはエントリ・ポイントの情
    報をヘッダに持っている
    –   ELFヘッダのうち、「Entry point address」の部分
    –   そのアドレスから実行開始するのが妥当
         ● アセンブリ的にはそのアドレスにジャンプする

           だけ。これを「実行を渡す」とか「処理を渡
           す」と表現したりする
2.ブートローダとOSの作成
開発の流れ
●   ここからブートローダとOSに分かれる
    –   ブートローダ
         ● ダウンロードしたOSを起動するプログラム


    –   OS
         ● 今回はHello Worldを表示するだけのプログラム


●   どっちもこれまで書いてきたプログラムをいじ
    るだけ
ブートローダのプログラム
●   追加ファイル
    –   なし
●   修正ファイル
    –   elf.h,elf.c...メモリ上へのコピーとエントリ・ポ
        イント対応
    –   main.c...エントリ・ポイントからの起動を追加
セグメントをRAMに展開する
●   そのままRAMにコピーするだけ
●   以前セグメント情報を表示していた部分を消し
    て以下のコードを追加
●   コピー先がVAではなくPAになってる。VAでも問
    題ないが、あくまで論理アドレスだからPAの方
    を利用すべしとのこと
memcpy((char *)phdr->physical_addr, (char *)header + phdr-
>offset, phdr->file_size);
memset((char *)phdr->physical_addr + phdr->file_size, 0,
phdr->memory_size - phdr->file_size);
エントリ・ポイントを取得
●   main.cで呼び出すエントリ・ポイントを返す関
    数。ELFファイルのチェックとロードも行われ
    ている
char *elf_load(char *buf)
{
    struct elf_header *header = (struct elf_header * )buf;

    if (elf_check(header) < 0)
        return NULL;

    if (elf_load_program(header) < 0)
        return NULL;

    return (char *)header->entry_point;
}
OSのプログラム
●   追加ファイル
    –   defines.h...ブートローダと同じ
    –   lib.h,lib.c...ブートローダと同じ
    –   serial.h,serial.c...ブートローダと同じ
    –   startup.s...ブートローダと同じ
    –   main.c...新しく作成。Hello Worldを表示
    –   ld.scr...OS側用のリンカ
    –   Makefile
●   これらのファイルは、~/12step/src/06/os以下
    に保存
プログラム修正
●   main.c
    –   初期化関数を全て削除
        ● データ領域のコピ、BSS領域のクリア、シリア

          ル・デバイスの初期化はブートローダ側でする
          ことになったので
●   ld.scr
    –   全てram上に配置されるように変更
●   Makefile
    –   不要な部分を削除
OS側のエントリ・ポイント
●   OS側のエントリ・ポイントは、ld.scrの
    ENTRY(“_start”)により、startup.sの_start
    ラベルの位置をエントリ・ポイントとしてELF
    ヘッダが作成
●   ブートローダのf()の呼び出しが、OS側の
    _startの位置から動作を開始することになる
●   ブートローダのld.scrにもENTRY(“_start”)
    はあるが、実はこれは特に意味はない
    –   リセット・ベクタから起動してるから
プログラム実行
●   osディレクトリでmakeして、それからbootload
    ディレクトリでmake、make image、make write
    してからのログ
/Users/sandai/12step/src/06/os% sudo cu -l /dev/tty.usbserial-FTG6PQ4H
Password:
Connected.
kzload (kozos boot loader) started.
kzload> load
~+lsx kozos
Sending kozos, 11 blocks: Give your local XMODEM receive command now.
Bytes Sent:   1536   BPS:220

Transfer complete

XMODEM receive succeeded!
kzload> run
starting from entry point: ffc020
Hello World!
> echo aaa
 aaa
補足
●   もしosのld.scrで.text.startupの部分を削除
    していなかったら、エントリ・ポイントのアド
    レス位置は違うので注意
●   なんなんだろうねこれ。よくわからんわ
3.まとめ
まとめ
●   ブートローダとOSを作成した
    –   OSというか、Hello Worldのプログラム
●   ブートローダ側とOS側でスタックとかかぶって
    るけどいいのかな?
    – ああ、あれか。スタックだもんな。関数抜け
      たら全部なくなるから、一緒のとこつかえば
      いいか
●   とりあえずブートローダの仕組みがわかったの
    でよかった
●   書籍ではまだCPUの動作原理という話が続く
    が、ここでは省略する

【学習メモ#6th】12ステップで作る組込みOS自作入門

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
    エントリ・ポイント ● ELF形式のファイルのセグメント情報は読み取 れるようになったので、これからセグメントを RAMに展開し処理を渡すことをする – このときにどのアドレスから実行開始すれば良いか を指示しなければならない ● この実行開始アドレスを、一般的にスタート・ アドレス又はエントリ・ポイントと呼ぶ – ELF形式ではエントリ・ポイントと言う
  • 6.
    ELF形式のエントリ・ポイント ● ELF形式のファイルはエントリ・ポイントの情 報をヘッダに持っている – ELFヘッダのうち、「Entry point address」の部分 – そのアドレスから実行開始するのが妥当 ● アセンブリ的にはそのアドレスにジャンプする だけ。これを「実行を渡す」とか「処理を渡 す」と表現したりする
  • 7.
  • 8.
    開発の流れ ● ここからブートローダとOSに分かれる – ブートローダ ● ダウンロードしたOSを起動するプログラム – OS ● 今回はHello Worldを表示するだけのプログラム ● どっちもこれまで書いてきたプログラムをいじ るだけ
  • 9.
    ブートローダのプログラム ● 追加ファイル – なし ● 修正ファイル – elf.h,elf.c...メモリ上へのコピーとエントリ・ポ イント対応 – main.c...エントリ・ポイントからの起動を追加
  • 10.
    セグメントをRAMに展開する ● そのままRAMにコピーするだけ ● 以前セグメント情報を表示していた部分を消し て以下のコードを追加 ● コピー先がVAではなくPAになってる。VAでも問 題ないが、あくまで論理アドレスだからPAの方 を利用すべしとのこと memcpy((char *)phdr->physical_addr, (char *)header + phdr- >offset, phdr->file_size); memset((char *)phdr->physical_addr + phdr->file_size, 0, phdr->memory_size - phdr->file_size);
  • 11.
    エントリ・ポイントを取得 ● main.cで呼び出すエントリ・ポイントを返す関 数。ELFファイルのチェックとロードも行われ ている char *elf_load(char *buf) { struct elf_header *header = (struct elf_header * )buf; if (elf_check(header) < 0) return NULL; if (elf_load_program(header) < 0) return NULL; return (char *)header->entry_point; }
  • 12.
    OSのプログラム ● 追加ファイル – defines.h...ブートローダと同じ – lib.h,lib.c...ブートローダと同じ – serial.h,serial.c...ブートローダと同じ – startup.s...ブートローダと同じ – main.c...新しく作成。Hello Worldを表示 – ld.scr...OS側用のリンカ – Makefile ● これらのファイルは、~/12step/src/06/os以下 に保存
  • 13.
    プログラム修正 ● main.c – 初期化関数を全て削除 ● データ領域のコピ、BSS領域のクリア、シリア ル・デバイスの初期化はブートローダ側でする ことになったので ● ld.scr – 全てram上に配置されるように変更 ● Makefile – 不要な部分を削除
  • 14.
    OS側のエントリ・ポイント ● OS側のエントリ・ポイントは、ld.scrの ENTRY(“_start”)により、startup.sの_start ラベルの位置をエントリ・ポイントとしてELF ヘッダが作成 ● ブートローダのf()の呼び出しが、OS側の _startの位置から動作を開始することになる ● ブートローダのld.scrにもENTRY(“_start”) はあるが、実はこれは特に意味はない – リセット・ベクタから起動してるから
  • 15.
    プログラム実行 ● osディレクトリでmakeして、それからbootload ディレクトリでmake、make image、make write してからのログ /Users/sandai/12step/src/06/os% sudo cu -l /dev/tty.usbserial-FTG6PQ4H Password: Connected. kzload (kozos boot loader) started. kzload> load ~+lsx kozos Sending kozos, 11 blocks: Give your local XMODEM receive command now. Bytes Sent: 1536 BPS:220 Transfer complete XMODEM receive succeeded! kzload> run starting from entry point: ffc020 Hello World! > echo aaa aaa
  • 16.
    補足 ● もしosのld.scrで.text.startupの部分を削除 していなかったら、エントリ・ポイントのアド レス位置は違うので注意 ● なんなんだろうねこれ。よくわからんわ
  • 17.
  • 18.
    まとめ ● ブートローダとOSを作成した – OSというか、Hello Worldのプログラム ● ブートローダ側とOS側でスタックとかかぶって るけどいいのかな? – ああ、あれか。スタックだもんな。関数抜け たら全部なくなるから、一緒のとこつかえば いいか ● とりあえずブートローダの仕組みがわかったの でよかった ● 書籍ではまだCPUの動作原理という話が続く が、ここでは省略する