Yap uzay (iyi, teknik olarak sadece bir kere): birincisi, bootloader (yol /boot/boot.s
olan) IDTR başlatır Bu yüzden Korumalı Mod'a geçerken CPU mutlu olur. idt_48:
.word 0 | idt limit=0
.word 0,0 | idt base=0L
IDTR böyle yüklenir:
lidt idt_48 | load idt with 0,0
Şimdi, atlama yapılabilir şöyle IDTR içeriğidir.
Burada IDT olmadığını unutmayın. Bu sadece bir kukla, yani çekirdeğin herhangi bir yerinde bir hata olmaz. Daha sonra, gerçek IDT başlatıldı (yol /boot/head.s
'dur). uzay böyle tahsis edilir: _idt: .fill 256,8,0 # idt is uninitialized
- o alandır CPU söyle (GDT Eğitimi bkz:
lgdt
olarak çok aynı şekilde çalışır lidt
)
lidt
beklediği IDTR'nin içeriğini içeren doğrusal adres. Yani içerik şuna benzer:
IDTR olarak başlatılır idt_descr:
.word 256*8-1 # idt contains 256 entries
.long _idt
aşağıdaki gibidir:
lidt idt_descr
- artık (BIOS varsayılan kullanmak PIC cips Programlama görmek istiyorum PIC söyle) @RossRidge için yorumlarda
belirtildiği gibi senin Soru, bu IRQ kesinti vektörleri (IVs) yeniden eşleştirmek anlamına gelir.
PIC IV'lerin Intel x86 özel durum adresleri ile çakıştığından, bunlardan birini yeniden eşleştirmeliyiz. Özel durum adresleri sabittir, bu yüzden PIC vektörlerini tekrarlamamız gerekir.
sağ Linus tarafından gelen kodunun üzerinde de bu yoruma bakın:
| well, that went ok, I hope. Now we have to reprogram the interrupts :-(
| we put them right after the intel-reserved hardware interrupts, at
| int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
| messed this up with the original PC, and they haven't been able to
| rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
| which is used for the internal hardware interrupts as well. We just
| have to reprogram the 8259's, and it isn't fun.
Şimdi, gerçek kod. Arasındaki jmp
s CPU ve PIC'yi senkronize etmek içindir, böylece CPU PIC'nin henüz alabileceği verileri göndermez. Bu, belleğe yazılırken bekleme durumları ile karşılaştırılabilir: CPU bellek/bellek ayırıcıdan daha hızlı olduğunda, bir dahaki sefere belleğe erişmeden önce biraz beklemeniz gerekir.
mov al,#0x11 | initialization sequence
out #0x20,al | send it to 8259A-1
.word 0x00eb,0x00eb | jmp $+2, jmp $+2
out #0xA0,al | and to 8259A-2
.word 0x00eb,0x00eb
mov al,#0x20 | start of hardware int's (0x20)
out #0x21,al
.word 0x00eb,0x00eb
mov al,#0x28 | start of hardware int's 2 (0x28)
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0x04 | 8259-1 is master
out #0x21,al
.word 0x00eb,0x00eb
mov al,#0x02 | 8259-2 is slave
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0x01 | 8086 mode for both
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0xFF | mask off all interrupts for now
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al
- ISR işleyicileri bir çift yaz Eğer
/kernel/traps.c
ve /kernel/asm.s
yılında işleyici kodları, hem IRQ'larin ve istisnalar istisnalar için
için (kesme hizmet yordamları bakın).
Bazı istisnalar, dışarı atmanız gereken işleyiciye atlamadan önce yığının üzerine bir hata kodu gönderir veya iret
komutu başarısız olur. Bir sayfa hatası, buna ek olarak ilgili sanal adresi cr2
'a yazar.
IRQ işleyicileri tüm sisteme yayılmıştır. -.- Zamanlayıcı ve disk kesme işleyicileri /kernel/system_call.s
'dadır, klavye kesme işleyicisi örneğin /kernel/keyboard.s
'dadır.
void trap_init(void)
{
int i;
set_trap_gate(0,÷_error);
set_trap_gate(1,&debug);
set_trap_gate(2,&nmi);
set_system_gate(3,&int3); /* int3-5 can be called from all */
set_system_gate(4,&overflow);
set_system_gate(5,&bounds);
set_trap_gate(6,&invalid_op);
set_trap_gate(7,&device_not_available);
set_trap_gate(8,&double_fault);
set_trap_gate(9,&coprocessor_segment_overrun);
set_trap_gate(10,&invalid_TSS);
set_trap_gate(11,&segment_not_present);
set_trap_gate(12,&stack_segment);
set_trap_gate(13,&general_protection);
set_trap_gate(14,&page_fault);
set_trap_gate(15,&reserved);
set_trap_gate(16,&coprocessor_error);
for (i=17;i<32;i++)
set_trap_gate(i,&reserved);
/* __asm__("movl $0x3ff000,%%eax\n\t"
"movl %%eax,%%db0\n\t"
"movl $0x000d0303,%%eax\n\t"
"movl %%eax,%%db7"
:::"ax");*/
}
IRQ işleyicisi:
- istisnalar için başlatma
trap_init
fonksiyonunda /kernel/traps.c
yapılır
uygun tanımlayıcılarında ISR işleyicileri adreslerini koyun Giriş başlatmaları tekrar birkaç dosyaya yayılır. Örneğin, /kernel/sched.c
numaralı telefondan sched_init
, zamanlayıcı kesme işleyici adresini başlatır.
- (PIC) IRQ maskeli desteklenen tüm kesmeler Bu makro
sti
ile main
fonksiyonunda /init/main.c
yapılır
etkinleştirin.
#define sti() __asm__ ("sti"::)
üçüncü adım, standart BIOS eşleştirmeleri kesmeler yeniden eşleme işlemlerinde olağan anlamına gelir: Bu, aşağıdaki gibi
/asm/system.h
tanımlanmıştır. Normalde IRQ 0-7, INT 8-15 ile eşleştirilir ve IRQ 8-15, INT 0x70-0x77 ile eşlenir. Eski haritalama bir sorun yaratıyor çünkü bir dizi CPU istisnası INT 8-15 aralığındadır, bu nedenle çoğu işletim sistemi en az IRQ 0-7'yi CPU istisnaları için ayrılmış aralık dışında bir şeye geri getirmektedir –Bu, PIT anlamına gelir. , IRQ 0'a bağlanır, INT 8 oluşturur. INT 0, tamsayı bölme taşmasıdır (sıfıra bölün) özel durumudur. –
IRQ'ları ilk 32 IDT girişlerinin üzerine taşımak için 3. adımı gerçekleştirmeniz önerilir, çünkü bunlar tuzaklar için kullanılır. Ayrıca, ilk 32 için biraz işleyici koymanızı öneririm, böylece bir sorunla karşılaşıp karşılaşmadığınızı görebilirsiniz. [Ve aa değişkeniniz için uçucu kullanın! –