2015-12-11 13 views
7

tôi đã cố gắng để phát triển một bộ nạp khởi động sử dụng this, nhưng khi nó được chạy nó cho thấy:đĩa đọc Lỗi trong khi tải thành phần vào bộ nhớ

disk read error! 

Nếu tôi bỏ qua nó, trong một phần sau, nó cho thấy tôi nhớ sai ánh xạ. Tôi cũng theo một số nguồn khác nữa nhưng vô ích. Có vẻ như tôi chỉ sao chép những gì họ đang làm. Nếu tôi thậm chí còn hơi khác một loại lỗi mới sẽ tạo ra mỗi lần.

Tôi có nên sử dụng bộ tải khởi động đã được xây dựng hoặc phải làm gì không?

Mã lỗi tải đĩa là như sau:

[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 

tôi sử dụng lệnh này để lắp ráp và chạy bootloader của tôi:

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

tôi gặp khó khăn vào thời điểm này. Trình tải khởi động của tôi hiển thị disk read error. Nếu tôi bỏ qua nó tại thời điểm này trong thời gian, sau đó nó tạo ra vấn đề trong khi thực hiện kernel.c của tôi Có vẻ như sử dụng bản đồ bộ nhớ sai.

+0

Plz kiểm tra mã này và giúp tôi ra! –

+0

Một vấn đề bạn có là bạn không thiết lập đúng _DS_ (Phân đoạn dữ liệu) khi chương trình của bạn bắt đầu. Bạn cũng thiết lập SP, nhưng bạn không thực sự thiết lập một _SS_ hợp lệ (Stack Segment). Điều này cũng có thể gây ra vấn đề. Trong disk_load bạn không đặt _ES_ (Phân đoạn mở rộng), cần phải được đặt đúng để vị trí bộ nhớ nơi dữ liệu được đọc được chỉ định đầy đủ (ES: BX là bộ đệm địa chỉ). Nếu bạn đang tạo một đĩa mềm 720k đọc 15 lĩnh vực có khả năng sẽ không hoạt động bởi vì các lĩnh vực tối đa trên một rãnh (xi lanh) là 9. Điều này có thể gây ra vấn đề đọc. –

+0

Cũng là một ý tưởng hay để đặt '[bits 16]' ở trên cùng để NASM biết tạo ra tất cả mã 16 bit cho bộ nạp khởi động –

Trả lời

5

"Ông ấy thực hiện một danh sách, anh ấy kiểm tra nó hai lần ..."

  • bootloader của bạn bắt đầu trong chế độ địa chỉ thật, vì vậy tốt nhất để buộc lắp ráp của bạn trong việc sử dụng 16- mã bit. Bạn đạt được điều này trong NASM bằng cách viết [bits 16] ở đầu chương trình của bạn.

  • Khi bộ nạp khởi động của bạn bắt đầu, BIOS sẽ đặt nó ở địa chỉ tuyến tính 00007C00h. Nó có thể làm điều này theo một số cách liên quan đến sự kết hợp của phân khúc và bù đắp.
    Khi bạn viết rõ ràng [org 0x7C00] bạn (loại) dự kiến ​​kết hợp này sẽ có phần phân đoạn bằng không. Nhưng điều này không phải là nghĩa vụ đối với BIOS! Và do đó, bạn có thể đặt các thanh ghi phân đoạn (DS, ES và SS) theo cách thủ công.

  • Chức năng teletype BIOS mà bạn sử dụng trong print_string sử dụng thường lệ BL và BH làm thông số. Vì vậy, bạn không bao giờ nên sử dụng thanh ghi BX để giải quyết văn bản của bạn. Chắc chắn, một số BIOS không sử dụng các tham số BL và BH (nữa) nhưng cố gắng phát triển các chương trình cho đối tượng lớn nhất.

  • Khi bạn khởi tạo thanh ghi SP với 0x9000 bạn thiết lập hiệu quả ngăn xếp có thể dễ dàng, mà không nhận thấy nó, ghi đè lên chương trình bên dưới nó! Tốt nhất nên chọn một sự kết hợp giữa SS và SP thỏa mãn nhu cầu của bạn và không gì hơn. Một ngăn xếp 4608 byte nằm phía trên bộ khởi động ở 7C00h và kết thúc ở 9000h sẽ yêu cầu: SS = 07E0h SP = 1200h. Để tránh bất kỳ sự cố nào trên phần cứng 8086, tốt nhất là tắt ngắt khi thay đổi SS: SP.

  • Bạn đã sử dụng hướng dẫn pushapopa. Đây không phải là hướng dẫn hợp lệ trên phần cứng 8086. Khi viết phần mềm mạnh mẽ, chúng ta nên kiểm tra xem phần cứng có hoạt động không. Nhưng ở đây giải pháp đơn giản nhất là chỉ có các thanh ghi đơn/đẩy.

  • Bạn đã hiểu giá trị trả lại từ hàm BIOS đọc từ đĩa, nhưng bạn chỉ hủy bỏ khi số lượng ngành không chính xác được chuyển. Đây là một cách tiếp cận sai lầm.Khi BIOS thông báo cho bạn về quá trình chuyển không đầy đủ (điều này có thể xảy ra nếu BIOS của bạn không được kích hoạt nhiều lần), bạn phải lặp lại cuộc gọi cho số lượng phần còn lại. Rõ ràng một số thông số sẽ phải được điều chỉnh: đầu tiếp theo, có thể là xy lanh tiếp theo và luôn là sector = 1. (Một giải pháp hoàn hảo sẽ liên quan đến việc lấy hình học đĩa từ BIOS hoặc đọc nó từ BPB hiện tại trên đĩa). Tôi cho rằng hoạt động cơ bản của đĩa mềm 1.44 MB.

  • Khi đọc từ đĩa không thành công lần đầu tiên bạn nên thử lại một vài lần. Lần đầu tiên thất bại như vậy là hoàn toàn bình thường. Năm thử lại là một giá trị tốt. Ở giữa các lần thử, bạn gọi hàm BIOS đặt lại đĩa.

  • Để đảm bảo QEMU thực sự có thể đọc 15 phần bổ sung đó, bạn nên đệm tệp này để tệp có tổng chiều dài là 16 phần. Các text bạn liên kết để làm điều này cũng!

"Đưa nó tất cả cùng nhau"

[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

Chỉ cần một bình luận về việc cập nhật _SS: SP_. Những gì bạn nói là trên thực tế đúng để tương thích với nhiều loại phần cứng nhất, nhưng lý do chính cho cặp CLI/STI là phá vỡ một lỗi trên một số CPU 8088 lỗi từ những năm 1980. Khi bạn cập nhật sổ đăng ký _SS_ với lệnh MOV, giả sử là vô hiệu hóa ngắt cho đến sau lệnh _NEXT_. Thông thường đó là bản cập nhật cho _SP_. Thật không may trên một số CPU 8088 lỗi ngắt các ngắt không được tắt như mong đợi vì vậy một cách rõ ràng sẽ sử dụng CLI/STI để tránh lỗi. –

+1

Tôi đã bình chọn câu trả lời của bạn. Sẽ làm cho một ít quan sát khác. Bạn dựa vào _AL_ là số lĩnh vực được đọc.Có một số BIOS cổ đại chỉ trả về một giá trị trong _AL_ nếu CF = 1 (Có, âm thanh hơi điên rồ nhưng đúng). Hầu hết các bộ nạp khởi động (nhắm mục tiêu một mảng phần cứng thực sự rộng hơn) không giả định giá trị _AL_ có thể dựa vào. Vì vậy, nói chung hầu hết các bộ tải khởi động đọc một sector tại một thời điểm, hoặc lấy hình học đĩa (hoặc từ BPB hoặc BDA) và chỉ đọc nhiều sector mà không bao giờ mở rộng một rãnh (cylinder). Nhưng mã của bạn sẽ làm việc với hầu hết phần cứng (và tất cả các trình giả lập mà tôi biết). –

Các vấn đề liên quan