การจำลอง Linus Torvalds: สร้างระบบปฏิบัติการของคุณเองตั้งแต่เริ่มต้น (VI)

เอาล่ะ หลังจากพักสักครู่ เรามาดำเนินการต่อในชุดบทเรียนของเรากัน หากเรากลับไปดูโค้ดก่อนหน้านี้ เราควรจะมี ISR สำหรับการหารด้วยศูนย์แล้ว ตอนนี้เราต้องเติม ISR ที่เหลือซึ่งเราได้ตั้งค่าข้อความไว้ก่อนหน้านี้ (32 ตัวแรก) ตอนนี้เราจะดำเนินการเขียนโปรแกรมการขัดจังหวะต่อไป เราจะสร้าง IRQ หรือที่เรียกว่าInterrupt Request IRQ เหล่านี้ถูกสร้างขึ้นโดยอุปกรณ์ฮาร์ดแวร์ เช่น คีย์บอร์ด เมาส์ เครื่องพิมพ์ เป็นต้น ในตอนแรก IRQ 8 ตัวแรกจะถูกแมปไปยังตำแหน่ง IDT ที่ 8 ถึง 15 โดยอัตโนมัติ เนื่องจากเราใช้ 32 ตัวแรกสำหรับข้อยกเว้นแล้ว ตอนนี้เราต้องแมปใหม่ เราจะกำหนด IRQ ตั้งแต่ 32 ถึง 45 ในการทำเช่นนี้ เราต้องแมป IRQ ใหม่ก่อน:

void ND::IRQ::Remap(int pic1, int pic2)
{
#define PIC1 0x20
#define PIC2 0xA0
#define ICW1 0x11
#define ICW4 0x01
/* send ICW1 */
ND::Ports::OutputB(PIC1, ICW1);
ND::Ports::OutputB(PIC2, ICW1);
/* send ICW2 */
ND::Ports::OutputB(PIC1 + 1, pic1); /* remap */
ND::Ports::OutputB(PIC2 + 1, pic2); /* pics */
/* send ICW3 */
ND::Ports::OutputB(PIC1 + 1, 4); /* IRQ2 -> connection to slave */
ND::Ports::OutputB(PIC2 + 1, 2);
/* send ICW4 */
ND::Ports::OutputB(PIC1 + 1, ICW4);
ND::Ports::OutputB(PIC2 + 1, ICW4);
/* disable all IRQs */
ND::Ports::OutputB(PIC1 + 1, 0xFF);
}

ตอนนี้เราสร้างฟังก์ชั่นเพื่อติดตั้ง IRQ:

void ND::IRQ::Install()
{
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_BLACK);
ND::Screen::PutString("\nInstalling IRQ...");
ND::IRQ::Remap(0x20,0x28);
ND::IDT::SetGate(32,(unsigned)ND::IRQ::IRQ1,0x08,0x8E);
ND::IDT::SetGate(33,(unsigned)ND::IRQ::IRQ2,0x08,0x8E);
ND::IDT::SetGate(34,(unsigned)ND::IRQ::IRQ3,0x08,0x8E);
ND::IDT::SetGate(35,(unsigned)ND::IRQ::IRQ4,0x08,0x8E);
ND::IDT::SetGate(36,(unsigned)ND::IRQ::IRQ5,0x08,0x8E);
ND::IDT::SetGate(37,(unsigned)ND::IRQ::IRQ6,0x08,0x8E);
ND::IDT::SetGate(38,(unsigned)ND::IRQ::IRQ7,0x08,0x8E);
ND::IDT::SetGate(39,(unsigned)ND::IRQ::IRQ8,0x08,0x8E);
ND::IDT::SetGate(40,(unsigned)ND::IRQ::IRQ9,0x08,0x8E);
ND::IDT::SetGate(41,(unsigned)ND::IRQ::IRQ10,0x08,0x8E);
ND::IDT::SetGate(42,(unsigned)ND::IRQ::IRQ11,0x08,0x8E);
ND::IDT::SetGate(43,(unsigned)ND::IRQ::IRQ12,0x08,0x8E);
ND::IDT::SetGate(44,(unsigned)ND::IRQ::IRQ13,0x08,0x8E);
ND::IDT::SetGate(45,(unsigned)ND::IRQ::IRQ14,0x08,0x8E);
ND::IDT::SetGate(46,(unsigned)ND::IRQ::IRQ15,0x08,0x8E);
ND::IDT::SetGate(47,(unsigned)ND::IRQ::IRQ16,0x08,0x8E);
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_GREEN);
ND::Screen::PutString("done");
asm volatile("sti");
}

ประโยคของ asm STI เราเปิดใช้งาน IRQ ตอนนี้เราไปกับสิ่งที่คล้ายกับ ISR หน้าที่ของ IRQ พื้นฐาน:

void ND::IRQ::IRQ1()
{
asm volatile(
"cli \n"
"pushl 0\n"
"pushl 32\n"
"jmp ND_IRQ_Common"
);
}

ส่วนทั่วไป (เช่นเดียวกับ ISR):

extern "C"
void ND_IRQ_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_IRQ_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"
);
}

และตัวจัดการพื้นฐาน:

extern "C"
void ND_IRQ_Handler(struct regs* r)
{
void (*handler)(struct regs *r);
if(r->int_no >= 40)
{
ND::Ports::OutputB(0xA0,0x20);
}
ND::Ports::OutputB(0x20,0x20);
}

ด้วยสิ่งนี้เราควรเปิดใช้งาน IRQ แล้วแม้ว่าจะยังไม่ได้ทำอะไรก็ตาม ในบทต่อไปเราจะดูวิธีรับข้อมูลจาก IRQ เหล่านี้เช่นนาฬิกาหรือแป้นพิมพ์

ถัดไป


และด้วยสิ่งนี้จะสิ้นสุดลง อย่างที่คุณเห็นตอนนี้ฉันเขียนน้อยลงเป็นประจำเนื่องจากปัญหาอื่น ๆ อย่างไรก็ตามฉันจะดำเนินการต่อไปจนกว่าฉันจะมีระบบปฏิบัติการที่สมบูรณ์ยิ่งขึ้น


เพิ่มเป็นแหล่งข้อมูลที่ต้องการใน Google