2015-12-11 8 views
7

にセクタをロードしている間、私はthisを使用して、ブートローダーを開発しようとしましたが、それが実行されたときには示していますディスク読み取りエラーメモリ

disk read error! 

私はそれを無視した場合、以降の部分では、それは間違ったメモリを私に示してマッピング。私はまた他のいくつかの情報源にも従っていましたが、無駄でした。彼らがやっていることをコピーしているような気がする。私が少しでも異なっていても、毎回新しい種類のエラーが発生します。

既にビルドされているブートローダを使用する必要がありますか?

ディスク負荷エラーのコードは以下の通りです:

[org 0x7c00] 

    KERNEL_OFFSET equ 0x1000  
    mov [BOOT_DRIVE], dl   
    mov bp, 0x9000   
    mov sp, bp 
    mov bx, MSG_REAL_MODE  
    call print_string   
    call load_kernel    
    jmp $ 

print_string: 
    pusha 
    mov ah, 0x0e 

loop: 
    mov al,[bx] 
    cmp al, 0 
    je return 
    int 0x10 
    inc bx 
    jmp loop 

return: 
    popa 
    ret 

disk_load: 
    push dx            
    mov ah, 0x02         
    mov al, dh           
    mov ch, 0x00          
    mov dh, 0x00          
    mov cl, 0x02          
    int 0x13           
    jc disk_error         
    pop dx            
    cmp dh, al           
    jne disk_error         
    ret 

disk_error : 
    mov bx, DISK_ERROR_MSG 
    call print_string 
    jmp $ 

DISK_ERROR_MSG db "Disk read error!", 0 

[bits 16] 

load_kernel: 
    mov bx, KERNEL_OFFSET  
    mov dh, 15   
    mov dl, [BOOT_DRIVE]      
    call disk_load             
    ret 

; Global variables 
BOOT_DRIVE  db 0 
MSG_REAL_MODE db "Started in 16-bit Real Mode", 0 

; Bootsector padding 
times 510-($-$$) db 0 
dw 0xaa55 

は、私は私のブートローダを組み立て、実行するには、このコマンドを使用します。

nasm boot.asm -f bin -o boot.bin && qemu-system-i386 boot.bin 

私はこの時点で動けなくなります。私のブートローダーはdisk read errorと表示されます。この時点で無視すると、kernel.cを実行している間に問題が発生します。間違ったメモリマッピングが使用されているようです。

+0

を "まとめ"! –

+0

プログラムの開始時に_DS_(データセグメント)が正しく設定されていないという問題があります。 SPも設定しますが、実際には有効な_SS_(スタックセグメント)を設定していません。これも問題を引き起こす可能性があります。 disk_loadでは、_ES_(拡張セグメント)を設定しません。これは、データが読み取られるメモリ位置が完全に指定されるように(ES:BXはアドレスバッファです)正しく設定する必要があります。 15セクタを読み取っている720kフロッピーディスクを作成している場合、トラック(シリンダ)の最大セクタが9であるため、動作しない可能性があります。これは読み込みの問題を引き起こす可能性があります。 –

+0

NASMがブートローダー用の16ビットコードをすべて生成することを知るために、[ビット16]を先頭に入れておくのも良い考えです。 –

答えて

5

「彼はリストを作って、彼が二度それをチェックしています...」

  • それは16を使用して、あなたのアセンブラを強制するのが最善の方法ですので、あなたのブートローダが、実アドレスモードで起動しますビットコード。あなたはプログラムの最上部に[bits 16]と書くことでNASMでこれを達成します。

  • ブートローダーが起動すると、BIOSはリニアアドレス00007C00hに配置します。これは、セグメントとオフセットの組み合わせに関して、さまざまな方法でこれを行うことができます。
    [org 0x7C00]を明示的に書いたときに、この組み合わせがセグメント部分をゼロにすると予想されました。しかし、これは決してBIOSの義務ではありません!したがって、セグメントレジスタ(DS、ES、SS)を手動で設定するのはあなた次第です。

  • print_stringルーチンで使用するBIOSテレタイプ機能は、BLとBHをパラメータとして使用します。だからあなたはあなたのテキストを扱うのにBXレジスタを使うべきではありません。確かに、一部のBIOSはBLとBHのパラメータを使用しませんが、それ以上のオーディエンスのためのプログラムを開発しようとします。

  • SPレジスタを0x9000で初期化すると、気付かないうちに簡単にそのスタックの下にあるプログラムを上書きすることができます。あなたのニーズを満たすSSとSPの組み合わせを選択するのが最善です。ブートセクタの上に7C00hであり、9000hで終了する4608バイトのスタックは、SS = 07E0h SP = 1200hを必要とします。 8086ハードウェアの問題を避けるには、SS:SPを変更するときに割り込みを無効にすることをお勧めします。

  • pushapopaの命令を使用しました。これらは8086ハードウェアの有効な命令ではありません。堅牢なソフトウェアを書くときは、ハードウェアがその作業に合っているかどうかをテストする必要があります。しかしここで最も簡単な解決策は、単一レジスタをプッシュ/ポップすることだけです。

  • あなたは、ディスクからの読み込み、BIOSの関数からの戻り値を解釈しているが、セクタの数が正しくありませんが、転送されたとき、あなただけの中止します。これは間違ったアプローチです。BIOSから不完全な転送が通知された場合(これは、BIOSがマルチトラック対応でない場合に発生する可能性があります)、残りのセクタ数を繰り返す必要があります。明らかに、次のヘッド、おそらく次のシリンダ、常にセクタ= 1のパラメータのいくつかを調整する必要があります。 (完璧なソリューションには、BIOSからディスクジオメトリを取得するか、またはディスク上に存在するBPBからディスクジオメトリを読み取ることが含まれます)。私は基本的な1.44 MBフロッピーの操作を想定していました。

  • ディスクからの読み取りが初めて成功しない場合は、何度も再試行する必要があります。 このような最初の失敗は完全に正常です。 5回の再試行は良い値です。その間に、diskdriveをリセットするBIOS関数を呼び出します。

  • QEMUがこれらの追加の15セクタを実際に読み取ることができるようにするには、合計16セクタ分の値を持つようにこのファイルを埋め込む必要があります。リンクしたtextもこれを行いました!

Plzは、このコードをチェックして、私を助けて

[bits 16] 
[org 0x7C00] 

KERNEL_OFFSET equ 0x1000 

xor ax, ax 
mov ds, ax 
mov es, ax  
mov [BOOT_DRIVE], dl 
mov ax, 0x07E0 
cli 
mov ss, ax 
mov sp, 0x1200 
sti 
mov si, MSG_REAL_MODE  
call print_string   
call load_kernel    
jmp $ 

print_string: 
    push ax 
    push bx 
    push si 
    mov bx, 0x0007 ;BL=WhiteOnBlack BH=Display page 0 
    mov ah, 0x0E ;Teletype function 
loop: 
    mov al, [si] 
    cmp al, 0 
    je return 
    int 0x10 
    inc si 
    jmp loop 
return: 
    pop si 
    pop bx 
    pop ax 
    ret 

disk_load: 
    mov [SECTORS], dh 
    mov ch, 0x00  ;C=0 
    mov dh, 0x00  ;H=0 
    mov cl, 0x02  ;S=2 
next_group: 
    mov di, 5   ;Max 5 tries 
again: 
    mov ah, 0x02  ;Read sectors 
    mov al, [SECTORS] 
    int 0x13 
    jc maybe_retry 
    sub [SECTORS], al ;Remaining sectors 
    jz ready 
    mov cl, 0x01  ;Always sector 1 
    xor dh, 1   ;Next head on diskette! 
    jnz next_group 
    inc ch   ;Next cylinder 
    jmp next_group 
maybe_retry: 
    mov ah, 0x00  ;Reset diskdrive 
    int 0x13 
    dec di 
    jnz again 
    jmp disk_error 
ready: 
    ret 

disk_error: 
    mov si, DISK_ERROR_MSG 
    call print_string 
    jmp $ 

DISK_ERROR_MSG db "Disk read error!", 0 

load_kernel: 
    mov bx, KERNEL_OFFSET  
    mov dh, 15   
    mov dl, [BOOT_DRIVE]      
    call disk_load             
    ret 

; Global variables 
BOOT_DRIVE  db 0 
SECTORS  db 0 
MSG_REAL_MODE db "Started in 16-bit Real Mode", 0 

; Bootsector padding 
times 510-($-$$) db 0 
dw 0xAA55 

; 15 sector padding 
times 15*256 dw 0xDADA 
+0

_SS:SP_の更新に関するコメント。あなたが言うことは実際には幅広い種類のハードウェアと互換性があることは事実ですが、CLI/STIペアの主な理由は1980年代のバグのある8088 CPUのバグを回避することです。 _SS_レジスタをMOV命令で更新すると、_NEXT_命令の後まで割り込みを無効にすることが考えられます。通常これは_SP_への更新です。残念なことに、バグの多い8088 CPUでは、割り込みが期待どおりにオフにならないため、バグを回避するためにCLI/STIを明示的に使用していました。 –

+1

私はあなたの答えをupvoted。もう少し観察します。読み取られたセクタ数は_AL_に依存します。CF = 1の場合、_AL_の値を返すだけの古代のBIOSがあります(はい、ちょっとクレイジーですが、本当です)。ほとんどのブートローダ(実際のハードウェアのより広い配列をターゲットにしている)は、_AL_の値に頼ることはできません。だから一般的に、ほとんどのブートローダは、一度に1つのセクタを読み込むか、ディスクのジオメトリ(BPBまたはBDAのいずれか)を取得し、トラック(シリンダ)にまたがらないマルチセクタの読み込みのみを行います。しかし、あなたのコードはほとんどのハードウェア(と私が知っているすべてのエミュレータ)で動作します。 –

関連する問題