2016-01-01 14 views
5

Korunan mod için kesintileri ayarlama işlemi nedir?Korunmuş modda kesintileri ayarlama (x86)

This bağlantı biri olmalıdır diyor ki:: kesme tanımlayıcı masanın

  • için

    • Yap uzay uzay (lgdt olarak çok aynı şekilde çalışır lidt GDT Eğitimi bakınız) CPU söyle
    • PIC'ye artık BIOS varsayılanlarını kullanmak istemediğinizi söyleyin (bkz. PIC çiplerini programlama)
    • Hem IRQ'lar hem de istisnalar için birkaç ISR işleyicisi yazın (Hizmet Hizmetlerini Kesme konusuna bakın)
    • (PIC) IRQ maskeli desteklenen tüm kesmeler

    Üçüncü adım bana hiç mantıklı Enable (Ben baktım

  • uygun tanımlayıcılarında ISR işleyicileri adreslerini koyun this link ama PIC bir şey söylemek hakkında hiçbir şey yoktu, bu yüzden onu yok saydım ve sonraki iki adımı tamamladı, sadece son adımı ulaştığında bir kez daha clueless olmak için. Ancak, kesinti anlayışımdan, anlamadığım her iki adım da PIC denetleyicisinden gelen donanım kesintileriyle ilgilidir ve PIT tarafından IRQ 0'da ortaya çıkan kesintileri etkilememelidir. Bu nedenle bu adımı da göz ardı ettim.

    Kodumu çalıştırdığımda düzgün bir şekilde derlendi ve hatta sanal bir makinede çalıştı, ancak kesinti yalnızca bir kez ateş gibi görünüyordu. Daha sonra PIC'ye EOI göndermediğimi fark ettim ve daha fazla kesinti olmasını engelledim. Ancak mov al, 0x20 ve out 0x20, al komutlarının eklenmesi, iret komutunun sanal makine çökmesini sağlar.

    İşte
    ; idt 
    idt_start : 
    
        dw 0x00   ; The interrupt handler is located at absolute address 0x00 
        dw CODE_SEG  ; CODE_SEG points to the GDT entry for code 
        db 0x0   ; The unused byte 
        db 0b11101001 ; 1110 Defines a 32 bit Interrupt gate, 0 is mandatory, privilege level = 0 (0b00), the last bit is one so that the CPU knows that the interrupt will be used 
        dw 0x00   ; The higher part of the offset (0x00) is 0x00 
    
    idt_end: 
    
    idt_descriptor : 
        dw idt_end - idt_start - 1 ; Size of our idt, always one less than the actual size 
        dd idt_start ; Start address of our idt 
    

    benim kesme işleyici (bellekte mutlak konumda 0x00 bulunan) oluyor:

    İşte benim IDT var

    ISR_0: 
        push eax 
        add [0x300], byte 
        mov al, 0x20 
        out 0x20, al 
        pop eax 
        iret  
        times 512-($-$$) db 0 
    

    Bu benim GDT korumalı moduna girmek ve yüklemek için kullanın koddur ve IDT belleğe:

    Ana işlevim (0x300 değerini denetler) aşağıdaki gibidir: Bu arada

    void main() { 
        char iii[15]; 
        int * aa = (int *)0x300; 
        for (;;) 
        { 
         setCursor(0, 0); 
         print(itoab(*aa, iii)); 
        } 
    } 
    

    , ben her şeyin doğru adrese yüklendi ve her şeyin beklendiği tam burada yer almaktadır ki bir bellek dökümü kullanarak doğruladıktan. Örneğin, 0x300, kodumu basitleştirmek için kullanılan belleğin ücretsiz bir parçasıdır.

  • +1

    üçü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 –

    +0

    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. –

    +0

    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! –

    cevap

    6

    Bakalım kumu biraz kıyaslanabilir, yani Linux 0.01 bunu yapıyor!Bu iki kere yapılır

    kesme tanımlayıcı tablo için

    • 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,&divide_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"::) 
      
    +0

    Detaylı cevap için teşekkürler! Her şey şimdi çalışıyor gibi görünüyor, sadece, donanım kesmeler ateş değil - int 'çağrısı PIT interrupt işleyici 'int 32' çağıran çağrılıyor, ancak 'sti' talimatı sonra bile PIT kesinti ateş asla .. – DividedByZero