これは実際の操作システムではありません。これは、教育目的で作成された単純な操作システムです。
私がフォローしている主な目標は、OSがゼロからどのように機能しているかを学ぶことです。独自のブートセクター、ハードウェア、ソフトウェアの割り込み、独自のドライバーから始めます。
リポジトリにはGCCが接着されています。なぜなら、錆びた別の簡単なOSを書くことを計画しているからです。ですから、 Ghaiklor-os-gccとGhaiklor-os-rustcがあることを願っています。
| こんにちは世界 |
|---|
Ghaiklor-OS-GCCは、生のバイナリ形式の2つのファイルで構成されています: boot.binおよびkernel.bin 。それらは、コンパイル後にそれに応じて、ブート/ブート、ビン/カーネル/カーネル。ビンにあります。
boot.binはNASMを介してコンパイルされます。 MakeFileはBoot/Boot.asmを取り、 nasm boot/boot.asm -f bin -o boot/boot.binを呼び出します。 NASMハンドルにはサブフォルダー自体から含まれるため、すべてのアセンブリファイルがバイナリにコンパイルされます。他に何も、簡単です。
Kernel.binは、インストールする必要があるクロスコンパイラGCCおよびLDを介してコンパイルされています。開発環境セクションをご覧ください。クロスコンパイラーがインストールされた後、 CPU 、ドライバー、含まれる、カーネルおよびLIBCフォルダーのソースを再帰的に取得できます。すべての.cファイルはgccを介してコンパイルされます。コンパイルされたオブジェクトファイルは、 kernel.binをコンパイルするために使用されます。その後、 Ld ld -o kernel/kernel.bin -Ttext 0x1000 <OBJ_FILES> --oformat binaryを介して使用されます。
os-image.bin isコンパイルboot.binおよびkernel.binの連結塩。 cat boot/boot.bin kernel/kernel.bin > os-image.binで簡単に達成できます。
私はあなたが実行できることをbootstrap.shスクリプトに書きました。ホストマシンに必要なすべての依存関係をインストールします。
bash bootstrap.shコンピューターがオンまたはリセットされると、Post-Power-on-Self-Testと呼ばれる一連の診断を実行します。このシーケンスは、フロッピー、CDROM、ハードディスクなどの起動可能なデバイスを見つけるのに頂点に達します。
デバイスは、それぞれバイト511と512でバイトシーケンス0x55 0xAA備えたブートセクターを搭載している場合に起動できます。 BIOSがそのようなブートセクターを見つけると、 0x0000:0x7C00にメモリにロードされます。
ブート可能なデバイスの簡単な実装:
jmp $
times 510 - ($ - $$) db 0
dw 0xAA55 $ - $$はCURRENT_POINTER - START_POINTERで結果を得ます。そうすれば、ブートレコードの長さを計算しています。その後、私たちはそこから510を覆い、ゼロで満たし、ブートセクターの署名で512バイトのブートレコードを取得します。
たとえば、100に等しい$ - $$があります。したがって、 510 - 100 = 410フリーバイトがあります。これらの410バイトにゼロを埋めています。最後の2バイト511と512は、 dw 0xAA55で満たされている起動可能な署名です。
終わり!起動可能なデバイスがあり、 jmp $好きなコードに置き換えることができます。
ブートセクターの実装
当初、コードは実際のモードで実行されています。
実際のモードは、すべてのX86プロセッサに存在する単純な16ビットモードです。実際のモードは最初のX86モード設計であり、多くの初期オペレーティングシステムで使用されました。互換性のために、すべてのX86プロセッサが実際のモードで実行を開始します。
実際のモードでは何が悪いのですか?
短所
長所
実際のモードにある多くの制限と問題があるため、保護モードに切り替える必要があります。
保護モードは、80286以来の最新のIntelプロセッサの主要な動作モードです。それぞれが最大4 GBのアドレス可能なメモリを持ついくつかの仮想アドレススペースを操作できます。
BIOSによって初期化されたCPUは実際のモードで開始されるため、保護されたモードに切り替えると、ほとんどのBIOS割り込みの使用が妨げられます。保護モードに切り替える前に、NMI、A20ラインの有効化、グローバル記述子テーブルをロードするなど、割り込みを無効にする必要があります。
保護モードに切り替えるためのアルゴリズム:
cli
lgdt [ gdt_descriptor ]
mov eax , cr0
or eax , 0x1
mov cr0 , eax
jmp CODE_SEG:init_pmPMに切り替えるための実装
グローバル記述子テーブル
しかし、私たちはさらに進むことができます...
ロングモードとは何ですか、そしてなぜそれをセットアップするのですか?
X86-64プロセッサの導入以来、ロングモードと呼ばれる新しいモードも導入されています。ロングモードは、基本的に、実際の64ビットモードと互換モード(32ビット)である2つのサブモードから構成されています。
私たちが興味を持っているのは、このモードが次のような多くの新機能を提供するため、単に64ビットモードです。
ロングモードに切り替える前に、CPUがこのモードをサポートしているかどうかを確認する必要があります。場合によっては、CPUがロングモードをサポートしていない場合、保護モードにフォールバックする必要があります。
ロングモードがサポートされているかどうかを検出します
その場合は、ロングモードに切り替えます
これらのモードはすべて素晴らしいですが、512バイトでオペレーティングシステムを書き込むことはできません。したがって、私たちのブートセクターは、コンパイルされたカーネルをハードディスクからロードする方法を知っている必要があります。
実際のモードの場合、ディスクから読み取りにBIOS割り込みを使用できます。私たちの場合、 INT 13,2 - Read Disk Sectors 。
それを使用する方法は?
;; al = number of sectors to read (1 - 128)
;; ch = track/cylinder number
;; cl = sector number
;; dh = head number
;; dl = drive number
;; bx = pointer to buffer
mov ah , 0x02
mov al , 15
mov ch , 0x00
mov cl , 0x02
mov dh , 0x00
mov dl , 0
mov bx , KERNEL_OFFSET_IN_MEMORY
int 0x13このコードは、ハードディスクからアドレスのKERNEL_OFFSET_IN_MEMORYに読み取ります。 2番目のセクターから始まる15のセクターを読み取り、アドレスKERNEL_OFFSET_IN_MEMORYで保存します。
コンパイルされたOS画像はブートセクターとカーネルの連結であり、ブートセクターが512バイトであることがわかっているため、カーネルが第2セクターで始まることを確信できます。
読み取りが正常に完了したら、 KERNEL_OFFSET_IN_MEMORYで命令を呼び出して、カーネルに実行を行うことができます。
call KERNEL_OFFSET_IN_MEMORY
jmp $ディスク読み取りの実装
ここでは、ブートセクターについて線を引くことができます。フローは単純です:
call命令によりカーネルに実行を行います。このステップで、ブートセクターは作業を終了し、カーネルの作業を開始します。
ブートソースをナビゲートして、それがどのように機能するかを取得することができます。
アドレスで命令を呼び出すとき、いくつかの問題を抱えることがあります。住所によるその命令はkernel_main()です。解決策は簡単です。
カーネルコードの開始時に添付されているサブルーチンを書くことができます。カーネルkernel_main()のこのサブルーチンコールExtern関数。オブジェクトファイルがリンクされると、この呼び出しはkernel_main()の呼び出しに変換されます。
global _start
[bits 32]
[extern kernel_main]
_start:
call kernel_main
jmp $カーネルエントリの実装
このステップでは、 kernel_main()メソッドへのエントリポイントがあります。そして、それがカーネル全体のエントリポイントです。
#includeがどのように機能し、 kernel_main()で何が起こるかを説明するのは退屈だと思います。あなたは私がそれから呼んでいる方法に簡単に従うことができます。
cのカーネルエントリ
それが最も単純な部分です。
生のバイナリ形式でboot/boot.bin Imageを構築する必要があります。そうするために、特別なフラグを持つnasmアセンブラーを呼び出します。
nasm boot/boot.asm -f bin -o boot/boot.binQEMU経由で実行できる生のバイナリ形式になります。
このステップでは、ブートセクターをまとめた作業を行っています。
bootフォルダーを除き、すべてのフォルダーからすべてのソースを再帰的に構築する必要があります。
すべてのCファイルは、 gccおよびAssemblyファイルを介してnasmを介してオブジェクトファイルにコンパイルされます。
gcc -g -ffreestanding -Wall -Wextra -fno-exceptions -m32 -std=c11 -c < SOURCE > -o < OBJ_FILE >
nasm < SOURCE > -f elf -o < OBJ_FILE >生のバイナリ形式にリンクするために必要なすべてのオブジェクトファイルになります。残されているのは、 ldを介してそれらをリンクすることだけです:
ld -o kernel/kernel.bin -Ttext 0x1000 kernel/kernel_entry.o < OBJ_FILES > --oformat binary kernel_main()を呼び出すことに問題があるため、 kernel/kernel_entry.o最初に問題があることに注意してください。これにより、最初の命令がboot/kernel_entry.asmから呼び出されることを保証します。
結局のところ、カーネル画像を生のバイナリ形式でコンパイルしました。
ブートセクターとカーネルは生のバイナリ形式であるため、それらを連結するだけです。
cat boot/boot.bin kernel/kernel.bin > os-image.binこれで、 qemu-system-i386を介してos-image.binを実行できます。ブート可能なセクターを見つけようとしているBIOS、 boot/boot.binを見つけて、署名を見ます。 boot/boot.binでアセンブリコードの実行を開始します。binは、int 13,2を介してメモリにkernel/kernel.binをロードし、それを実行します。
それがすべて一緒に機能する方法です。プロジェクトを自由にナビゲートしてください、ありがとう?
MITライセンス(MIT)
Copyright(c)2016 Eugene Obrezkov
このソフトウェアと関連するドキュメントファイル(「ソフトウェア」)のコピーを入手して、制限なしにソフトウェアを扱うために、このソフトウェアを制限する権利を含め、ソフトウェアのコピーをコピー、変更、公開、配布、販売する、ソフトウェアのコピーを許可する人を許可する人を許可することを含めて、許可が無料で許可されます。
上記の著作権通知とこの許可通知は、ソフトウェアのすべてのコピーまたはかなりの部分に含まれるものとします。
このソフトウェアは、商品性、特定の目的への適合性、および非侵害の保証を含むがこれらに限定されない、明示的または黙示的なものを保証することなく、「現状のまま」提供されます。いかなる場合でも、著者または著作権所有者は、契約、不法行為、またはその他の訴訟、ソフトウェアまたはソフトウェアの使用またはその他の取引に関連する、またはその他の契約、またはその他の請求、またはその他の責任について責任を負いません。