apic timer
setup timer
boot cpu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
start_kernel
=> time_init();
=> choose early clocksource in [hpet, pm, pit] to
calibrate_tsc
## 以hpet计算tsc 为例
## 这里主要是因为hpet/pit/pm频率是确定的,但是tsc
## 频率不确定, 需要用其他的clocksource来计算下
=> cpu_khz = hpet_calibrate_tsc();
=> ((tsc_delta) * 1000000000L) / hpet_delta *
=> enable early timer
=> setup_irq(0, &irq0)
# ifndef CONFIG_SMP
=> time_init_gtod()
=> rest_init
=> kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
=> smp_prepare_cpus
=> setup_boot_APIC_clock ## want to use APIC clock
=> disable irq
=> calibration_result = calibrate_APIC_clock()
=> setup_APIC_timer(calibration_result);
=> enable irq
time_init_gtod
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/*
* Decide what mode gettimeofday should use.
*/
void time_init_gtod(void)
{
char *timetype;
if (unsynchronized_tsc())
notsc = 1;
if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
vgetcpu_mode = VGETCPU_RDTSCP;
else
vgetcpu_mode = VGETCPU_LSL;
//有hpet 没有tsc ,优先使用hpet
if (vxtime.hpet_address && notsc) {
//timetype -- [timer, clocksource]
timetype = hpet_use_timer ? "HPET" : "PIT/HPET";
//如果使用hpet timer
if (hpet_use_timer)
//HPET_T0_CMP 表示下一次要到期的cycle
//hpet_tick 表示 一次tick所占用的cycle
//两者相减代表上次到期的cycle
vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick;
else
vxtime.last = hpet_readl(HPET_COUNTER);
vxtime.mode = VXTIME_HPET;
do_gettimeoffset = do_gettimeoffset_hpet;
#ifdef CONFIG_X86_PM_TIMER
/* Using PM for gettimeofday is quite slow, but we have no other
choice because the TSC is too unreliable on some systems. */
} else if (pmtmr_ioport && !vxtime.hpet_address && notsc) {
timetype = "PM";
do_gettimeoffset = do_gettimeoffset_pm;
vxtime.mode = VXTIME_PMTMR;
sysctl_vsyscall = 0;
printk(KERN_INFO "Disabling vsyscall due to use of PM timer\n");
#endif
} else {
timetype = hpet_use_timer ? "HPET/TSC" : "PIT/TSC";
vxtime.mode = VXTIME_TSC;
}
printk(KERN_INFO "time.c: Using %ld.%06ld MHz WALL %s GTOD %s timer.\n",
vxtime_hz / 1000000, vxtime_hz % 1000000, timename, timetype);
printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
cpu_khz / 1000, cpu_khz % 1000);
vxtime.quot = (USEC_PER_SEC << US_SCALE) / vxtime_hz;
vxtime.tsc_quot = (USEC_PER_MSEC << US_SCALE) / cpu_khz;
vxtime.last_tsc = get_cycles_sync();
set_cyc2ns_scale(cpu_khz);
}
This post is licensed under CC BY 4.0 by the author.