Saya telah membuat bootloader dasar dalam perakitan, tetapi tidak benar-benar melompat ke kernel. Itu hanya mengatakan "Booting ...". Saya yakin itu hanya kesalahan konyol yang saya buat, seperti melompat ke tempat yang salah. Seharusnya menampilkan output seperti "Booting... Loaded!". Saya juga sudah mencoba mengatur es ke 0 sebelum memuatnya, tetapi itu pun tidak berhasil. Berikut kode saya:

mov ax, 9ch
mov ss, ax
mov sp, 4096d
mov ax, 7c0h
mov ds, ax
mov es, ax

xor ah, ah
int 13h

clc

mov si, msg2
call print

mov ah, 02h
xor ax, ax
mov es, ax
mov bx, 0x7E00
mov al, 1h
mov ch, 0
mov cl, 2h
mov dh, 0
int 13h

jc error

jmp 0x7E00

mov si, msg3
call print

error:
mov si, msg
call print
hlt

print:
lodsb
cmp al, 0
jz done
mov ah, 0eh
int 10h
jmp print
done:
ret

msg db "An error occured!!", 0
msg2 db "Booting...", 0
msg3 db "Did not jump to kernel correctly!"

times 510-($-$$) db 0
dw 0xAA55

mov si, msgloaded
call printl
jmp $

printl:
lodsb
cmp al, 0
jz donel
mov ah, 0eh
int 10h
jmp print
donel:
ret

msgloaded db "Loaded!", 0

times 0x400-($-$$) db 0

Semua bantuan dihargai. Saya akan menghargai siapa pun yang dapat membantu saya. Terima kasih!

1
programmer 17 November 2017, 21:37

1 menjawab

Jawaban Terbaik

Untuk bahasa tingkat tinggi ada banyak petunjuk tentang apa yang dimaksudkan oleh programmer yang terkandung dalam loop struktur, bagaimana nama variabel dipilih, mendefinisikan/enum, dll; dan mudah untuk menulis kode yang dapat dipelihara tanpa komentar.

Untuk bahasa assembly tidak ada nama variabel yang dipilih dengan baik dan tidak ada tipe variabel (misalnya ax tidak memberi tahu pembaca apakah itu pointer ke string atau tinggi jerapah atau ...), instruksi sering kali tidak menunjukkan maksud (misalnya lea dapat digunakan untuk mengalikan dengan konstanta dan mungkin tidak digunakan untuk memuat alamat yang efektif), aliran kontrol jauh lebih fleksibel (misalnya sesuatu seperti do(condition1) { } while(condition2) baik-baik saja) dan goto (baik jmp dan cabang bersyarat seperti jc) banyak digunakan.

Untuk alasan ini, bahasa rakitan yang ditulis/dipelihara dengan baik menggunakan banyak komentar. Lebih khusus lagi, Anda akan menggunakan komentar di sisi kanan untuk menggambarkan niat Anda. Ini memungkinkan Anda untuk memeriksa apakah niatnya benar dengan membaca komentar, dan kemudian memeriksa apakah niat itu diterapkan dengan benar dengan membandingkan instruksi pada setiap baris dengan komentarnya. Itu membuatnya lebih mudah untuk menghindari bug, dan lebih mudah untuk menemukan bug.

Inilah paruh pertama kode Anda dengan komentar:

;Memory Layout
;
; 0x009C:0x1000 = 0x000019C0 = stack top
; 0x07C0:0x0000 = 0x00007C00 = load address
; 0x0000:0x7E00 = 0x00007E00 = kernel address

%define STACK_SEGMENT      0x009C
%define STACK_TOP_OFFSET   0x1000
%define LOAD_SEGMENT       0x07C0
%define KERNEL_SEGMENT     0x0000
%define KERNEL_OFFSET      0x7E00

;_______________________________________________

;Entry point
;
;Input
; dl = BIOS boot device number

    mov ax, STACK_SEGMENT
    mov ss, ax
    mov sp, STACK_TOP_OFFSET
    mov ax, LOAD_SEGMENT
    mov ds, ax
    mov es, ax

;Reset disk system
;
;Note: This should be completely unnecessary. We know the BIOS
;      disk services are working correctly and don't need
;      to be reset because the BIOS just used it successfully
;      to load this code into memory.

    xor ah, ah            ;ah = BIOS "reset disk system" function number
    int 13h               ;Call BIOS disk services
    clc                   ;Unnecessary

;Display welcome message

    mov si, msg2
    call print

;Load kernel from disk
; dl = BIOS boot device number

    mov ah, 02h           ;ah = BIOS "read sectors" function number
    xor ax, ax            ;ax = KERNEL_SEGMENT
    mov es, ax
    mov bx, KERNEL_OFFSET ;es:bx = address to load kernel
    mov al, 1h            ;al = number of sectors to read
    mov ch, 0             ;ch = cylinder number for first sector
    mov cl, 2h            ;cl = sector number for first sector
    mov dh, 0             ;dh = head number for first sector
    int 13h               ;Call BIOS disk services

    jc error              ;Handle error if there was one

;Pass control to "kernel"

    jmp KERNEL_SEGMENT:KERNEL_OFFSET

Inilah bagian yang membuat bug Anda jelas:

                          ;ah = BIOS "read sectors" function number
                          ;ax = KERNEL_SEGMENT

Pada dasarnya, jika Anda mengomentari kode Anda dengan benar, Anda akan melihat bahwa memuat KERNEL_SEGMENT ke ax menimpa nomor fungsi BIOS (yang berada di 8 bit tertinggi ax). Ini menyebabkan potongan kode ini memanggil fungsi BIOS "reset disk system" dan tidak memuat apa pun dari disk sama sekali. Ketika melompat ke tempat kernel seharusnya dimuat (tetapi tidak) nanti, memori itu mungkin masih penuh dengan nol karena belum digunakan, tetapi memori yang penuh dengan nol didekodekan sebagai instruksi add oleh CPU, sehingga CPU dengan senang hati menjalankan instruksi add selama bertahun-tahun.

Catatan: Ada bug lain (tidak terkait) - kode Anda untuk mencetak string menggunakan lodsb yang bergantung pada flag arah; tetapi Anda tidak melakukan instruksi cld untuk menyetel flag arah, jadi tergantung pada status (tidak terdefinisi) BIOS meninggalkan flag ini, ia dapat mencetak sampah sebagai gantinya.

3
Brendan 17 November 2017, 20:00