En ĉi tiu kvina epizodo ni vidos tabelon sufiĉe similan al la GDT kaj teorie kaj uzate, ni aludas la IDT. IDT signifas Priskriba Tablo de Interrompoj y estas tablo uzata por trakti interrompojn okazantajn. Ekzemple, iu dividas per 0, la funkcio zorge de prilaborado nomiĝas. Ĉi tiuj funkcioj estas la ISR (Interrompi Servajn Rutinojn). Do ni kreu la IDT kaj aldonu iom da ISR.
Unue ni deklaros la strukturojn respondajn al la 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));
Kiel videblas, se vi komparas ĝin kun la GDT, la Ptr-strukturo estas identa kaj la Eniro estas sufiĉe simila. Tial la funkcioj meti eniron (SetGate) kaj instali (Instali) estas tre similaj.
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;
}
Instali:
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();
Se ni rigardas, ni vidos, ke la instalfunkcio uzas la funkcion ND :: Memory :: Set, kiun ni deklaris en la alia afiŝo. Ni ankaŭ povas aprezi, kiel ni ankoraŭ ne vokas al SetGate kaj ni vokas ND :: IDT :: Flush, por ĉi tiu funkcio ni uzas la asm-volatilan aserton denove:
asm volatile("lidtl (idtptr)");
Se ĉio funkcias bone kaj ni faras estetikan aranĝon, ĝi aspektu tiel:
Bone, nun ni komencos plenigi la IDT per interrompoj. Ĉi tie mi kreos nur unu, sed cetere estus same. Mi faros la dividon per nula paŭzo. Kiel vi bone scias en matematiko, nombro ne povas esti dividita per 0. Se tio okazas en la procesoro, escepto estiĝas, ĉar ĝi ne povas daŭri. En IDT la unua interrompo en listo (0) respondas al ĉi tiu evento.
Ni aldonas ĉi tion inter la memora agordo kaj la flush ene de la Instala funkcio de la IDT:
ND::IDT::SetGate(0,(unsigned)ND::ISR::ISR1,0x08,0x8E);
La revokfunkcio estos ND :: ISR :: ISR1 kiu estas sufiĉe simpla kvankam ni devas uzi ASM:
void ND::ISR::ISR1()
{
asm volatile(
"cli \n"
"pushl 0 \n"
"pushl 0 \n"
"jmp ND_ISR_Common \n"
);
}
ND_ISR_Common ni difinos ĝin kiel funkcion en lingvo C. Por konservi dosierojn kaj plibonigi legeblecon, ni povas uzi eksteran "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"
);
}
Ĉi tiu kodo en ASM povas esti iomete malfacile komprenebla, sed tio estas ĉar ni deklaros strukturon en C por aliri la datumojn generitajn de la interrompo. Evidente, se vi ne volus tion, vi povus simple nomi la Kernan Panikon en ND :: ISR :: ISR1 aŭ io simila. La strukturo havas formon tian, ke:
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;
};
Kaj fine ni faras la funkcion ND_ISR_Handler (ankaŭ kun C-ligilo) en kiu ni montras kernan panikon kaj malgrandan priskribon de la eraro laŭ tiu, kiun ni havas en listo de eraroj.
extern "C"
void ND_ISR_Handler(struct regs *r)
{
if(r->int_no < 32) { ND::Panic::Show(exception_messages[r->int_no]);
for(;;);
}
}
Bone kaj per ĉi tio ni jam povas trakti ĉi tiun interrompon. Kun la resto de interrompoj okazus simile krom ke estas iuj, kiuj redonas parametrojn, kaj ni uzus la reg-strukturon por akiri ĝin. Tamen vi eble demandos vin, kiel ni scias, ĉu ĝi vere funkcias. Por provi ĉu ĝi funkcias, ni enkondukos simplan linion post la ND :: IDT :: Install ():
int sum=10/0;
Se ni kompilas, ĝi donos al ni averton kaj se ni provos plenumi ĝin, ni ricevos belan ekranon:
Kaj kun ĉi tio finiĝas ĉi tiu afiŝo, mi pensas, ke ĝi estas unu el la plej ampleksaj sed sufiĉe funkciaj.
5 komentoj, lasu la viajn
Mi ŝanĝis al LFS, ĝi estas pli kontinua.
Sankta ... Ĉiuokaze la lerniloj estas bonaj.
Tre bone, mi sekvas ĝin ekde la komenco. Ĉu vi povus kunigi la kodojn al ĉiu antaŭfilmo?
Vi havas la tutan fontkodon havebla ĉe GitHub: http://github.com/AdrianArroyoCalle/next-divel De tie vi povas elŝuti ZIP, TAR.GZ aŭ simple uzi git.
Hahaha tre bone! Aprobu! 🙂