В этой пятой части мы увидим таблицу, очень похожую на GDT как в теории, так и в использовании, мы ссылаемся на IDT. IDT означает Таблица описания прерываний y - таблица, которая используется для обработки возникающих прерываний. Например, кто-то делает деление на 0, вызывается функция, отвечающая за обработку. Эти функции - ISR (Процедуры обслуживания прерывания). Итак, давайте создадим IDT и добавим ISR.
Сначала мы собираемся объявить структуры, соответствующие IDT:
struct Entry{
uint16_t base_low;
uint16_t sel;
uint8_t always0;
uint8_t flags;
uint16_t base_high;
} __attribute__((packed));
struct Ptr{
uint16_t limit;
uint32_t base;
} __attribute__((packed));
Как видно, если вы сравните его с GDT, структура Ptr идентична, а Entry очень похожа. Поэтому функции установки записи (SetGate) и установки (Install) очень похожи.
void ND::IDT::SetGate(uint8_t num,uint32_t base,uint16_t sel, uint8_t flags)
{
idt[num].base_low=(base & 0xFFFF);
idt[num].base_high=(base >> 16) & 0xFFFF;
idt[num].sel=sel;
idt[num].always0=0;
idt[num].flags=flags;
}
Установить:
idtptr.limit=(sizeof(struct ND::IDT::Entry)*256)-1;
idtptr.base=(uint32_t)&idt;
ND::Memory::Set(&idt,0,sizeof(struct ND::IDT::Entry)*256);
ND::IDT::Flush();
Если мы посмотрим, то увидим, что функция установки использует функцию ND :: Memory :: Set, которую мы объявили в другом посте. Мы также можем оценить, что мы еще не выполняем никаких вызовов SetGate и вызываем ND :: IDT :: Flush, для этой функции мы снова используем оператор asm volatile:
asm volatile("lidtl (idtptr)");
Если все пойдет хорошо и мы сделаем эстетическую аранжировку, она должна выглядеть так:
Хорошо, теперь приступим к заполнению IDT прерываниями. Здесь я собираюсь создать только один, но для остальных он будет таким же. Я сделаю деление на нулевой перерыв. Как вы хорошо знаете в математике, число не может быть разделено на 0. Если это происходит в процессоре, генерируется исключение, поскольку оно не может продолжаться. В IDT этому событию соответствует первое прерывание в списке (0).
Мы добавляем это между настройкой памяти и сбросом в функции установки IDT:
ND::IDT::SetGate(0,(unsigned)ND::ISR::ISR1,0x08,0x8E);
Функция обратного вызова будет ND :: ISR :: ISR1, что довольно просто, хотя мы должны использовать ASM:
void ND::ISR::ISR1()
{
asm volatile(
"cli \n"
"pushl 0 \n"
"pushl 0 \n"
"jmp ND_ISR_Common \n"
);
}
ND_ISR_Common мы определим его как функцию на языке C. Для сохранения файлов и улучшения читаемости мы можем использовать extern «C» {}:
extern "C"
void ND_ISR_Common()
{
asm volatile(
"pusha \n"
"push %ds \n"
"push %es \n"
"push %fs \n"
"push %gs \n"
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movl %esp, %eax \n"
"push %eax \n"
"movl $ND_ISR_Handler, %eax \n"
"call *%eax \n"
"popl %eax \n"
"popl %ds \n"
"popl %es \n"
"popl %fs \n"
"popl %gs \n"
"popa \n"
"addl 8, %esp \n"
"iret \n"
);
}
Этот код в ASM может быть немного сложным для понимания, но это связано с тем, что мы собираемся объявить структуру на C для доступа к данным, сгенерированным прерыванием. Очевидно, если вы этого не хотите, вы можете просто вызвать Kernel Panic в ND :: ISR :: ISR1 или что-то в этом роде. Структура имеет такую форму, что:
struct regs{
uint32_t ds;
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
uint32_t int_no, err_code;
uint32_t eip, cs, eflags, useresp, ss;
};
И, наконец, мы выполняем функцию ND_ISR_Handler (также со ссылкой на C), в которой мы показываем панику ядра и небольшое описание ошибки в соответствии с тем, которое есть в списке ошибок.
extern "C"
void ND_ISR_Handler(struct regs *r)
{
if(r->int_no < 32) { ND::Panic::Show(exception_messages[r->int_no]);
for(;;);
}
}
Хорошо, и с этим мы уже можем справиться с этим прерыванием. С остальными прерываниями это произойдет аналогично, за исключением того, что есть некоторые, которые возвращают параметры, и мы будем использовать структуру reg для их получения. Однако вы можете задаться вопросом, как мы узнаем, действительно ли это работает. Чтобы проверить, работает ли это, мы собираемся ввести простую строку после ND :: IDT :: Install ():
int sum=10/0;
Если мы скомпилируем, он выдаст нам предупреждение, и если мы попытаемся выполнить его, мы получим хороший экран:
И на этом я считаю, что этот пост является одним из самых обширных, но весьма функциональных.
Я перешел на LFS, он более сплошной.
Святой ... В общем, уроки хорошие.
Очень хорошо, слежу за ним с самого начала. Не могли бы вы прикрепить коды к каждому трейлеру?
У вас есть весь исходный код, доступный на GitHub: http://github.com/AdrianArroyoCalle/next-divel Оттуда вы можете скачать ZIP, TAR.GZ или просто использовать git.
Хахаха очень хорошо! Одобрить! 🙂