Timer 如何使用可编程中断控制器PIC和可编程间隔定时器PIT在内核上调度进程?

Timer 如何使用可编程中断控制器PIC和可编程间隔定时器PIT在内核上调度进程?,timer,x86,operating-system,pic,osdev,Timer,X86,Operating System,Pic,Osdev,在我的“wannabe内核”中,我成功地在保护模式下通过IDT启用了软件中断处理。现在我转向硬件中断,以便能够为进程分配时间片。问题是我的内核没有收到PIT的任何中断 inline void outb(uint8_t port,unsigned char value) { __asm__ __volatile__ ("outb %%ax,%%dx": :"d" (port), "a" (value)); } static inline uint8_t in

在我的“wannabe内核”中,我成功地在保护模式下通过IDT启用了软件中断处理。现在我转向硬件中断,以便能够为进程分配时间片。问题是我的内核没有收到PIT的任何中断

inline void outb(uint8_t port,unsigned char value)
    {
       __asm__ __volatile__ ("outb %%ax,%%dx": :"d" (port), "a" (value));
    }

    static inline uint8_t inb(uint16_t port)
    {
        uint8_t ret;
        __asm__ __volatile__ ( "inb %1, %0" : "=a"(ret) : "d"(port) );
        return ret;
    }

    #define PIC1    0x20
    #define PIC2  0xA0   
    #define PIC1_COMMAND    PIC1
    #define PIC1_DATA       (PIC1+1)
    #define PIC2_COMMAND    PIC2
    #define PIC2_DATA       (PIC2+1)

    #define ICW1_ICW4       0x01        
    #define ICW1_SINGLE     0x02        
    #define ICW1_INTERVAL4  0x04        
    #define ICW1_LEVEL      0x08        
    #define ICW1_INIT       0x10        

    #define ICW4_8086       0x01    
    #define ICW4_AUTO       0x02        
    #define ICW4_BUF_SLAVE  0x08
    #define ICW4_BUF_MASTER 0x0C    
    #define ICW4_SFNM       0x10

    void init_pic()
    {
        unsigned char a1, a2;
        unsigned offset_master = 0x20;
        unsigned offset_slave = 0x28;
        a1 = inb(PIC1_DATA);                        
        a2 = inb(PIC2_DATA);

        outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4);  
        outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
        outb(PIC1_DATA, offset_master);                 
        outb(PIC2_DATA, offset_slave);                 
        outb(PIC1_DATA, 4);                      
        outb(PIC2_DATA, 2);                       
        outb(PIC1_DATA, ICW4_8086);
        outb(PIC2_DATA, ICW4_8086);
        outb(PIC1_DATA, a1); 
        outb(PIC2_DATA, a2);
    }

    #define PIT_COMMAND 0x43
    #define PIT_DATA1   0x40
    #define PIT_DATA2   0x41
    #define PIT_DATA3   0x42

    void init_pit()
    {
       uint32_t divisor = 1193180 / 50;

       outb(PIT_COMMAND, 0x36);

       uint8_t l = (uint8_t)(divisor & 0xFF);
       uint8_t h = (uint8_t)( (divisor>>8) & 0xFF );

       outb(PIT_DATA1, l);
       outb(PIT_DATA1, h);  
    }
以及计时器处理程序

    unsigned tick = 0;
    void timerHandler()
    {
       tick++;
       char* ascii_code;
       itoa(ascii_code, 'd', tick);
       terminal_writestring("PIT Tick: ", &terminal);
       terminal_writestring(ascii_code, &terminal);
       terminal_writestring("\n", &terminal);
    }
bochs没有提供isse原因的详细信息:

00122970752e[CPU0  ] interrupt(): gate descriptor is not valid sys seg       (vector=0x20)
00122970752e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00122970752e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
我以和软件中断处理程序相同的方式(只是条目号不同)注册到IDT定时器处理程序。
按要求编辑:IDT设置代码:

    struct __InteruptDescriptorTableEntry
    {
       uint16_t offset_low;
       uint16_t selector; 
       uint8_t zero;      
       uint8_t type_attr; 
       uint16_t offset_up; 
    } __attribute__((packed));
    typedef struct __InteruptDescriptorTableEntry IDTEntry;

    struct _ITD_PTR
    {
        uint16_t idtSize;
        uint32_t idtBaseAddr;
    } __attribute__((packed));
    typedef struct _ITD_PTR _IDT_PTR;

    void zeroIDT()
    {   
        unsigned i;
        for(i=0;i<NUM_IDT_ENTRIES-1;++i)
        {
            IDTEntry nullIDTEntry = fillIDTEntry(0,0,0);
            registerInterupt(nullIDTEntry, i);
        }
    }

    void registerInterupt(const IDTEntry entry, const unsigned intNo)
    {
        if(intNo < NUM_IDT_ENTRIES)
            InteruptDescriptorTable[intNo] = entry;
    }

    #define LOW_FUN_ADDR(fun) ( (uint32_t)fun & 0xFFFF )
    #define UP_FUN_ADDR(fun) ( (uint32_t)fun >> 16) & 0xFFFF

    IDTEntry fillIDTEntry(uint32_t intHandler,
                          uint16_t selector,   
                          uint8_t type_attr)

    {   IDTEntry newEntry;
        newEntry.offset_low = LOW_FUN_ADDR(intHandler); 
        newEntry.selector = selector; 
        newEntry.zero = 0;     
        newEntry.type_attr = type_attr;
        newEntry.offset_up = UP_FUN_ADDR(intHandler);
        return newEntry;
    }

    extern void _lidt(_IDT_PTR* idtPtr);
    void timerHandler_TEST();

    void loadIDT()
    {
        zeroIDT();
        _IDT_PTR idtPtr;
        idtPtr.idtSize = sizeof(struct __InteruptDescriptorTableEntry)*256 - 1;
        idtPtr.idtBaseAddr = (uint32_t) &InteruptDescriptorTable;

        IDTEntry printOnScreenInt = fillIDTEntry((uint32_t)interupt_pritnOnScreen, 0x18, 0xee);
        registerInterupt(printOnScreenInt, 50);

        IDTEntry timerIntEntry = fillIDTEntry((uint32_t)timerHandler_TEST, 0x18, 0xee);
        registerInterupt(printOnScreenInt, 13);
        _lidt(&idtPtr);
    }
编辑2:我已经将PIT的面具改为:

a1 = 0x7F; //master                        
a2 = 0xFF; //slave
仅接收PIT int,但未交付IRQ(无三重故障)。
编辑3:
info-gdt
info-IDT

IDT[0x20]=32-Bit Interrupt Gate target=0x0018:0x001009c0, DPL=3
IDT[0x32]=32-Bit Interrupt Gate target=0x0018:0x001009c0, DPL=3

GDT:
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x01]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
GDT[0x02]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
GDT[0x03]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
GDT[0x04]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
GDT[0x05]=32-Bit TSS (Busy) at 0x00101000, length 0x00068

我们需要您输入设置代码,而不是所有这些代码,因为这与您的错误无关。@user35443 code postedA旁注-您可能希望中断门使用
0x8e
,而不是
0xee
,否则用户空间将能够使用
int
指令调用这些处理程序。@Luaan:是的,他这样做了;请注意,中断触发错误在向量0x20上。@Luaan:捕捉得很好,尽管它看起来有点像输入错误(特别是在查看
info idt
输出时)。
IDT[0x20]=32-Bit Interrupt Gate target=0x0018:0x001009c0, DPL=3
IDT[0x32]=32-Bit Interrupt Gate target=0x0018:0x001009c0, DPL=3

GDT:
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x01]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
GDT[0x02]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
GDT[0x03]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
GDT[0x04]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
GDT[0x05]=32-Bit TSS (Busy) at 0x00101000, length 0x00068