最小マルチブートブートローダー

この記事では、マルチブート標準を使用して最小限のオペレーティングシステムカーネルを作成する方法について説明します。 実際、画面にロードしてOK



を印刷するだけOK



。 将来の記事では、 Rust



プログラミング言語を使用して拡張します。







私はすべてを詳細に説明し、コードをできる限りシンプルにしようとしました。 質問、提案、または問題がある場合は、 GitHub



コメントを残すか、タスク作成GitHub



。 ソースコードはリポジトリで利用可能です













復習



コンピュータの電源を入れると、特別なフラッシュメモリからBIOSがロードされます。 BIOS



はセルフテストとハードウェア初期化テストを実行し、起動可能なデバイスを検索します。 少なくとも1つが見つかった場合、制御はブートローダーに転送されます。ブートローダーは、ストレージデバイスの先頭に格納されている実行可能コードのごく一部です。 ブートローダーは、デバイス上のカーネルイメージの場所を特定し、それをメモリにロードします。 また、x86プロセッサはデフォルトで非常に限られたリアルモードで起動するため(1978年のプログラムと互換性があるため)、プロセッサをいわゆるプロテクトモードに切り替える必要があります。







これはそれ自体が複雑なプロジェクトであるため、ローダーを作成しません(実際にこれを実行したい場合は、 ここ読んでください )。 代わりに、 多くのテスト済みブートローダーの 1つを使用して、CD-ROMからカーネルをブートします。 しかし、どれですか?







マルチブート



幸いなことに、ブートローダーの標準、マルチブート仕様があります。 コアは、仕様をサポートし、互換性のあるブートローダーがそれをロードできることを示すだけです。 Multiboot 2



仕様を使用します( PDF

有名なブートローダーGRUB 2とともに。







ブートローダーに



Multiboot 2



サポートを知らせるには、カーネルを次の形式の



で開始する必要があります。







野原 種類 価値
マジックナンバー u32 0xE85250D6



建築 u32 i386の場合は0



、MIPSの場合は4



ヘッダー長 u32 タグを含む合計ヘッダーサイズ
チェックサム u32 -( + + )



タグ 可変
終了タグ (u16、u16、u32) (0, 0, 8)





x86アセンブラーに変換すると、次のようになります( Intel



構文):







 section .multiboot_header header_start: dd 0xe85250d6 ;   (multiboot 2) dd 0 ;  0 (  i386) dd header_end - header_start ;   ;   dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start)) ;   `multiboot`   ;    dw 0 ;  dw 0 ;  dd 8 ;  header_end:
      
      





x86アセンブラーがわからない場合は、簡単な紹介を次に示します。









nasm



を使用して、このファイル( multiboot_header.asm



と呼びます)を既にコンパイルできます。







`archlinux`にnasmをインストールする
 [loomaclin@loomaclin ~]$ yaourt nasm 1 extra/nasm 2.13.02-1 An 80x86 assembler designed for portability and modularity 2 extra/yasm 1.3.0-2 A rewrite of NASM to allow for multiple syntax supported (NASM, TASM, GAS, etc.) 3 aur/intel2gas 1.3.3-7 (3) (0.20) Converts assembly language files between NASM and GNU assembler syntax 4 aur/nasm-git 20150726-1 (1) (0.00) 80x86 assembler designed for portability and modularity 5 aur/sasm 3.9.0-1 (18) (0.61) Simple crossplatform IDE for NASM, MASM, GAS, FASM assembly languages 6 aur/yasm-git 1.3.0.r30.g6caf1518-1 (0) (0.00) A complete rewrite of the NASM assembler under the BSD License ==> Enter n° of packages to be installed (eg, 1 2 3 or 1-3) ==> --------------------------------------------------------- ==> 1 [sudo] password for loomaclin: resolving dependencies... looking for conflicting packages... Packages (1) nasm-2.13.02-1 Total Download Size: 0.34 MiB Total Installed Size: 2.65 MiB :: Proceed with installation? [Y/n] :: Retrieving packages... nasm-2.13.02-1-x86_64 346.0 KiB 1123K/s 00:00 [#############################################################################] 100% (1/1) checking keys in keyring [#############################################################################] 100% (1/1) checking package integrity [#############################################################################] 100% (1/1) loading package files [#############################################################################] 100% (1/1) checking for file conflicts [#############################################################################] 100% (1/1) checking available disk space [#############################################################################] 100% :: Processing package changes... (1/1) installing nasm [#############################################################################] 100% :: Running post-transaction hooks... (1/1) Arming ConditionNeedsUpdate... [loomaclin@loomaclin ~]$ nasm --version NASM version 2.13.02 compiled on Dec 10 2017 [loomaclin@loomaclin ~]$
      
      





次のコマンドはフラットバイナリファイルを生成し、結果のファイルには24バイトが含まれます(x86マシンで作業している場合はlittle endian



)。







 [loomaclin@loomaclin ~]$ cd IdeaProjects/ [loomaclin@loomaclin IdeaProjects]$ mkdir a_minimal_multiboot_kernel [loomaclin@loomaclin IdeaProjects]$ cd a_minimal_multiboot_kernel/ [loomaclin@loomaclin a_minimal_multiboot_kernel]$ nano multiboot_header.asm [loomaclin@loomaclin a_minimal_multiboot_kernel]$ nasm multiboot_header.asm [loomaclin@loomaclin a_minimal_multiboot_kernel]$ hexdump -x multiboot_header 0000000 50d6 e852 0000 0000 0018 0000 af12 17ad 0000010 0000 0000 0008 0000 0000018 [loomaclin@loomaclin a_minimal_multiboot_kernel]$
      
      





ブートコード



カーネルをロードするには、ローダーが呼び出すことができるコードを追加する必要があります。 boot.asm



ファイルを作成しましょう。







 global start section .text bits 32 start: ;  `OK`   mov dword [0xb8000], 0x2f4b2f4f hlt
      
      





ここにはいくつかの新しいコマンドがあります:









組み立て、表示、および分解した後、プロセッサのオペコードが動作しているのがわかります。







 [loomaclin@loomaclin a_minimal_multiboot_kernel]$ nano boot.asm [loomaclin@loomaclin a_minimal_multiboot_kernel]$ nasm boot.asm [loomaclin@loomaclin a_minimal_multiboot_kernel]$ hexdump -x boot 0000000 05c7 8000 000b 2f4f 2f4b 00f4 000000b [loomaclin@loomaclin a_minimal_multiboot_kernel]$ ndisasm -b 32 boot 00000000 C70500800B004F2F mov dword [dword 0xb8000],0x2f4b2f4f -4B2F 0000000A F4 hlt [loomaclin@loomaclin a_minimal_multiboot_kernel]$
      
      





実行可能ファイルを作成する



後でGRUB



を介して実行可能ファイルをダウンロードするには、 ELF



実行可能ファイルでなければなりません。 したがって、単純なバイナリの代わりにnasm



を使用してELF



オブジェクトファイルを作成する必要があります。 これを行うには、単に引数に-f elf64



を追加します。







ELF



実行可能コード自体を作成するには、オブジェクトファイルをリンクする必要があります。 linker.ld



と呼ばれるリンク用のカスタムスクリプトを使用します。







 ENTRY(start) SECTIONS { . = 1M; .boot : { /*      */ *(.multiboot_header) } .text : { *(.text) } }
      
      





人間の言語で書かれたものを翻訳しましょう:









ELF



オブジェクトファイルを作成し、上記のリンカースクリプトを使用してリンクします。







 [loomaclin@loomaclin a_minimal_multiboot_kernel]$ nasm -f elf64 multiboot_header.asm [loomaclin@loomaclin a_minimal_multiboot_kernel]$ nasm -f elf64 boot.asm [loomaclin@loomaclin a_minimal_multiboot_kernel]$ ld -n -o kernel.bin -T linker.ld multiboot_header.o boot.o [loomaclin@loomaclin a_minimal_multiboot_kernel]$
      
      





-n



(または--nmagic



)フラグをリンカーに渡すことが非常に重要です。これにより、実行可能ファイル内の自動セクションアライメントが無効になります。 そうしないと、リンカは実行可能ファイルの.boot



セクションのページを整列させる場合があります。 これが発生すると、 GRUB



はマルチブートヘッダーを見つけることができなくなります。これは、先頭にないためです。







objdump



コマンドを使用して、生成された実行可能ファイルのセクションを表示し、 .boot



セクションにファイル内の最小オフセットがあることを確認します。







 [loomaclin@loomaclin a_minimal_multiboot_kernel]$ objdump -h kernel.bin kernel.bin: file format elf64-x86-64 Sections: Idx Name Size VMA LMA File off Algn 0 .boot 00000018 0000000000100000 0000000000100000 00000080 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .text 0000000b 0000000000100020 0000000000100020 000000a0 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE [loomaclin@loomaclin a_minimal_multiboot_kernel]$
      
      





注: ld



およびobjdump



コマンドはプラットフォームに依存しています。 x86_64アーキテクチャで作業していない場合、 binutilsクロスコンパイルする必要があります 。 その後、 x86_64‑elf‑ld



およびx86_64‑elf‑objdump



代わりに、それぞれx86_64‑elf‑ld



およびx86_64‑elf‑objdump



使用します。


ISOイメージの作成



すべてのBIOS



ベースのパーソナルコンピューターはCD-ROMから起動する方法を知っているため、カーネルとGRUB



ブートローダーファイルを含むブート可能なCD-ROMイメージをISOと呼ばれる単一のファイルに作成する必要があります。 次のディレクトリ構造を作成し、 kernel.bin



boot



ディレクトリにコピーしboot









 isofiles └── boot ├── grub │ └── grub.cfg └── kernel.bin
      
      





grub.cfg



は、カーネルファイル名とmultiboot 2



との互換性を示します。 次のようになります。







 set timeout=0 set default=0 menuentry "my os" { multiboot2 /boot/kernel.bin boot }
      
      





コマンドを実行します。







 [loomaclin@loomaclin a_minimal_multiboot_kernel]$ mkdir isofiles [loomaclin@loomaclin a_minimal_multiboot_kernel]$ mkdir isofiles/boot [loomaclin@loomaclin a_minimal_multiboot_kernel]$ mkdir isofiles/boot/grub [loomaclin@loomaclin a_minimal_multiboot_kernel]$ cp kernel.bin isofiles/boot/ [loomaclin@loomaclin a_minimal_multiboot_kernel]$ nano grub.cfg [loomaclin@loomaclin a_minimal_multiboot_kernel]$ cp grub.cfg isofiles/boot/grub/
      
      





次のコマンドを使用して、起動可能なイメージを作成できます。







 [loomaclin@loomaclin a_minimal_multiboot_kernel]$ grub-mkrescue -o os.iso isofiles xorriso 1.4.8 : RockRidge filesystem manipulator, libburnia project. Drive current: -outdev 'stdio:os.iso' Media current: stdio file, overwriteable Media status : is blank Media summary: 0 sessions, 0 data blocks, 0 data, 7675m free Added to ISO image: directory '/'='/tmp/grub.jN4u6m' xorriso : UPDATE : 898 files added in 1 seconds Added to ISO image: directory '/'='/home/loomaclin/IdeaProjects/a_minimal_multiboot_kernel/isofiles' xorriso : UPDATE : 902 files added in 1 seconds xorriso : NOTE : Copying to System Area: 512 bytes from file '/usr/lib/grub/i386-pc/boot_hybrid.img' ISO image produced: 9920 sectors Written to medium : 9920 sectors at LBA 0 Writing to 'stdio:os.iso' completed successfully.
      
      





注:一部のプラットフォームでは、 grub-mkrescue



呼び出すと問題が発生する場合があります。 うまくいかなかった場合は、次の手順を試してください。

  • --verbose



    てコマンドを実行し、
  • xorriso



    ライブラリxorriso



    インストールされていることを確認してxorriso



    xorriso



    またはlibisoburn



    パッケージ)。




`Archlinuxに` libisoburn`を置かなければならなかった

[loomaclin @ loomaclin a_minimal_multiboot_kernel] $ yaourt xorriso

1個の追加/ libisoburn 1.4.8-2

ライブラリlibburnおよびlibisofsのフロントエンド

==>インストールするパッケージのn°を入力します(例:1 2 3または1-3)

==>-==> 1







[sudo] loomaclinのパスワード:

依存関係の解決...

競合するパッケージを探しています...







パッケージ(3)libburn-1.4.8-1 libisofs-1.4.8-1 libisoburn-1.4.8-2







合計ダウンロードサイズ:1.15 MiB

合計インストールサイズ:3.09 MiB







::インストールを続行しますか? [Y / n]

::パッケージの取得...

libburn-1.4.8-1-x86_64 259.7 KiB 911K / s 00:00 [################################## ##################################################] 100%

libisofs-1.4.8-1-x86_64 237.8 KiB 2.04M / s 00:00 [################################ ###################################################]] 100%

libisoburn-1.4.8-2-x86_64 683.8 KiB 2.34M / s 00:00 [################################ ###################################################]] 100%

(3/3)キーリングのキーをチェックする[############################################# ###########################################] 100%

(3/3)パッケージの整合性のチェック[############################################ #########################################] 100%

(3/3)パッケージファイルの読み込み[############################################# #########################################] 100%

(3/3)ファイルの競合のチェック[############################################# ###########################################] 100%

(3/3)利用可能なディスク容量[############################################ ###########################################] 100%

::パッケージ変更の処理...

(1/3)libburn [#############################################のインストール######################################] 100%

(2/3)libisofs [###############################################のインストール######################################] 100%

(3/3)libisoburnのインストール









読み込み中



OSをダウンロードします。 これを行うには、 QEMUを使用します。







 [loomaclin@loomaclin a_minimal_multiboot_kernel]$ qemu-system-x86_64 -cdrom os.iso (qemu-system-x86_64:10878): Gtk-WARNING **: Allocating size to GtkScrollbar 0x7f2337e5a280 without calling gtk_widget_get_preferred_width/height(). How does the code know the size to allocate? (qemu-system-x86_64:10878): Gtk-WARNING **: Allocating size to GtkScrollbar 0x7f2337e5a480 without calling gtk_widget_get_preferred_width/height(). How does the code know the size to allocate? (qemu-system-x86_64:10878): Gtk-WARNING **: Allocating size to GtkScrollbar 0x7f2337e5a680 without calling gtk_widget_get_preferred_width/height(). How does the code know the size to allocate?
      
      





エミュレータウィンドウが表示されます:

エミレータウィンドウ







左上隅にある緑色のテキストOK



に注意してください。 これがうまくいかない場合は、コメントのセクションをご覧ください。







何が起こったのかをまとめます:







  1. BIOSは、仮想CD-ROM(ISO)からブートローダー(GRUB)をロードします。
  2. ブートローダーはカーネル実行可能コードを読み取り、マルチブートヘッダーを見つけました。
  3. .boot



    および.text



    .boot



    をメモリにコピーしました( 0x100000



    および0x100020



    )。
  4. エントリポイントに移動しました( 0x100020



    、これはobjdump -f



    呼び出すことで見つけることができます)。
  5. カーネルはテキストOK



    緑色で表示し、プロセッサを停止しました。


これを実際のハードウェアでテストすることもできます。 結果のイメージをディスクまたはUSBドライブに書き込み、そこから起動する必要があります。







ビルドの自動化



ここで、ファイルを変更するたびに4つのコマンドを正しい順序で呼び出す必要があります。 これは悪いです。 Makefileを使用してこのプロセスを自動化しましょう。 ただし、最初に、適切なディレクトリ構造を作成して、アーキテクチャ依存のファイルを分離する必要があります。







 … ├── Makefile └── src └── arch └── x86_64 ├── multiboot_header.asm ├── boot.asm ├── linker.ld └── grub.cfg
      
      





私たちは作成します:







 [loomaclin@loomaclin a_minimal_multiboot_kernel]$ mkdir -p src/arch/x86_64 [loomaclin@loomaclin a_minimal_multiboot_kernel]$ cp multiboot_header.asm src/arch/x86_64/ [loomaclin@loomaclin a_minimal_multiboot_kernel]$ cp boot.asm src/arch/x86_64/ [loomaclin@loomaclin a_minimal_multiboot_kernel]$ cp linker.ld src/arch/x86_64/ [loomaclin@loomaclin a_minimal_multiboot_kernel]$ cp grub.cfg src/arch/x86_64/ [loomaclin@loomaclin a_minimal_multiboot_kernel]$ nano Makefile
      
      





メイクファイルは次のようになります。







 arch ?= x86_64 kernel := build/kernel-$(arch).bin iso := build/os-$(arch).iso linker_script := src/arch/$(arch)/linker.ld grub_cfg := src/arch/$(arch)/grub.cfg assembly_source_files := $(wildcard src/arch/$(arch)/*.asm) assembly_object_files := $(patsubst src/arch/$(arch)/%.asm, \ build/arch/$(arch)/%.o, $(assembly_source_files)) .PHONY: all clean run iso all: $(kernel) clean: @rm -r build run: $(iso) @qemu-system-x86_64 -cdrom $(iso) iso: $(iso) $(iso): $(kernel) $(grub_cfg) @mkdir -p build/isofiles/boot/grub @cp $(kernel) build/isofiles/boot/kernel.bin @cp $(grub_cfg) build/isofiles/boot/grub @grub-mkrescue -o $(iso) build/isofiles 2> /dev/null @rm -r build/isofiles $(kernel): $(assembly_object_files) $(linker_script) @ld -n -T $(linker_script) -o $(kernel) $(assembly_object_files) # compile assembly files build/arch/$(arch)/%.o: src/arch/$(arch)/%.asm @mkdir -p $(shell dirname $@) @nasm -felf64 $< -o $@
      
      





コメント(以前にmakeを使用したことがない場合は、 makefileチュートリアルをご覧ください ):









これでmake



を呼び出すmake



ができ、更新されたすべてのアセンブラファイルがコンパイルおよびリンクされます。 make iso



コマンドもISOイメージを作成し、 make run



がQEMUを起動します。







次は?



次の記事では、ページテーブルを作成し、プロセッサ構成を実行して64ビットロングモードモードに切り替えます。







注釈



  1. 表の式-(magic + architecture + header_length)



    は、32ビットに収まらない負の値を作成します。 0x100000000



    から減算することにより、減算した値を変更せずに値を正のままにします。 その結果、追加の符号ビットなしで、結果は32ビットに配置され、コンパイラは満足です:)
  2. メモリの多くの特定の領域は1メガバイトマークまで配置できるため、オフセット0x0でカーネルをロードする必要はありません(たとえば、画面にOK



    を表示するために使用する0xb8000



    いわゆるVGAバッファー)。



All Articles