您的位置:首页 > 其它

interrupt.c

2011-06-05 22:55 134 查看
pintos中的中断有256个即0-255.
void *frame_pointer; 是一个frame总会有个指针
void (*eip) (void); 下一个执行的指令的地址。
void *esp; stack pointer 栈指针
IDT(Interrupt Descriptor Table)是一个描述interrupt的数组,即idt[INTR_CNT];
PIC(可编程中断控制器):外设发出中断请求需要PIC进行处理。
当发生中断时先调用intrNN_stub();这是用汇编写的。接着调用intr_entry();即把intr_frame放入栈中。最后调用intr_handler()执行特定注册过的中断。
intr_handler();返回后则恢复现场,即把栈中的CPU寄存器的值都恢复。
intr_frame里面的都是CPU寄存器的值,我们在中断时所要做的事就是保存现场,而这就是一个现场,我们只要把这个放入栈中即可。
static intr_handler_func *intr_handlers[INTR_CNT];这个就是对应每个中断处理函数。
static unsigned int unexpected_cnt[INTR_CNT];这个是记录了每个中断里没有注册中断处理函数的计数。
static bool yield_on_return;一般外部中断是不能yield或sleep。
intr_init() 函数把中断的一些基本配置都配好了。0-19都是有原因的中断,20以上就是unknown。

//-------------------------------------------------------------------------------------------------------------------------------------------
static void
register_handler (uint8_t vec_no, int dpl, enum intr_level level,
intr_handler_func *handler, const char *name)
{
ASSERT (intr_handlers[vec_no] == NULL);
if (level == INTR_ON)
idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
else
idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
intr_handlers[vec_no] = handler;
intr_names[vec_no] = name;
}
这个函数的意思是vec_no的中断调用了这个函数,调用handler这个函数的前提是vec_no的中断执行程序还没有被注册。
这样这个函数就可以把handler注册为中断处理程序,dpl(descriptor privilege level)只有两种取值,第一种为3,意思是允许用户模式中断,第二种0,意思是禁止中断。
如果level是打开中断,则把idt[vec_no]描述为make_trap_gate.并且把intr_handler[vec_no]赋值,name也赋值。
void
intr_register_ext (uint8_t vec_no, intr_handler_func *handler,
const char *name)
{
ASSERT (vec_no >= 0x20 && vec_no <= 0x2f);
register_handler (vec_no, 0, INTR_OFF, handler, name);
}
这个函数的作用是注册外部中断的处理函数,因此dpl=0,因为外部中断必须是设备发出的信号,因此不可能是用户进程调用的,INTR_OFF说明处理函数时不能中断。

static uint64_t
make_gate (void (*function) (void), int dpl, int type)
type有两种取值,第一种14,意思是进入中断并且禁止中断,第二种15,意思是进入中断开启中断。这个函数的目的是为了打开一扇门能调用handler。
static uint64_t
make_intr_gate (void (*function) (void), int dpl)
{
return make_gate (function, dpl, 14);
}
因此interrupt gate是禁止中断,所以type是14.
static uint64_t
make_trap_gate (void (*function) (void), int dpl)
{
return make_gate (function, dpl, 15);
}
这里为15.开启中断。
void
intr_register_ext (uint8_t vec_no, intr_handler_func *handler,
const char *name)
{
ASSERT (vec_no >= 0x20 && vec_no <= 0x2f);
register_handler (vec_no, 0, INTR_OFF, handler, name);
}
是注册外部中断的程序,因此把dpl设为0,即禁止中断,外部中断执行程序是不能嵌套的。
//---------------------------------------------------------------------------------------------
bool
intr_context (void)
{
return in_external_intr;
}
看他是不是还在外部中断期间。
//----------------------------------------------------------------------------------------------
void
intr_handler (struct intr_frame *frame)
{
bool external;
intr_handler_func *handler;

/* External interrupts are special.
We only handle one at a time (so interrupts must be off)
and they need to be acknowledged on the PIC (see below).
An external interrupt handler cannot sleep. */
external = frame->vec_no >= 0x20 && frame->vec_no < 0x30; //看他是不是外部中断。因为外部中断只能一次执行一次。
if (external)
{
ASSERT (intr_get_level () == INTR_OFF);
ASSERT (!intr_context ());

in_external_intr = true; //外部中断刚开始需要说明正在外部中断
yield_on_return = false; //并且不能在返回时yield
}

/* Invoke the interrupt's handler. */
handler = intr_handlers[frame->vec_no]; //内部中断只需执行这个handler即可。
if (handler != NULL)
handler (frame);
else if (frame->vec_no == 0x27 || frame->vec_no == 0x2f)
{
/* There is no handler, but this interrupt can trigger
spuriously due to a hardware fault or hardware race
condition. Ignore it. */
}
else
unexpected_interrupt (frame); //没有注册handler

/* Complete the processing of an external interrupt. */
if (external)
{
ASSERT (intr_get_level () == INTR_OFF);
ASSERT (intr_context ());

in_external_intr = false; //退出外部中断
pic_end_of_interrupt (frame->vec_no); //设置pic

if (yield_on_return) //外部中断一定不会执行这句话
thread_yield ();
}
}
//-------------------------------------------------------------------
static void
unexpected_interrupt (const struct intr_frame *f)
{
/* Count the number so far. */
unsigned int n = ++unexpected_cnt[f->vec_no];

/* If the number is a power of 2, print a message. This rate
limiting means that we get information about an uncommon
unexpected interrupt the first time and fairly often after
that, but one that occurs many times will not overwhelm the
console. */
if ((n & (n - 1)) == 0)
printf ("Unexpected interrupt %#04x (%s)/n",
f->vec_no, intr_names[f->vec_no]);
}
这个函数只是把frame中对应的vec_no的unexpected_cnt数组加一。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: