Timer 如何使用可编程中断控制器PIC和可编程间隔定时器PIT在内核上调度进程?
在我的“wannabe内核”中,我成功地在保护模式下通过IDT启用了软件中断处理。现在我转向硬件中断,以便能够为进程分配时间片。问题是我的内核没有收到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
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