天天看點

初始化定時器中斷

5.10.4 初始化定時器中斷

回到start_kernel,612行time_init函數:

void __init time_init(void)

{

       late_time_init = x86_late_time_init;

}

函數x86_late_time_init實際上是初始化tsc時鐘源。在time_init中隻是把該函數的位址賦給全局變量late_time_init,以後某個時刻肯定會調用它的,這裡先提前詳細分析一下他:

static __init void x86_late_time_init(void)

{

       x86_init.timers.timer_init();

       tsc_init();

}

x86_init.timers.timer_init實際是函數hpet_time_init,來自檔案kernel/timer.c:

101 void __init hpet_time_init(void)

102 {

103        if (!hpet_enable())

104               setup_pit_timer();

105        setup_default_timer_irq();

106}

由于我們沒有配置CONFIG_HPET_TIMER,是以103行hpet_enable傳回0,調用104行的函數setup_pit_timer,位于arch/x86/kernel/i8253.c:

104void __init setup_pit_timer(void)

 105{

 106       

 110        pit_ce.cpumask = cpumask_of(smp_processor_id());

 111        pit_ce.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, pit_ce.shift);

 112        pit_ce.max_delta_ns = clockevent_delta2ns(0x7FFF, &pit_ce);

 113        pit_ce.min_delta_ns = clockevent_delta2ns(0xF, &pit_ce);

 114

 115        clockevents_register_device(&pit_ce);

 116        global_clock_event = &pit_ce;

 117}

整個函數的115行之前都是在通過彙編指令初始化全局變量pit_ce,這個clock_event_device類型的變量在編譯的時候已經被初始化成了:

static struct clock_event_device pit_ce = {

       .name             = "pit",

       .features  = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,

       .set_mode       = init_pit_timer,

       .set_next_event = pit_next_event,

       .shift              = 32,

       .irq         = 0,

};

我們看到它的irq号為0,也就是對應32号中斷描述符表項,即interrupt[0]處理函數。115行把它注冊到通知鍊和clockevent_devices連結清單中:

void clockevents_register_device(struct clock_event_device *dev)

{

       unsigned long flags;

……//一些調試代碼

       raw_spin_lock_irqsave(&clockevents_lock, flags);

       list_add(&dev->list, &clockevent_devices);

       clockevents_do_notify(CLOCK_EVT_NOTIFY_ADD, dev);

       clockevents_notify_released();

       raw_spin_unlock_irqrestore(&clockevents_lock, flags);

}

最後将全局global_clock_event設定成這個定時器,然後回到hpet_time_init中,105行,調用setup_default_timer_irq():

void __init setup_default_timer_irq(void)

{

       setup_irq(0, &irq0);

}

static struct irqaction irq0  = {

       .handler = timer_interrupt,

       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,

       .name = "timer"

};

很簡單,調用setup_irq把interrupt[0]對應的處理函數設定成timer_interrupt。至于随後如何處理的,請檢視部落格“定時器中斷”

http://blog.csdn.net/yunsongice/archive/2010/03/07/5354137.aspx