尝试"sti"时出现一般保护错误 [英] General Protection Fault when trying to `sti`

查看:88
本文介绍了尝试"sti"时出现一般保护错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试在测试引导加载程序上实现硬件中断.异常正在起作用(因此发现它是GPF).尝试 sti 时,发生了GPF.这是我的主要代码:

Trying to implement hardware interrupts on a test bootloader. Exceptions are working(thus found it is GPF). When trying to sti, a GPF is occured. Here is my main code:

    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

这就是我的GDT的样子:

This is how my GDT looks like:

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
    

这就是我的IDT的样子:

And this is how my IDT looks like:

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.

我的PIC设置代码:

    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
    

试图在修改IDT中的条目后使sti检查键盘中断,但随后发现 sti 导致了GPF异常.qemu日志:

Tried to enable sti to check keyboard interrupt after modifying that entry in IDT, but then found that sti causes a GPF exception. qemu log:

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

我不知道为什么会发生这种情况,我也不了解它以了解自己.请帮忙.

I have no idea why this happens, nor I have much knowledge about it to find out myself. Please help.

推荐答案

我观察到在您的错误输出中您遇到了以下异常:

I had observed that in your error output you got this exception:

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

重要的是,这是#GP(常规保护错误)的例外,错误代码为 0x7c2 .OSdev Wiki包含有关异常以及如何解释#GP异常的错误代码的摘要:

The important part is that this is exception is a #GP (General Protection Fault) with an error code of 0x7c2. The OSdev Wiki has a synopsis of the Exceptions and how to interpret the error code for a #GP exception:

错误代码0x7c2是二进制 11111000 01 0 .位0清楚表示这不是外部原因引起的异常.位1和2是 01 ,这意味着在访问IDT时引起了异常. 11111000 是中断向量的索引,它是 0xF8 .这是一个危险信号.您的PIC重新映射代码似乎是将主pic重新映射为0x20-0x27,将从PIC重新映射为0x28-0x2f.除非PIC重新映射代码错误,否则中断 0xF8 没有任何意义.

The error code 0x7c2 is binary 11111000 01 0. Bit 0 being clear means that this wasn't an exception with an external cause. Bit 1 and 2 is 01 which means the exception was caused when accessing the IDT. 11111000 is the index of the interrupt vector which is 0xF8. This is a red flag. Your PIC remapping code appears to be remapping the master pic to 0x20-0x27 and the slave PIC to 0x28-0x2f. Interrupt 0xF8 makes no sense unless the PIC remapping code is wrong.

在查看PIC重新映射代码时,我发现了一个问题:

Upon reviewing the PIC remapping code I noticed an issue:

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

为清楚起见,我删除了 jmp $ + 2 ,因为它们不是必需的.如果您交替更新主PIC端口和从PIC端口,则 out 指令将用作所需的延迟.OSDev Wiki上有关于执行 PIC重新映射和初始化的部分.您的代码在这里有所不同:

I have removed the jmp $+2 for clarity and because they aren't needed. If you alternate updating the master and slave PIC ports then the out instruction will act as the needed delay. The OSDev Wiki has a section on doing the PIC remapping and initialization. Your code differs here:

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

在将4写入端口0x21并将2写入端口0xA1之后,您需要将1写入端口0xA1,将1写入端口0xA2.然后,您可以将中断屏蔽写入端口0x21和端口0xA1,以启用和禁用所需的中断.正确的代码可能类似于:

After writing 4 to port 0x21 and 2 to port 0xA1 you need to write 1 to port 0xA1 and 1 to port 0xA2. Then you are free to write the interrupt mask to port 0x21 and port 0xA1 to enable and disable the needed interrupts. The correct code could look something like:

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

通过使用错误的初始化代码,我能够重现您的QEMU异常和中断.我会在0xF8上收到一个中断:

I was able to reproduce your QEMU exceptions and interrupts by using your incorrect initialization code. I would get an interrupt on 0xF8:

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

由于#GP异常未处理且在我的IDT之外,因此出现了

Followed by #GP exception since it was unhandled and outside my IDT:

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

修复后,我开始收到类似于计时器的中断,并带有类似于以下内容的正确条目:

After the fix I start getting interrupts like the timer with correct entries similar to:

0: v=20 e=0000 i=0 cpl=0 IP=0008:00007c4f pc=00007c4f ...

这篇关于尝试"sti"时出现一般保护错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆