Перезагрузите цикл при включении прерываний с помощью sti

Всякий раз, когда я пытаюсь включить прерывания, используя 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

Полный вывод, включая исключения / прерывания SMM, можно найти на pastebin.

РЕДАКТИРОВАТЬ 4: Вот мой обработчик прерываний (на основе osdev wiki):

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: Я знаю, что это слишком много правок, но я добавил последний код в ветку отладки моего проекта на github https://github.com/nm111/NMOS/tree/debug,

РЕДАКТИРОВАТЬ 6: Проблема, кажется, исправлена ​​сейчас, но это не может быть проверено до сегодняшнего дня, так как в настоящее время у меня нет доступа к компьютеру.

tl; dr Не заимствуйте код от Osdev Wiki.

0 ответов

Другие вопросы по тегам