ฟังก์ชันการอ่านดิสก์ไม่ทำงานตามที่คาดไว้ใน Bootloader

Aug 16 2020

ฉันกำลังพยายามพัฒนา bootloader พื้นฐาน แต่ฉันประสบปัญหาเมื่อฉันพยายามสร้างฟังก์ชันสำหรับอ่านภาคเพิ่มเติมจากฮาร์ดไดรฟ์ ฉันกำลังพัฒนาบน Kali Linux ใน NASM และใช้ QEMU เป็นโปรแกรมจำลองของฉัน นี่คือไฟล์ bootloader หลักของฉัน:

[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

อย่างที่คุณเห็นmy_stringอยู่หลัง 512 ไบต์ในภาคที่สองของฮาร์ดไดรฟ์จำลอง แต่เมื่อฉันรวบรวมและเรียกใช้ bootloader มันจะไม่ส่งออกอะไรเลย ในรหัสที่ผมให้ไว้ข้างต้นผมพิมพ์my_string หลังจากread_diskฟังก์ชั่นที่มีมากกว่า แต่ที่น่าแปลกก็คือถ้าฉันย้ายสองบรรทัดที่พิมพ์my_string ภายในฟังก์ชันมันก็ใช้ได้ นี่คือรหัสที่ใช้งานได้:

[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

ฉันจะขอบคุณมากถ้ามีใครอธิบายความแปลกประหลาดนี้ให้ฉันฟังได้

คำตอบ

4 MichaelPetch Aug 16 2020 at 14:38

คุณควรตั้งค่าSS: SPไม่ใช่เฉพาะSPก่อนที่จะอ่านลงในหน่วยความจำ SSอาจเป็นศูนย์หรืออาจไม่ใช่ ถ้าSSเป็น 0x0000 สแต็กของคุณจะอยู่ที่ 0x0000: 0x8000 และจะขยายลงมาจากที่นั่น

รหัสของคุณอ่านเซกเตอร์ 512 ไบต์ที่สองบนดิสก์ไปยังหน่วยความจำที่ 0x0000: 0x7e00 ซึ่งรวมไบต์ทั้งหมดที่มีขนาดไม่เกินและรวมถึงที่อยู่ส่งคืนของdisk_readฟังก์ชันที่วางบนสแต็กที่ 0x0000: 0x7ffe ถึง 0x0000: 0x7fff

เนื่องจากคุณรวบรวมสแต็กไว้แล้วสิ่งint 0x13นี้จะไม่กลับมาอีกเลยเนื่องจากข้อมูลภายในที่อยู่ที่ส่งคืนและแฟล็กเสียหาย การทำให้สแตกเสียหายเช่นนี้จะมีผลลัพธ์ที่คาดเดาไม่ได้ พิจารณาวางสแต็กที่ 0x0000: 0x7c00 ด้านล่าง bootloader เพื่อที่จะไม่รบกวนข้อมูลและรหัสที่คุณโหลดหลังจาก bootloader

หมายเหตุ: คุณควรตั้งค่าการลงทะเบียนกลุ่มทั้งหมดที่คุณต้องการให้เป็นค่าที่คุณคาดหวัง คุณไม่ควรพึ่งพาการลงทะเบียนกลุ่มใด ๆ ที่มีค่าเฉพาะ BIOS ไม่รับประกันค่าแม้ว่าในอีมูเลเตอร์ส่วนใหญ่จะเป็น 0x0000 ก็ตาม