ฟังก์ชันการอ่านดิสก์ไม่ทำงานตามที่คาดไว้ใน Bootloader
ฉันกำลังพยายามพัฒนา 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
ฉันจะขอบคุณมากถ้ามีใครอธิบายความแปลกประหลาดนี้ให้ฉันฟังได้
คำตอบ
คุณควรตั้งค่า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 ก็ตาม