Emulowanie Linusa Torvaldsa: Stwórz własny system operacyjny od 0 (V)

W tej piątej części zobaczymy tabelę dość podobną do GDT zarówno w teorii, jak iw użyciu, odnosimy się do IDT. IDT oznacza Tabela opisów przerwań y to tablica używana do obsługi występujących przerwań. Na przykład, ktoś dzieli przez 0, wywoływana jest funkcja odpowiedzialna za przetwarzanie. Te funkcje to ISR (Procedury obsługi przerwań). Stwórzmy więc IDT i dodajmy trochę ISR.

Najpierw zadeklarujemy struktury odpowiadające 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));

Jak widać, porównując go z GDT, struktura Ptr jest identyczna, a Entry dość podobna. Dlatego funkcje wstawiania wpisu (SetGate) i instalowania (Instaluj) są bardzo podobne.

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;
}

Zainstalować:

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();

Jeśli spojrzymy, zobaczymy, że funkcja install używa funkcji ND :: Memory :: Set, którą zadeklarowaliśmy w innym poście. Możemy również docenić to, że nie wykonujemy jeszcze żadnych wywołań SetGate i wywołujemy ND :: IDT :: Flush, dla tej funkcji ponownie używamy instrukcji volatile asm:

asm volatile("lidtl (idtptr)");

Jeśli wszystko pójdzie dobrze i wykonamy estetyczną aranżację, powinno to wyglądać tak:

NastępnyDivel-RTD

OK, teraz zaczniemy wypełniać IDT przerwaniami. Tutaj utworzę tylko jeden, ale dla reszty będzie tak samo. Mam zamiar podzielić przez zero. Jak dobrze wiesz z matematyki, liczby nie można podzielić przez 0. Jeśli tak się dzieje w procesorze, generowany jest wyjątek, ponieważ nie może kontynuować. W IDT pierwsze przerwanie na liście (0) odpowiada temu zdarzeniu.

Dodajemy to między ustawieniem pamięci a opróżnieniem w ramach funkcji instalacji IDT:

ND::IDT::SetGate(0,(unsigned)ND::ISR::ISR1,0x08,0x8E);

Funkcją zwrotną będzie ND :: ISR :: ISR1, co jest dość proste, chociaż musimy użyć ASM:

void ND::ISR::ISR1()
{
asm volatile(
"cli \n"
"pushl 0 \n"
"pushl 0 \n"
"jmp ND_ISR_Common \n"
);
}

ND_ISR_Common zdefiniujemy to jako funkcję w języku C. Aby zapisać pliki i poprawić czytelność, możemy użyć 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"
);
}

Ten kod w ASM może być nieco trudny do zrozumienia, ale dzieje się tak, ponieważ zamierzamy zadeklarować strukturę w C, aby uzyskać dostęp do danych wygenerowanych przez przerwanie. Oczywiście, jeśli tego nie chcesz, możesz po prostu wywołać Kernel Panic w ND :: ISR :: ISR1 lub coś w tym rodzaju. Konstrukcja ma taki kształt, że:

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;
};

Na koniec tworzymy funkcję ND_ISR_Handler (również z linkiem C), w której pokazujemy panikę jądra i mały opis błędu zgodnie z tym, który mamy na liście błędów.

extern "C"
void ND_ISR_Handler(struct regs *r)
{
if(r->int_no < 32) { ND::Panic::Show(exception_messages[r->int_no]);
for(;;);
}
}

Dobrze i dzięki temu jesteśmy już w stanie poradzić sobie z tą przerwą. Z resztą przerwań byłoby podobnie, z wyjątkiem tego, że są takie, które zwracają parametry i użylibyśmy struktury reg, aby je uzyskać. Jednak możesz się zastanawiać, skąd wiemy, czy to naprawdę działa. Aby sprawdzić, czy to działa, wprowadzimy prostą linię po ND :: IDT :: Install ():

int sum=10/0;

Jeśli skompilujemy, da nam to ostrzeżenie, a jeśli spróbujemy go wykonać, otrzymamy ładny ekran:

NastępnyDivel-ISR


I tym kończy się ten post, myślę, że jest jednym z najbardziej rozbudowanych, ale całkiem funkcjonalnych.


Zostaw swój komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

*

*

  1. Odpowiedzialny za dane: Miguel Ángel Gatón
  2. Cel danych: kontrola spamu, zarządzanie komentarzami.
  3. Legitymacja: Twoja zgoda
  4. Przekazywanie danych: Dane nie będą przekazywane stronom trzecim, z wyjątkiem obowiązku prawnego.
  5. Przechowywanie danych: baza danych hostowana przez Occentus Networks (UE)
  6. Prawa: w dowolnym momencie możesz ograniczyć, odzyskać i usunąć swoje dane.

  1.   Mezotabler powiedział

    Przerzuciłem się na LFS, jest bardziej ciągły.

  2.   Eliotime3000 powiedział

    Święty ... W każdym razie tutoriale są dobre.

  3.   sc powiedział

    Bardzo dobrze, śledzę to od początku. Czy mógłbyś dołączyć kody do każdej przyczepy?

    1.    AdrianArroyoStreet powiedział

      Masz cały kod źródłowy dostępny na GitHub: http://github.com/AdrianArroyoCalle/next-divel Stamtąd możesz pobrać ZIP, TAR.GZ lub po prostu użyć git.

  4.   dopracowany powiedział

    Hahaha, bardzo dobrze! Zatwierdzać! 🙂