5

最近、私は自分自身の本当に本当に基本的なOSを書くことに興味を持つようになりました。私はスタックを確立し、いくつかの基本的なことを行ういくつかの基本的なアセンブリを作成しました(まあ、コピーしました)。これはうまくいくように見えましたが、Cをミックスに導入しようとするとすべてが台無しになりました。

2つの主要なプロジェクトファイルがあります。スタックを作成してC関数を呼び出すNASMであるloader.sと、基本的なC関数を含むkernel.cです。

現時点での私の問題は、基本的に、kernel.binファイルを実行するとQEMUがフリーズすることです。私のコードにはいくつもの問題があると思います-おそらくこの質問は、その極端な特異性のためにStackOverflow形式には実際には適切ではありません。私のプロジェクトファイルは次のとおりです。

loader.s:

BITS 16                         ; 16 Bits

extern kmain                    ; Our 'proper' kernel function in C

loader:
    mov ax, 07C0h           ; Move the starting address [7C00h] into 'ax'
    add ax, 32              ; Leave 32 16 byte blocks [200h] for the 512 code segment
    mov ss, ax              ; Set 'stack segment' to the start of our stack
    mov sp, 4096            ; Set the stack pointer to the end of our stack [4096 bytes in size]

    mov ax, 07C0h           ; Use 'ax' to set 'ds'
    mov ds, ax              ; Set data segment to where we're loaded
    mov es, ax              ; Set our extra segment

    call kmain              ; Call the kernel proper

    cli                     ; Clear ints

    jmp $                   ; Hang


; Since putting these in and booting the image without '-kernel' can't find
; a bootable device, we'll comment these out for now and run the ROM with
; the '-kernel' flag in QEMU
        ;times 510-($-$$) db 0          ; Pad remained of our boot sector with 0s
        ;dw 0xAA55                      ; The standard 'magic word' boot sig

kernel.c:

#include <stdint.h>

void kmain(void)
{
        unsigned char *vidmem = (char*)0xB8000; //Video memory address
        vidmem[0] = 65; //The character 'A'
        vidmem[1] = 0x07; //Light grey (7) on black (0)
}

私はそのようにすべてをコンパイルします:

nasm -f elf -o loader.o loader.s

i386-elf-gcc -I / usr / include -o kernel.o -c kernel.c -Wall -nostdlib -fno-builtin -nostartfiles -nodefaultlibs

i386-elf-ld-Tリンカー.ld-okernel.binloader.o kernel.o

そして、そのようにテストします:

qemu-system-x86_64 -kernel kernel.bin

誰かが私のためにこれを見てくれることを願っています-コードスニペットはそれほど長くはありません。

ありがとう。

4

1 に答える 1

10

どこから始めますか?(リューズ、あなたですか?)

からのコードloader.sはマスター ブート レコード (MBR) に入ります。ただし、MBR には、ハード ドライブのパーティション テーブルも保持されます。したがって、 をアセンブルしたら、それを MBR とマージloader.sする必要があります: のコード、MBRのパーティション テーブル。コードを MBR にコピーしただけでは、ハード ドライブのパーティション分割が無効になります。マージを適切に行うには、パーティション テーブルが MBR のどこにあるかを正確に知る必要があります...loader.sloader.s

loader.sMBR に入るからの出力は、「第 1 段階のブートローダー」と呼ばれます。上記の理由により、最初の段階では 436 バイトしかありません。この時点でできないことの1 つは、その上に C コンパイラの出力をたたいて (つまり、バイナリを 1 セクタ (MBR) よりも大きくして)、それをハード ドライブにコピーすることです。古いハードドライブで一時的に機能する可能性がありますが、最新のものは、コピーによって破壊されるセクター1以降にさらに多くのパーティション情報を保持しています.

アイデアは、「第 2 段階」であるkernel.cのバイナリにコンパイルすることです。利用可能な 436 バイトの最初の段階では、BIOS (または EFI) を使用して、ハード ドライブの特定のポイントから 2 番目の段階を読み込みます (最初の段階にパーティション テーブルとファイル システムの解析を追加できないため)。ステージ) から、ロードしたばかりのコードにジャンプします。第 2 ステージは同じ種類のサイズ制限を受けていないため、適切な処理を行うことができます。つまり、パーティション情報を解析し、「ホーム」パーティションを見つけ、そのファイル システムを解析し、実際のパーティションをロードして解析します。カーネルバイナリ。

私がこれらすべてを地球低軌道から見ていることに気づいてほしい。ブートローディングは複雑なプロセスの 1 つであり、1 つの SO 投稿で詳細を説明することはできません。したがって、OSDevなど、これらの主題に特化した Web サイトがあります。ただし、注意してください。この種の開発には、経験豊富なプログラマー、プロ級の調査を行うことができ、賢明な方法で質問をし、自重を負うことができる人々が必要です。最近はこれらのスキルが一般的に低下しているため、OS 開発 Web サイトは、アプローチを誤ると不機嫌になりがちです (*)。

(*): または、私がこの投稿を終えたときに dwalter が行ったように、彼らはコメントなしのソースをあなたに投げつけます。;-)

編集:もちろん、これはエミュレータがフリーズする実際の理由ではありません。i386-elf-gcc は、32 ビット プロテクト モード用のコードを生成するコンパイラであり、「フラット」メモリ モデル、つまりゼロから始まるコード/データ セグメントを想定しています。あなたloader.sは16ビットのリアルモードコード(BITS 16部品で述べられているように)であり、プロテクトモードをアクティブにせず、セグメントレジスタをGCCが期待する値に初期化せず、FalseでGCCによって生成されたコードにジャンプします仮定... BAM。

于 2012-06-12T14:35:23.600 に答える