使用sti启用中断时重新启动循环

时间:2017-05-13 08:45:02

标签: gcc x86 interrupt osdev protected-mode

每当我尝试使用sti命令启用中断时,模拟器立即重新启动。我在启动时在保护模式下执行以下代码:

void* idt = (void*) 0x00000;
struct {
    uint16_t length;
    void*    base;
} __attribute__((packed)) IDTR = {128, idt};

asm ("lidt %0" : : "m"(IDTR));
asm ("sti");

操作系统启动时有一段短暂的时间,甚至接受输入,但随后重新启动。为什么会发生这种情况?如何解决?

编辑:将-d int添加到qemu时,我得到以下输出:

SMM: enter
EAX=000000b5 EBX=00008acc ECX=00005678 EDX=000ece30
ESI=07fbdde6 EDI=000ece30 EBP=00006c38 ESP=00006c38
EIP=000f8acb EFL=00000016 [----AP-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA]
SS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00c09300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     000f7070 00000037
IDT=     000f70ae 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000014 CCD=00006c24 CCO=EFLAGS  
EFER=0000000000000000
SMM: after RSM
EAX=000000b5 EBX=00008acc ECX=00005678 EDX=000ece30
ESI=07fbdde6 EDI=000ece30 EBP=00006c38 ESP=00006c38
EIP=00008acc EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =de00 000de000 ffffffff 00809300
CS =f000 000f0000 ffffffff 00809b00
SS =0000 00000000 ffffffff 00809300
DS =0000 00000000 ffffffff 00809300
FS =0000 00000000 ffffffff 00809300
GS =0000 00000000 ffffffff 00809300
LDT=0000 00000000 0000ffff 00008200
TR =0000 00000000 0000ffff 00008b00
GDT=     00000000 00000000
IDT=     00000000 000003ff
CR0=00000010 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=00000000 CCD=00000000 CCO=EFLAGS  
EFER=0000000000000000

有一段时间,那么

check_exception old: 0xffffffff new 0x6

编辑2:-d cpu-reset-d int更有帮助。它打印:

CPU Reset (CPU 0)
EAX=00000032 EBX=00000000 ECX=5153092a EDX=51530000
ESI=0000000a EDI=00100000 EBP=00000000 ESP=00000fb0

(剪断)

XMM06=00000000000000000000000000000000 
XMM07=00000000000000000000000000000000
Triple fault

编辑3:-d int -no-reboot -no-shutdown os-image的完整输出(不包括SMM例外情况如下):

     0: v=20 e=0000 i=0 cpl=0 IP=0008:00001712 pc=00001712 SP=0010:00001f6c env->regs[R_EAX]=000000fa
EAX=000000fa EBX=00007d6a ECX=0000050c EDX=00000060
ESI=00007ca8 EDI=00000000 EBP=00001f80 ESP=00001f6c
EIP=00001712 EFL=00000206 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00007c6b 00000018
IDT=     00000000 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000004 CCD=00001f50 CCO=EFLAGS  
EFER=0000000000000000
check_exception old: 0xffffffff new 0xd
     1: v=0d e=0102 i=0 cpl=0 IP=0008:00001712 pc=00001712 SP=0010:00001f6c env->regs[R_EAX]=000000fa
EAX=000000fa EBX=00007d6a ECX=0000050c EDX=00000060
ESI=00007ca8 EDI=00000000 EBP=00001f80 ESP=00001f6c
EIP=00001712 EFL=00000206 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00007c6b 00000018
IDT=     00000000 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000004 CCD=00001f50 CCO=EFLAGS  
EFER=0000000000000000
check_exception old: 0xd new 0xd
     2: v=08 e=0000 i=0 cpl=0 IP=0008:00001712 pc=00001712 SP=0010:00001f6c env->regs[R_EAX]=000000fa
EAX=000000fa EBX=00007d6a ECX=0000050c EDX=00000060
ESI=00007ca8 EDI=00000000 EBP=00001f80 ESP=00001f6c
EIP=00001712 EFL=00000206 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00007c6b 00000018
IDT=     00000000 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
DR6=ffff0ff0 DR7=00000400
CCS=00000004 CCD=00001f50 CCO=EFLAGS  
EFER=0000000000000000
check_exception old: 0x8 new 0xd

可以在pastebin上找到包括SMM例外/中断的完整输出。

编辑4:这是我的中断处理程序(基于osdev wiki's):

void* irq0handler(void) {
    volatile void* address;
    asm goto("jmp %l[ISREnd]" ::: "memory" : ISREnd);                                                                           
// jump to end of ISR
    asm volatile(".align 16" ::: "memory");
    ISRStart:
    asm volatile(
        "pushal             \n\t"                                                                                                                               
// save regs
        "pushl %%ebp        \n\t"
        "movl %%esp, %%ebp  \n\t"
        "cld                "                                                                                                                   
// direction flag is used by gcc
        ::: "memory");
    asm volatile(
        "pushl %%es         \n\t"                                                                                                               
// save segment regs
        "pushl %%ds         \n\t"
        "movw $16, %%cx     \n\t"                                                                                                               
// set segment regs for kernel
        "movw %%cx, %%ds    \n\t"
        "movw %%cx, %%es    \n\t"
        "addl $4, (%%esp)   \n\t"                                                                                                               
// add 4 to make it point to PUSHAD struct
        "call *%%eax        \n\t"                                                                                                               
// call IRQ func.
        :: "a"(irq0func): "memory");                                                                                                        
// eax is the IRQ 0 function
    asm volatile(
        "popl %%es          \n\t"                                                                                                               
// restore everything
        "popl %%ds          \n\t"
        "leave              \n\t"
        "popal              \n\t"
        "iret               "                                                                                                               
// return from interrupt handler
        ::: "memory");
    ISREnd:
    asm goto(
        ".intel_syntax noprefix        \n\t"
        "mov eax, offset %l[ISRStart]  \n\t"                                                                                        
// get address of ISR start
        "mov [ebx], eax                \n\t"                                                                                        
// set ebx to adderss
        ".att_syntax                       "
        :: "b"(&address) : "eax", "memory" : ISRStart);                                                                 
// ebx to be set to adderss
    return (void*) address;                                                                                                                         
// return adderss of ISR
}

void irq0func() {
    // do something
    _PIC_sendEOI(0);
}

它使用函数_PIC_sendEOI(unsigned char irqnum)(发送结束中断)。通过运行函数fillidt(idt+(0x20*8), 8, irq0handler(), 0xe, 0)

来加载处理程序
void fillidt(void* idt, int select, int offset, int type, int perm) {
  size_t idt_ent_size = (size_t) 8;       // 8 bytes per entry

    uint8_t type_attr;

    int segment = 0;

    type_attr = 1;                                                  //     present
    type_attr <<= 2;                                                //     2 bits to set
    type_attr |= perm;                                          // perm is 2 bits
    type_attr <<= 1;                                                // 1 bit to set
    type_attr |= segment;                                       // segment is 1 bit
    type_attr <<= 4;                                                // 4 bits to set
    type_attr |= type;                                          // type is 4 bits

  struct {
    uint16_t offset_1;                    // offset bits 0..15
    uint16_t selector;                    // a code segment selector in the GDT or LDT
    uint8_t zero;                         // unused
    uint8_t type_attr;                                      // type and attributes
    uint16_t offset_2;                    // offset bits 16..31
  } __attribute__ ((packed)) idt_desc = {offset & 0xffff, select, 0,     type_attr, (offset & 0xffff0000) >> 16};
  memcpy(&idt_desc, idt, idt_ent_size);     // copy the descriptor
}

编辑5:我知道这是有点太多的编辑,但我已将最新的代码提交到https://github.com/nm111/NMOS/tree/debug的github项目的调试分支。

编辑6:此问题现在似乎已修复,但直到今天晚些时候才能验证,因为我目前无法访问计算机。

tl; dr不要从Osdev Wiki借用代码。

0 个答案:

没有答案
相关问题