init_platform_timer
xen\arch\x86\setup.c void __init __start_xen(unsigned long mbi_p) { init_xen_time(); |
xen\arch\x86\time.c int __init init_xen_time(void) { init_platform_timer(); |
xen\arch\x86\time.c static void __init init_platform_timer(void) { init_timer(&plt_overflow_timer,plt_overflow, NULL, 0); |
xen\arch\x86\time.c static void plt_overflow(void *unused) { count = plt_src.read_counter(); plt_stamp64 += (count - plt_stamp) & plt_mask; plt_stamp = count; |
xen\arch\x86\time.c
read_platform_stime
platform_time_calibration
resume_platform_timer
rtc的时间获得
tools\ioemu-qemu-xen\hw\ mc146818rtc.c RTCState *rtc_init(int base, qemu_irq irq, int base_year) { s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100; qemu_mod_timer(s->second_timer2, s->next_second_time); |
tools\ioemu-qemu-xen\qemu-tool.c ?
int64_t qemu_get_clock(QEMUClock *clock)
{
qemu_timeval tv;
qemu_gettimeofday(&tv);
return (tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000)) / 1000000;
}
tools\ioemu-qemu-xen\vl.c int64_t qemu_get_clock(QEMUClock *clock) { switch(clock->type) { case QEMU_TIMER_REALTIME: return get_clock() / 1000000; default: case QEMU_TIMER_VIRTUAL: if (use_icount) { return cpu_get_icount(); } else { return cpu_get_clock(); } } } |
tools\ioemu-qemu-xen\vl.c static void init_timers(void) { init_get_clock(); ticks_per_sec = QEMU_TIMER_BASE; rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME); vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL); } |
tools\ioemu-qemu-xen\vl.c中main函数
use_icount?
tools\ioemu-qemu-xen\vl.c /* return the host CPU monotonic timer and handle stop/restart */ static int64_t cpu_get_clock(void) { int64_t ti; if (!cpu_ticks_enabled) { return cpu_clock_offset; } else { ti = get_clock(); return ti + cpu_clock_offset; } } |
tools\ioemu-qemu-xen\vl.c static int64_t get_clock(void) { LARGE_INTEGER ti; QueryPerformanceCounter(&ti); return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq); } |
结论:qemu通过dom0获取rtc时间。
tools\ioemu-qemu-xen\hw\ mc146818rtc.c static void rtc_copy_date(RTCState *s) { const struct tm *tm = &s->current_tm; int year;
s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec); s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min); |
tools\ioemu-qemu-xen\hw\ mc146818rtc.c void rtc_set_date(RTCState *s, const struct tm *tm) { s->current_tm = *tm; rtc_copy_date(s); } |
rtc_init ->rtc_set_date_from_host –> rtc_set_date
tools\ioemu-qemu-xen\hw\ mc146818rtc.c static void rtc_set_date_from_host(RTCState *s) { struct tm tm; int val;
/* set the CMOS date */ qemu_get_timedate(&tm, 0); rtc_set_date(s, &tm); |
走下面哪条路径?
tools\ioemu-qemu-xen\vl.c /***********************************************************/ /* host time/date access */ void qemu_get_timedate(struct tm *tm, int offset) { time_t ti; struct tm *ret;
time(&ti); ti += offset; if (rtc_date_offset == -1) { if (rtc_utc) ret = gmtime(&ti); //参数类型?? else ret = localtime(&ti); } else { ti -= rtc_date_offset; ret = gmtime(&ti); }
memcpy(tm, ret, sizeof(struct tm)); } |
xen\common\time.c中gmtime作用就是将时间格式化到一个结构体中,并将其返回。
read_platform_stime
xen\arch\x86\time.c void cstate_restore_tsc(void) { stime_delta = read_platform_stime() - t->stime_master_stamp; |
TSC 是时间戳计数器的缩写
static void time_calibration_tsc_rendezvous(void *_r) { for ( i = 4; i >= 0; i-- ) { if ( smp_processor_id() == 0 ) { while ( atomic_read(&r->semaphore) != (total_cpus - 1) ) mb();
if ( r->master_stime == 0 ) { r->master_stime =read_platform_stime(); |
/* Ordinary rendezvous function which does not modify TSC values. */ static void time_calibration_std_rendezvous(void *_r) { if ( smp_processor_id() == 0 ) { while ( atomic_read(&r->semaphore) != (total_cpus - 1) ) cpu_relax(); r->master_stime = read_platform_stime(); |
void init_percpu_time(void) { struct cpu_time *t = &this_cpu(cpu_time); unsigned long flags; s_time_t now;
local_irq_save(flags); rdtscll(t->local_tsc_stamp); now = read_platform_stime(); |
/* Late init function (after all CPUs are booted). */ int __init init_xen_time(void) { /* If TSCs are not marked as 'reliable', re-sync during rendezvous. */ if ( !boot_cpu_has(X86_FEATURE_TSC_RELIABLE) ) time_calibration_rendezvous_fn =time_calibration_tsc_rendezvous; |
static void time_calibration(void *unused) { struct calibration_rendezvous r = { .cpu_calibration_map = cpu_online_map, .semaphore = ATOMIC_INIT(0) };
/* @wait=1 because we must wait for all cpus before freeing @r. */ on_selected_cpus(&r.cpu_calibration_map, time_calibration_rendezvous_fn, &r, 1); } |
xen\arch\x86\time.c static void (*time_calibration_rendezvous_fn)(void *) = time_calibration_std_rendezvous; |
platform_time_calibration
cpu_frequency_change-> platform_time_calibration
local_time_calibration-> platform_time_calibration
time_suspend-> platform_time_calibration
int __init init_xen_time(void) { open_softirq(TIME_CALIBRATE_SOFTIRQ,local_time_calibration); |
resume_platform_timer
int time_resume(void) { /*u64 tmp = */init_pit_and_calibrate_tsc();
/* Disable this while calibrate_tsc_ap() also is skipped. */ /*set_time_scale(&this_cpu(cpu_time).tsc_scale, tmp);*/
resume_platform_timer(); |
device_power_up-> time_resume
结论
xen通过init_platform_timer来初始化时间源供Dom0使用。
DomU则通过rtc_init来从Dom0获取时间。
因此,时间虚拟化的路径应该如下:
xen->Dom0->DomU
2013年5月23日上传