5

nasm で単純な x86 Linux ブートローダーを構築しようとしています。

Linux bzImage は、最初のセクターから始まるディスク パーティション sda1 に保存されます。

bzImage (15 セクター) からリアル モード コードを 0x7E00 からメモリに読み込みます。ただし、コードに飛び込むとハングするだけで、何も起こりません。

sda のマスター ブート レコードのコードを作成しました。全部貼るだけでいいのかな。far jump命令の後にハングする理由を知りたいです。

[BITS 16]

%define BOOTSEG 0x7C0 
%define BOOTADDR (BOOTSEG * 0x10)

%define HDRSEG (BOOTSEG + 0x20)
%define HDRADDR (HDRSEG * 0x10)

%define KERNSEG (HDRSEG + 0x20)

[ORG BOOTADDR]
entry_section:
    cli
    jmp     start
start:
    ; Clear segments
    xor     ax, ax
    mov     ds, ax  
    mov     es, ax
    mov     gs, ax
    mov     fs, ax
    mov     ss, ax
    mov     sp, BOOTADDR    ; Lots of room for it to grow down from here

    ; Read all 15 sectors of realmode code in the kernel
    mov     ah, 0x42
    mov     si, dap
    mov     dl, 0x80
    int     0x13
    jc  bad

    ; Test magic number of kernel header
    mov     eax, dword [HDRADDR + 0x202]
    cmp     eax, 'HdrS'
    jne     bad

    ; Test jump instruction is there
    mov     al, byte [KERNSEG * 16]
    cmp     al, 0xEB
    jne     bad

    xor     ax, ax      ; Kernel entry code will set ds = ax
    xor     bx, bx      ; Will also set ss = dx
    jmp     dword KERNSEG:0

; Simple function to report an error and halt
bad:
    mov     al, "B"
    call    putc
    jmp     halt

; Param: char in al 
putc:
    mov     ah, 0X0E    
    mov     bh, 0x0F
    xor     bl, bl  
    int     0x10
    ret

halt:
    hlt
    jmp     halt

; Begin data section
dap:                ; Disk address packet
    db  0x10            ; Size of dap in bytes
    db  0               ; Unused
    dw  15              ; Number of sectors to read
    dw  0               ; Offset where to place data
    dw  HDRSEG          ; Segment where to place data
    dd  0x3F            ; Low order of start addres in sectors
    dd  0               ; High order of start address in sectors

; End data section

times 446-($-$$) db 0   ; Padding to make the MBR 512 bytes

; Hardcoded partition entries
part_boot:
    dw 0x0180, 0x0001, 0xFE83, 0x3c3f, 0x003F, 0x0000, 0xF3BE, 0x000E
part_sda2:
    dw 0x0000, 0x3D01, 0xFE83, 0xFFFF, 0xF3FD, 0x000E, 0x5AF0, 0x01B3
part_sda3:
    dw 0xFE00, 0xFFFF, 0xFE83, 0xFFFF, 0x4EED, 0x01C2, 0xb113, 0x001D
part_sda4:
    dw 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000

dw 0xAA55   ; Magic number at relative address 510
mbrend:     ; Relative address 512
4

2 に答える 2

1

コードがブートローダーであると仮定します (したがって、MBR ではありません):

  • 必要がない限り、IRQ を無効にしないでください。BIOS は、正しく機能するためにそれらを必要とし、何らかの BIOS 機能内でそれらを有効にします (たとえば、ディスク機能内の「セクター転送」IRQ を待機します)。あなたのコードはよりリアルなモードのコードを読み込んで制御を渡すだけなので (たとえば、保護モードへの切り替えなどは関係ありません)、ブート ローダー全体のどこでも IRQ を無効にする理由はありません。
  • リアル モードのアドレス指定では、通常、0x07C0:0x0000 よりも 0x0000:0x7C00 を使用する方がクリーンで簡単です。両方を混在させようとしているようです (たとえば、前者にはセグメント レジスタを設定し、後者には BOOTSEG と HDRSEG を定義します)。
  • パーティションテーブルには「プライマリパーティション」ではなく「拡張パーティション」が含まれているため、パーティションテーブルは間違っています(おそらく空白/空である必要があります)。
  • ブート ローダーは、特定の/ハードコードされた「開始 LBA」を想定しないでください (パーティションの「開始 LBA」は、OS のインストール時にエンド ユーザーがどのようにディスクをパーティション分割したいかによって異なります)。MBR のプライマリ パーティション テーブルからパーティションの「開始 LBA」を特定する必要があります。これは通常、MBR がパーティションのパーティション テーブル エントリを指している DS:SI を離れることを期待して行われます。
  • 「BIOS デバイス 0x80」から起動していると想定しないでください。MBR は DL を正しいデバイス番号に設定したままにする必要があり、(たとえば) OS が 2 番目のハード ドライブなどにインストールされている場合にコードが機能しない理由はありません。
  • ハードコーディングされた「読み取りを開始する LBA」(DAP 内) が間違っています。歴史的な理由から、トラックごとにおそらく 63 のセクターがあり、パーティションは 64 番目のセクターから始まります。これは、LBA セクター 0x3F がパーティション (ブートローダー) の最初のセクターであり、カーネルの最初のセクターではないことを意味します。カーネルの最初のセクターは LBA セクター 0x40 (パーティションの 2 番目のセクター) であると想定しています。
  • 「セクター数」もハードコーディングしないでください。カーネルの先頭をロードして調べ、そこからロードするセクターの数を決定します。
  • 通常、512 バイト (実際には 446 バイトに近い) は、まともなブートローダーには少なすぎます。ブート ローダーの最初の 512 バイトは、ブート ローダーの残りの部分をロードする必要があります (残りのすべてのスペア バイトは、エラー処理を改善するために使用されます。たとえばputs("Read error while trying to load boot loader")putc('B'). 他のすべて (カーネルの断片のロード、ビデオ モードの設定、「リアル モード カーネル ヘッダー」フィールドでの正しい値の設定など) は、最初のセクターではなく、追加のセクターにある必要があります。

コンピューターの起動方法は、すべての MBR が任意のディスクの任意のパーティションに任意の OS をチェーンロードできるように慎重に設計されていることに注意してください。また、MBR は、複数の OS をインストールできる大きなもの (ブート マネージャーなど) の一部である場合があります (たとえば、ユーザーがプリティ メニューまたは何かを使用して、MBR のコードがチェーンロードするパーティションを選択できる場合)。この設計により、ユーザーは、インストールされている OS に影響を与えることなく (または、インストールされているすべての OS を修正する必要が生じることなく)、いつでも MBR (またはブート マネージャー) を他のものに置き換えることができます。簡単な例として、ユーザーは 12 の異なるパーティションを持つことができ、そのすべてにブート ローダーと Linux の別の/独立したバージョンが含まれており、ブート マネージャー (GRUB、Plop、GAG、MasterBooter など) をインストールする必要があります。いつでも欲しい。

コードがハングする理由については、とにかくすべてのコードを書き直す必要があることを考えると、それほど重要ではありません。興味がある場合は、デバッガー (Bochs など) を備えたエミュレーター内で実行することを強くお勧めします。これにより、何が起こったのかを正確に調べることができます (たとえば、メモリを 0x00007E00 にダンプして内容を確認し、JMP を 1 ステップ実行して何が実行されているかを確認するなど)。

于 2013-02-02T21:24:39.747 に答える
1

コメントがコードと一致しません!

xor bx, bx ; Will also set ss = dx

それがあなたの問題かどうかは真剣に疑問です...

免責事項:私はこれを行っていません!私は「ニワトリ」で、いつもフロッピーからブートしてきました。

私が MBR で見られると「期待」しているのは、それ自体が邪魔にならないように移動し、アクティブなパーティションの最初のセクターを再び 7C00h にロードしてから、そこにジャンプすることです。この「実際のブートローダー」が残りをロードします。私は bzImage のレイアウトに慣れていません - おそらく 7E00h で読み込まれるでしょう...

私は私の頭の上にいると思います。コートを着せてあげる...

于 2013-02-02T15:17:41.717 に答える