Mencoba menerapkan interupsi perangkat keras pada bootloader uji. Pengecualian berfungsi (sehingga ditemukan itu adalah GPF). Saat mencoba sti, terjadi GPF. Ini kode utama saya:

    cli
    lgdt [gdt_desc]
    lidt [idt_desc]
    mov eax, cr0
    or eax, 1
    mov cr0, eax
    jmp 0x8:bit_32
bit_32:
[bits 32]
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov eax, 0x8000
    mov esp, eax
    mov ebp, esp
    sti                              ; exception raised

Beginilah tampilan GDT saya:

start_gdt:

null:
    dd 0x0
    dd 0x0
code:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10011010b
    db 01000000b
    db 0x0
data:
    dw 0xffff
    dw 0
    db 0x0
    db 10010010b
    db 01001011b
    db 0x0

gdt_desc:
    dw gdt_desc-start_gdt-1
    dd start_gdt
    

Dan seperti inilah tampilan IDT saya:

start_idt:

i0:
    dw genroutine
    dw 0x8
    db 0
    db 10001110b
    dw 0
    
i1: dw genroutine
    dw 0x8
    db 0
    db 10001111b
    dw 0
    
i2: dw genroutine
    dw 0x8
    db 0
    db 10001110b
    dw 0
    
i3: dw genroutine
    dw 0x8
    db 0
    db 10001111b
    dw 0
    
i5: dw genroutine
    dw 0x8
    db 0
    db 10001111b
    dw 0
.
.
;around 50 times, with some modification like for keyboard, GPF etc.

Kode pengaturan PIC saya:

    mov al, 0x11
    out 0x20, al
    jmp $+2
    jmp $+2
    out 0xA0, al
    jmp $+2
    jmp $+2
    mov al, 0x20
    out 0x21, al
    jmp $+2
    jmp $+2
    mov al, 0x28
    out 0xA1, al
    jmp $+2
    jmp $+2
    mov al, 4
    out 0x21, al
    mov al, 2
    jmp $+2
    jmp $+2
    out 0xA1, al
    jmp $+2
    jmp $+2
    mov al, 11111101b
    out 0x20, al
    mov al , 11111101b
    jmp $+2
    jmp $+2
    out 0x21, al
    ret
    

Mencoba mengaktifkan sti untuk memeriksa interupsi keyboard setelah memodifikasi entri itu di IDT, tetapi kemudian menemukan bahwa sti menyebabkan pengecualian GPF. log qemu:

check_exception old: 0xffffffff new 0xd
     1: v=0d e=07c2 i=0 cpl=0 IP=0008:0000000000007c74 pc=0000000000007c74 SP=0010:0000000000008000 env->regs[R_EAX]=0000000000008000
EAX=00008000 EBX=00007e15 ECX=00000022 EDX=00002080
ESI=00007e00 EDI=00000800 EBP=00008000 ESP=00008000
EIP=00007c74 EFL=00000246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 000bffff 004b9300 DPL=0 DS   [-WA]
CS =0008 00000000 0000ffff 00409a00 DPL=0 CS32 [-R-]
SS =0010 00000000 000bffff 004b9300 DPL=0 DS   [-WA]
DS =0010 00000000 000bffff 004b9300 DPL=0 DS   [-WA]
FS =0010 00000000 000bffff 004b9300 DPL=0 DS   [-WA]
GS =0010 00000000 000bffff 004b9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00007d4c 00000017
IDT=     00007e15 0000038f
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 DR3=0000000000000000 
DR6=00000000ffff0ff0 DR7=0000000000000400
CCS=00000044 CCD=00008000 CCO=EFLAGS  
EFER=0000000000000000

Saya tidak tahu mengapa ini terjadi, saya juga tidak memiliki banyak pengetahuan tentang hal itu untuk mencari tahu sendiri. Tolong bantu.

1
Pranav appu 10 Juli 2020, 09:14

1 menjawab

Jawaban Terbaik

Saya telah mengamati bahwa dalam output kesalahan Anda, Anda mendapatkan pengecualian ini:

check_exception old: 0xffffffff new 0xd
     1: v=0d e=07c2 i=0 cpl=0 IP=0008:0000000000007c74 ...

Bagian penting adalah bahwa pengecualian ini adalah #GP (Kesalahan Perlindungan Umum) dengan kode kesalahan 0x7c2. Wiki OSdev memiliki sinopsis Pengecualian dan cara menginterpretasikan kode kesalahan untuk pengecualian #GP:

enter image description here

Kode kesalahan 0x7c2 adalah biner 11111000 01 0. Bit 0 menjadi jelas berarti ini bukan pengecualian dengan penyebab eksternal. Bit 1 dan 2 adalah 01 yang berarti eksepsi disebabkan saat mengakses IDT. 11111000 adalah indeks dari vektor interupsi yaitu 0xF8. Ini adalah bendera merah. Kode remapping PIC Anda tampaknya memetakan ulang master pic ke 0x20-0x27 dan PIC slave ke 0x28-0x2f. Interupsi 0xF8 tidak masuk akal kecuali kode pemetaan ulang PIC salah.

Setelah meninjau ulang kode pemetaan ulang PIC, saya melihat masalah:

mov al, 0x11
out 0x20, al
out 0xA0, al
mov al, 0x20
out 0x21, al
mov al, 0x28
out 0xA1, al
mov al, 4
out 0x21, al
mov al, 2
out 0xA1, al
mov al, 11111101b
out 0x20, al
mov al , 11111101b
out 0x21, al
ret

Saya telah menghapus jmp $+2 untuk kejelasan dan karena itu tidak diperlukan. Jika Anda bergantian memperbarui port PIC master dan slave maka instruksi out akan bertindak sebagai penundaan yang diperlukan. Wiki OSDev memiliki bagian tentang melakukan pemetaan ulang dan inisialisasi PIC. Kode Anda berbeda di sini:

mov al, 4
out 0x21, al          ; This is Correct
mov al, 2
out 0xA1, al          ; This is Correct
mov al, 11111101b
out 0x20, al          ; This is Wrong
mov al , 11111101b
out 0x21, al          ; This is Wrong
ret

Setelah menulis 4 ke port 0x21 dan 2 ke port 0xA1 Anda perlu menulis 1 ke port 0xA1 dan 1 ke port 0xA2. Kemudian Anda bebas menulis interrupt mask ke port 0x21 dan port 0xA1 untuk mengaktifkan dan menonaktifkan interupsi yang diperlukan. Kode yang benar dapat terlihat seperti:

mov al, 4
out 0x21, al          ; This is Correct
mov al, 2
out 0xA1, al          ; This is Correct
mov al, 1
out 0xA1, al          ; This is Correct
out 0x21, al          ; This is Correct

; Now set the PIC masks. Each bit in the mask is 0=enabled interrupt, 1=disabled.
mov al, 0
out 0x21, al          ; Enable all interrupts on Slave
out 0xA1, al          ; Enable all interrupts on Master

; Now set the PIC masks. Each bit in the mask is 0=enabled interrupt, 1=disabled.
; mov al, 0xfc
; out 0x21, al          ; Disable all interrupts on Master except timer and keyboard
                        ; 0xfc = 0b11111100
; mov al, 0xff
; out 0xA1, al          ; Disable all interrupts on Slave
    
ret

Saya dapat mereproduksi pengecualian dan interupsi QEMU Anda dengan menggunakan kode inisialisasi yang salah. Saya akan mendapatkan interupsi pada 0xF8:

 0: v=f8 e=0000 i=0 cpl=0 IP=0008:00007c51 pc=00007c51 ...

Diikuti oleh pengecualian #GP karena tidak ditangani dan di luar IDT saya:

1: v=0d e=07c2 i=0 cpl=0 IP=0008:00007c51 pc=00007c51 ...

Setelah perbaikan saya mulai mendapatkan interupsi seperti timer dengan entri yang benar mirip dengan:

0: v=20 e=0000 i=0 cpl=0 IP=0008:00007c4f pc=00007c4f ...
4
Michael Petch 19 November 2020, 19:39