2016-01-01 6 views
5

संरक्षित मोड के लिए इंटरप्ट सेट करने की प्रक्रिया क्या है?संरक्षित मोड में इंटरप्ट्स सेट करना (x86)

This लिंक कहते हैं एक चाहिए::

  • बाधा डिस्क्रिप्टर तालिका
  • के लिए मेक अंतरिक्ष सीपीयू जहां कि अंतरिक्ष है (lidt lgdt के रूप में बहुत उसी तरह काम करता देख GDT ट्यूटोरियल) बताओ
  • पीआईसी को बताएं कि अब आप BIOS डिफ़ॉल्ट का उपयोग नहीं करना चाहते हैं (पीआईसी चिप्स प्रोग्रामिंग देखें)
  • आईआरक्यू और अपवाद दोनों के लिए कुछ आईएसआर हैंडलर (इंटरप्ट सेवा रूटीन देखें) लिखें
  • उचित वर्णनकर्ता
  • आईआरक्यू नकाब में सभी समर्थित बीच में आता है (पीआईसी की)

तीसरे चरण में मेरे लिए कोई मतलब नहीं है सक्षम करें (मैं को देखा में ISR संचालकों के पते रखो this लिंक लेकिन पीआईसी को कुछ भी बताने के बारे में कुछ भी नहीं था) इसलिए मैंने इसे अनदेखा कर दिया और अगले दो चरणों को पूरा किया, केवल एक बार फिर जब मैं अंतिम चरण तक पहुंचा तो अनजान हो गया। हालांकि, इंटरप्ट्स की मेरी समझ से, दोनों चरणों को मैं समझ नहीं पाया था कि पीआईसी नियंत्रक से हार्डवेयर इंटरप्ट्स से संबंधित है और आईआरक्यू 0 पर पीआईटी द्वारा उठाए गए इंटरप्ट को प्रभावित नहीं करना चाहिए। इसलिए मैंने इस चरण को भी नजरअंदाज कर दिया।

जब मैंने अपना कोड चलाया तो यह ठीक हो गया और वर्चुअल मशीन में भी भाग गया, लेकिन अंतराल केवल एक बार आग लग रहा था। तब मुझे एहसास हुआ कि मैं पीआईसी को ईओआई नहीं भेज रहा था, इसे और अधिक बाधाओं को बढ़ाने से रोक रहा था। हालांकि, निर्देश से पहले mov al, 0x20 और out 0x20, al जोड़ना निर्देश वर्चुअल मशीन क्रैश बनाता है।

; 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 

यहाँ मेरी बाधा हैंडलर (स्मृति में पूर्ण स्थान 0x00 पर स्थित) है:

यहाँ मेरी IDT है

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

इस कोड मैं सुरक्षित मोड में प्रवेश करने और GDT लोड करने के लिए उपयोग करें और आईडीटी में स्मृति:

[bits 16] 

switch_to_pm: 

    cli 
    lgdt [gdt_descriptor] 
    lidt [idt_descriptor] 
    mov eax, cr0 
    or eax, 1 
    mov cr0,eax 
    jmp CODE_SEG:init_pm 

[bits 32] 

init_pm : 

    mov ax, DATA_SEG 
    mov ds, ax 
    mov ss, ax 
    mov es, ax 
    mov fs, ax 
    mov gs, ax 
    mov ebp, 0x90000 
    mov esp, ebp 
    sti 
    call BEGIN_PM 

मेरा मुख्य कार्य (जो 0x300 के मान की जांच करता है) निम्नानुसार है:

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

वैसे, मैं एक स्मृति डंप का उपयोग कर कि सब कुछ सही पते पर लोड किया जाता है और सब कुछ बिल्कुल जहां यह उम्मीद है है सत्यापित किया है। उदाहरण के लिए, 0x300 बस मेरे कोड को सरल बनाने के लिए उपयोग की गई स्मृति का एक नि: शुल्क हिस्सा है।

+1

तीसरे चरण उनके मानक BIOS मैपिंग से बीच में आता है remapping के सामान्य प्रक्रिया को संदर्भित करता है: यह /asm/system.h में इस प्रकार परिभाषित किया गया है। आम तौर पर आईआरक्यू 0-7 को आईएनटी 8-15 में मैप किया जाता है, और आईआरक्यू 8-15 को आईएनटी 0x70-0x77 में मैप किया जाता है। पूर्व मैपिंग में समस्या आई है क्योंकि आईएनटी 8-15 में कई सीपीयू अपवाद हैं, इसलिए अधिकांश ऑपरेटिंग सिस्टम कम से कम आईआरक्यू 0-7 को सीपीयू अपवाद –

+0

के लिए आरक्षित सीमा के बाहर रीमेप करते हैं ध्यान दें कि इसका अर्थ है पीआईटी , जो आईआरक्यू 0 से जुड़ा हुआ है, INT 8. उत्पन्न करता है INT 0 पूर्णांक विभाजित ओवरफ़्लो (शून्य से विभाजित) अपवाद है। –

+0

आईआरक्यू की पहली 32 आईडीटी प्रविष्टियों के ऊपर जाने के लिए चरण 3 करने की अत्यधिक अनुशंसा की जाती है, क्योंकि इन्हें जाल के लिए उपयोग किया जाता है। मैं उन पहले 32 के लिए कुछ हैंडलर डालने की अत्यधिक अनुशंसा करता हूं, ताकि आप देख सकें कि क्या आप किसी समस्या में भाग लेते हैं या नहीं। [और अपने एए चर के लिए volatiled उपयोग करें! –

उत्तर

6

चलिए देखते हैं कि कुछ तुलनात्मक रूप से छोटे कर्नेल, यानी, Linux 0.01 ऐसा करता है!बाधा डिस्क्रिप्टर तालिका

यह दो बार किया जाता है के लिए

  • मेक अंतरिक्ष (ठीक है, तकनीकी रूप से केवल एक बार): पहला, बूटलोडर (पथ /boot/boot.s है) initializes आई डी टी आर , इसलिए संरक्षित मोड में कूदते समय सीपीयू खुश है।

    idt_48: 
        .word 0   | idt limit=0 
        .word 0,0  | idt base=0L 
    

    आई डी टी आर इस तरह भरी हुई है:

    lidt  idt_48  | load idt with 0,0 
    

    अब, कूद प्रदर्शन किया जा सकता आई डी टी आर सामग्री इस प्रकार है।
    ध्यान दें कि यहां कोई आईडीटी नहीं है। यह सिर्फ एक डमी है, इसलिए कर्नेल में कहीं भी कोई त्रुटि नहीं होती है।

    बाद में, असली आईडीटी प्रारंभ किया गया है (पथ /boot/head.s है)। अंतरिक्ष इस तरह आवंटित होता है,

    _idt: .fill 256,8,0  # idt is uninitialized 
    
    • सीपीयू जहां कि अंतरिक्ष है बताओ (देखें GDT ट्यूटोरियल: lidtlgdt के रूप में बहुत उसी तरह काम करता)

    lidt उम्मीद एक आईडीटीआर की सामग्री युक्त रैखिक पता। यही कारण है कि सामग्री इस तरह दिखता है:

    idt_descr: 
        .word 256*8-1  # idt contains 256 entries 
        .long _idt 
    

    आई डी टी आर के रूप में आरंभ नहीं हो जाता इस प्रकार है:

    lidt idt_descr 
    
    • पीआईसी है कि आप अब BIOS चूक (का उपयोग पीआईसी चिप्स प्रोग्रामिंग देखना चाहते हैं बताओ)

    @RossRidge को टिप्पणी में उल्लेख किया है अपने सवाल, इसका मतलब है कि आईआरक्यू इंटरप्ट वैक्टर (आईवीएस) को रीमेप करना।
    चूंकि पीआईसी चतुर्थ इंटेल x86 अपवाद पते के साथ ओवरलैप करते हैं, इसलिए हमें उनमें से एक को रीमेप करना होगा। अपवाद पते हार्ड-वायर्ड हैं, इसलिए हमें पीआईसी वैक्टरों को रीमेप करने की आवश्यकता है।
    भी इस टिप्पणी देखें सही लीनुस द्वारा इसी कोड के ऊपर:

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

    अब, यहाँ असली कोड है। jmp एस बीच में सीपीयू और पीआईसी सिंक्रनाइज़ करने के लिए हैं, इसलिए सीपीयू डेटा नहीं भेज पाएगा जिसे पीआईसी अभी तक प्राप्त नहीं हो सकता है। स्मृति में लिखते समय यह राज्यों की प्रतीक्षा करने के लिए तुलनीय है: जब सीपीयू मेमोरी/मेमोरी आर्बिटर से तेज़ होता है, तो अगली बार मेमोरी एक्सेस करने से पहले इसे कुछ समय इंतजार करना पड़ता है।

    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 संचालकों की एक जोड़ी लिखें दोनों IRQs और अपवादों

    अपवादों के लिए के लिए (इंटरप्ट सेवा दिनचर्या देखें), /kernel/traps.c और /kernel/asm.s में हैंडलर कोड पा सकते हैं।
    कुछ अपवाद हैंडलर पर कूदने से पहले स्टैक पर एक त्रुटि कोड दबाते हैं, जिसे आपको पॉप करना होगा या iret निर्देश विफल हो जाएगा। एक पेज गलती भी संबंधित वर्चुअल एड्रेस को cr2 पर लिखती है।
    आईआरक्यू हैंडलर पूरे सिस्टम में फैले हुए हैं। -.- टाइमर और डिस्क इंटरप्ट हैंडलर /kernel/system_call.s में हैं, उदाहरण के लिए कीबोर्ड इंटरप्ट हैंडलर /kernel/keyboard.s में है।

    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");*/ 
    } 
    

    आईआरक्यू हैंडलर:

    • उचित वर्णनकर्ता

    अपवाद के लिए प्रारंभ trap_init समारोह में /kernel/traps.c में किया जाता है में ISR संचालकों के पते रखो प्रवेश प्रारंभिकरण फिर से कई फाइलों में फैल गए हैं। उदाहरण के लिए sched_init/kernel/sched.c टाइमर इंटरप्ट हैंडलर का पता शुरू करता है।

    • (पीआईसी की) आईआरक्यू नकाब में सभी समर्थित बीच में आता है

    इस मैक्रो sti साथ main समारोह में /init/main.c में किया जाता है सक्षम करें।

    #define sti() __asm__ ("sti"::) 
    
+0

विस्तृत उत्तर के लिए धन्यवाद! सबकुछ अब काम कर रहा प्रतीत होता है, केवल हार्डवेयर इंटरप्ट्स फायरिंग नहीं कर रहे हैं - 'int 32' को कॉल करने से पीआईटी इंटरप्ट हैंडलर को आग लगती है, हालांकि' एसआईआई 'निर्देश के बाद भी पीआईटी बाधा कभी नहीं होती है .. – DividedByZero

संबंधित मुद्दे