Chức năng đọc đĩa không hoạt động như mong đợi trong Bootloader

Aug 16 2020

Tôi đang cố gắng phát triển một bộ nạp khởi động cơ bản, nhưng tôi đã gặp sự cố khi cố gắng tạo một chức năng để đọc các sector bổ sung từ ổ cứng. Tôi đang phát triển nó trên Kali Linux trong NASM và sử dụng QEMU làm trình giả lập của mình. Đây là tệp bộ nạp khởi động chính của tôi:

[org 0x7c00]

mov bp, 0x8000
mov sp, bp

call read_disk

mov si, my_string
call print          ;prints a string, si points to the string to be printed

jmp $ read_disk mov ah, 0x02 ;read from disk mov al, 0x01 ;read one sector mov ch, 0x00 ;read from cylinder 0 mov dh, 0x00 ;read from head 0 mov cl, 0x02 ;read the second sector mov bx, 0 mov es, bx mov bx, 0x7c00+512 int 0x13 jc disk_error ;BIOS sets the carry flag if disk read was unsuccessful ret disk_error: mov si, error_msg call print jmp $
;
;Functions
;
%include "functions/print.asm"
%include "functions/print_hex.asm"
%include "functions/print_nl.asm"
%include "functions/calc_len.asm"
%include "functions/find_string.asm"

;
;Data
;
error_msg:
    db 'Error reading disk', 0

times 510-($-$$) db 0    ;pad out the rest of the bootloader with zeros to increase the size to 512 bytes
dw 0xaa55                ;Magic bytes so BIOS recognizes the hard drive as bootable

;
;SECOND SECTOR
;

my_string:
    db 'Disk read successful', 0

times 512 db 0   ;need to pad out the rest of the sector with zeros since  QEMU requires it

Như bạn có thể thấy, my_stringnằm sau 512 byte, trong khu vực thứ hai của ổ cứng được mô phỏng. Nhưng khi tôi biên dịch và chạy bộ nạp khởi động, nó không xuất ra bất cứ thứ gì. Trong đoạn code tôi cung cấp ở trên, tôi in my_string sau khi các read_diskchức năng kết thúc. Nhưng kỳ lạ thay, Nếu tôi di chuyển hai dòng in my_string bên trong hàm, nó hoạt động. Đây là mã hoạt động:

[org 0x7c00]

mov bp, 0x8000
mov sp, bp

call read_disk

jmp $ read_disk mov ah, 0x02 ;read from disk mov al, 0x01 ;read one sector mov ch, 0x00 ;read from cylinder 0 mov dh, 0x00 ;read from head 0 mov cl, 0x02 ;read the second sector mov bx, 0 mov es, bx mov bx, 0x7c00+512 int 0x13 jc disk_error ;BIOS sets the carry flag if disk read was unsuccessful mov si, my_string call print ;prints a string, si points to the string to be printed ret disk_error: mov si, error_msg call print jmp $
;
;Functions
;
%include "functions/print.asm"
%include "functions/print_hex.asm"
%include "functions/print_nl.asm"
%include "functions/calc_len.asm"
%include "functions/find_string.asm"

;
;Data
;
error_msg:
    db 'Error reading disk', 0

times 510-($-$$) db 0    ;pad out the rest of the bootloader with zeros to increase the size to 512 bytes
dw 0xaa55                ;Magic bytes so BIOS recognizes the hard drive as bootable

;
;SECOND SECTOR
;

my_string:
    db 'Disk read successful', 0

times 512 db 0   ;need to pad out the rest of the sector with zeros since  QEMU requires it

Tôi sẽ rất biết ơn nếu ai đó có thể giải thích sự kỳ lạ kỳ lạ này cho tôi.

Trả lời

4 MichaelPetch Aug 16 2020 at 14:38

Bạn nên đặt SS: SP chứ không phải chỉ là SP trước khi đọc vào bộ nhớ. SS có thể bằng 0 hoặc có thể không. Nếu SS xảy ra là 0x0000 thì ngăn xếp của bạn ở 0x0000: 0x8000 và nó sẽ giảm dần từ đó.

Mã của bạn đọc khu vực 512 byte thứ hai trên đĩa vào bộ nhớ ở 0x0000: 0x7e00 bao gồm tất cả các byte lên đến và bao gồm địa chỉ trả về của disk_readhàm đã được đặt trên ngăn xếp ở 0x0000: 0x7ffe đến 0x0000: 0x7fff.

Vì bạn đã che giấu ngăn xếp, nên int 0x13có khả năng sẽ không bao giờ trả lại vì dữ liệu nội bộ, địa chỉ trả về và các cờ đã bị hỏng. Làm hỏng ngăn xếp như thế này sẽ có kết quả khó lường. Cân nhắc đặt ngăn xếp ở 0x0000: 0x7c00 bên dưới bộ nạp khởi động để không ảnh hưởng đến dữ liệu và mã bạn tải sau bộ nạp khởi động.

Lưu ý: Bạn nên đặt tất cả các đăng ký phân đoạn bạn cần thành các giá trị mà bạn mong đợi. Bạn không nên dựa vào bất kỳ thanh ghi phân đoạn nào chứa một giá trị cụ thể. BIOS không đảm bảo giá trị của chúng, mặc dù trong hầu hết các trình giả lập, chúng sẽ là 0x0000.