@232321fdsa

Не работает таблица прерываний(IDT). Что делать?

Всем привет, я пишу свою ОС и у меня возникла проблема при написании таблицы прерываний(IDT). Я когда намеренно вызываю прерывание оно почему то не обрабатывается.
Вот мой IDT.h файл
#pragma once

#ifndef _IDT_

#include "stdint.h"

#define IDT_SIZE 256

namespace SimpleOS {

    class IDT {

        struct IDTSlot;
        struct IDTPtr;

        static IDTSlot idt[IDT_SIZE];
        static IDTPtr idt_ptr;

    public:

        static void init_idt();

    private:
        
        static void dividing_by_zero();

    private:

        static void set_in_idt_slot(int pos, uint32_t base, uint16_t sel, uint8_t flags);

        static void load_idt();

        struct IDTSlot {
            uint16_t offset_first;
            uint16_t selector;
            uint8_t zero;
            uint8_t type_attr;
            uint16_t offset_second;
        };

        struct IDTPtr {
            uint16_t limit;
            uint32_t base;
        };
    };
}

#endif // _IDT_

и вот мой IDT.cpp файл
#include "IDT/IDT.h"
#include "terminal/terminal.h"

using namespace SimpleOS;

void IDT::init_idt() {

    set_in_idt_slot(0, (uint32_t)dividing_by_zero, 0x08, 0x8E); // 0x08, 0x8E

    load_idt();

    __asm__ __volatile__("sti");
}

void IDT::set_in_idt_slot(int pos, uint32_t base, uint16_t sel, uint8_t flags) {
    idt[pos].offset_first = base & 0xFFFF;
    idt[pos].selector = sel;
    idt[pos].zero = 0;
    idt[pos].type_attr = flags;
    idt[pos].offset_second = (base >> 16) & 0xFFFF;
}

void IDT::load_idt() {
    idt_ptr.limit = (sizeof(IDTSlot) * IDT_SIZE) - 1;
    idt_ptr.base = (uint32_t)&idt;
    __asm__ __volatile__("lidt (%0)" : : "r" (&idt_ptr));
}

void IDT::dividing_by_zero() {
    Terminal::print("Failed operation dividing by zero");
    __asm__ __volatile__("cli; iret");
}

IDT::IDTSlot IDT::idt[IDT_SIZE];
IDT::IDTPtr IDT::idt_ptr;

и в kernel.cpp я вызываю намеренное прерывание
#include "terminal/terminal.h"
#include "IDT/IDT.h"

using namespace SimpleOS;

extern "C" void kernel_main(void) {
	IDT::init_idt();

    __asm__ __volatile__("int $0");
}

но оно почему то не обрабатывается.
В чем может быть проблема?
  • Вопрос задан
  • 166 просмотров
Пригласить эксперта
Ответы на вопрос 1
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
В чем может быть проблема?

Проблема может быть в чём угодно, чтобы сказать точнее нужен полный собирающийся код.

Вот эта структура:
struct IDTPtr {
    uint16_t limit;
    uint32_t base;
};

должна быть определена с атрибутом packed, иначе компилятор вставляет паддинг для выравнивания поля base на границу uint32_t, из-за чего в IDT загружается неверный адрес.

Ну и, вдобавок, нельзя делать iret из середины с++-функции, потому что компилятор организовал в ней кадр стека и вместо возврата iret снимает и интерпретирует мусор из этого кадра:
001000e6 <SimpleOS::IDT::dividing_by_zero()>:
  1000e6:       55                      push   %ebp
  1000e7:       89 e5                   mov    %esp,%ebp
  1000e9:       53                      push   %ebx
  1000ea:       83 ec 04                sub    $0x4,%esp
  1000ed:       e8 15 01 00 00          call   100207 <__x86.get_pc_thunk.ax>
  1000f2:       05 06 11 00 00          add    $0x1106,%eax
  1000f7:       83 ec 0c                sub    $0xc,%esp
  1000fa:       8d 90 08 fe ff ff       lea    -0x1f8(%eax),%edx
  100100:       52                      push   %edx
  100101:       89 c3                   mov    %eax,%ebx
  100103:       e8 4c 00 00 00          call   100154 <SimpleOS::Terminal::print(char const*)>
  100108:       83 c4 10                add    $0x10,%esp
  10010b:       fa                      cli
  10010c:       cf                      iret
  10010d:       90                      nop
  10010e:       8b 5d fc                mov    -0x4(%ebp),%ebx
  100111:       c9                      leave
  100112:       c3                      ret
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы