#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_
#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;
#include "terminal/terminal.h"
#include "IDT/IDT.h"
using namespace SimpleOS;
extern "C" void kernel_main(void) {
IDT::init_idt();
__asm__ __volatile__("int $0");
}
В чем может быть проблема?
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