Эмуляция Линуса Торвальдса: создайте свою собственную операционную систему из 0 (V)

В этой пятой части мы увидим таблицу, очень похожую на 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)");

Если все пойдет хорошо и мы сделаем эстетическую аранжировку, она должна выглядеть так:

NextDivel-RTD

Хорошо, теперь приступим к заполнению 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;

Если мы скомпилируем, он выдаст нам предупреждение, и если мы попытаемся выполнить его, мы получим хороший экран:

СледующийDivel-ISR


И на этом я считаю, что этот пост является одним из самых обширных, но весьма функциональных.


Оставьте свой комментарий

Ваш электронный адрес не будет опубликован. Обязательные для заполнения поля помечены *

*

*

  1. Ответственный за данные: Мигель Анхель Гатон
  2. Назначение данных: контроль спама, управление комментариями.
  3. Легитимация: ваше согласие
  4. Передача данных: данные не будут переданы третьим лицам, кроме как по закону.
  5. Хранение данных: база данных, размещенная в Occentus Networks (ЕС)
  6. Права: в любое время вы можете ограничить, восстановить и удалить свою информацию.

  1.   Мезодаблер сказал

    Я перешел на LFS, он более сплошной.

  2.   элиотайм3000 сказал

    Святой ... В общем, уроки хорошие.

  3.   sc сказал

    Очень хорошо, слежу за ним с самого начала. Не могли бы вы прикрепить коды к каждому трейлеру?

    1.    АдрианАрройоУлица сказал

      У вас есть весь исходный код, доступный на GitHub: http://github.com/AdrianArroyoCalle/next-divel Оттуда вы можете скачать ZIP, TAR.GZ или просто использовать git.

  4.   нюансированный сказал

    Хахаха очень хорошо! Одобрить! 🙂