前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[virt][qemu]clocksource的管理和虚拟化

[virt][qemu]clocksource的管理和虚拟化

作者头像
皮振伟
发布2018-04-09 11:09:02
4.7K2
发布2018-04-09 11:09:02
举报
文章被收录于专栏:皮振伟的专栏

前言: kvm-clock,tsc,hpet,acpi_pm,pit,rtc。。。这些词看着都晕了@@ 虚拟化场景下,容作者在这里一一道来。 分析: 1,Linux clocksource

以Linux为例,查看操作系统的clocksource: 在/sys/devices/system/clocksource/clocksource0目录下; available_clocksource是当前所有可用的clocksource; current_clocksource是当前正在使用的clocksource。 所以,先不管这些名词是什么东西,怎么实现的,起码kvm-clock、tsc、hpet、acpi_pm是同一类的东西;并且,在Linux上,统一管理它们,并叫“clocksource”。它们提供了timer的能力,给操作系统使用。举例来说,kernel中的调度,就需要使用timer来支持。 因为windows不开源,也不知道它的源代码,最多就是根据外部的一些现象来猜测它的逻辑。具体的代码分析都基于Linux。 2,clocksource management 主要逻辑代码在linux-4.0.4/kernel/time/clocksource.c中实现:

clocksource实现了一个基本框架,提供了clocksource_register给具体的driver使用。 其中关键函数clocksource_enqueue:

可见,所有的clocksource是根据rating参数大小被组织到了一个list中。 linux默认使用rating最高的clocksource,或者用户修改过clocksource,通过clocksource_select函数生效。 在linux-4.0.4/arch/x86/kernel/kvmclock.c:

声明了kvm-clock的rating是400; 同理,在linux-4.0.4/arch/x86/kernel/tsc.c中,可以看到tsc的rating是300; linux-4.0.4/arch/x86/kernel/hpet.c中,hpet的rating是250; linux-4.0.4/drivers/clocksource/acpi_pm.c中,acpi_pm的rating是200; linux-4.0.4/drivers/clocksource/i8253.c中,pit的rating是110。 综上,Linux大致实现了clocksource的管理框架,各个timer实现自己的drvier,并注册到clocksource中。根据rating来看timer的性能:kvmclock>tsc>hpet>acpi_pm>pit。 3,kvmclock kvmclock比较特殊,是在kvm虚拟化的时候使用的,物理机上并没有---这也是和其他的timer很大的一个差别。 在linux-4.0.4/arch/x86/kernel/kvmclock.c中,kvmclock实现的关键函数:

计算出来pvit的物理地址(这个“物理地址”,其实是Guest Physical Address,即GPA),写MSR寄存器,通过msr_kvm_system_time(MSR_KVM_SYSTEM_TIME),告诉Host它的pvit地址。 在Host中: linux-4.0.4/arch/x86/kvm/x86.c文件中kvm_set_msr_common函数:

这里说一下,Guest中使用了wrmsr指令,Host会感知,然后进入到kvm_set_msr_common中处理。可见,通过kvm_gfn_to_hva_cache_init函数,会把传过来的地址参数data记录到pv_time中。这样子就可以通过pv_time来直接修改Guest中的pvit。 因为Host和Guest,使用的是相同的tsc,这里还需要说明一个问题: 参考linux-4.0.4/arch/x86/kvm/x86.c文件中kvm_guest_time_update函数: 关于Guest中的时间的计算,pv time中有两个重要参数:tsc_timestamp和system_time Guest Sytem Time = Guest Sytem Time + offset; 为什么要这么麻烦的计算? 因为热迁移。两台Host的TSC不一样,如果Dst Host的TSC比Src Host的TSC小,那么可能会让Windows蓝屏或者linux panic。 如果Dst Host的TSC比Src Host的TSC大,那么在Guest中看到tsc瞬间跳变。所以需要计算offset来调整。 另外,在Guest中,还需要做一次计算delta: 在linux-4.0.4/arch/x86/include/asm/pvclock.h文件中的__pvclock_read_cycles函数中: 计算Host中读取到Tsc和Guest中读取到的Tsc的差值,再计算出来delta,最后再计算出来Guest中的“kvmclock”。这里把Host和Guest中前后两次的Tsc微小差值都计算进去了,可见精度确实很高。 kvmclock是kvm虚拟化中rating最高的timer;当然,它的计算也真的很麻烦。 4,tsc 如果Guest中使用rdtsc指令,则会被Host拦截,Host中处理后返回给Guest: linux-4.0.4/arch/x86/kvm/emulate.c中:

继续调用,会到linux-4.0.4/arch/x86/kvm/vmx.c中:

先读取出来Host的Tsc,在加上offset。offset的原理也是为了防止热迁移tsc变小。 这里再说一下tsc的timer。因为tsc只是一个单调递增的寄存器,本身不能产生timer的irq。设置了tsc之后,apic会产生timer的irq。 5, hpet hpet是纯粹的qemu在用户态模拟出来的。 代码qemu-2.8.0-rc4/hw/timer/hpet.c

qemu的设备虚拟化逻辑。注意,是为hpet设备注册了callback函数hpet_timer: 前面是计算下次超时的时间,最后一行很关键,向Guest里inject irq了。 所以,hpet的逻辑就很清晰了:qemu模拟了hpet device,并在用户态周期性的inject irq,在Guest中就觉得是一个timer了。 6, pit 代码实现在:linux-4.0.4/arch/x86/kvm/i8254.c中:

关键代码分析,Host为Guest的pit创建了一个内核线程,名称就是“kvm-pit/PID”。所以,启动一个qemu虚拟机之后,ps找到qemu的pid,然后就能看到一个对应的内核线程。稍微说一下,这个线程稍微特殊一点,不是一个常规定义的routine函数,是基于kernel worker机制。

继续分析,当Guest中激活了PIT之后,Host中调用create_pit_timer函数创建一个hr timer。hr timer会在interval后调用callback函数---pit_timer_fn。 pit_timer_fn就是把一个work加入到worker queue中,刚刚创建的kvm-pit线程就可以执行了。kvm-pit真正执行的,就是pit_do_work函数。

好吧,又向Guest中inject irq了。 这里多说一句哈,在Guest Linux上,虽然创建了kvm-pit线程,但是却没有跑;在Guest windows上,kvm-pit线程周期性的执行work。

后记:

总结上述timer的逻辑,或使用不同的硬件,或使用软件,或在内核态,或在用户态,都是周期性地向Guest中inject irq。

KVM虚拟化CPU和管理内存,qemu虚拟化设备,加上上述的timer,还有就是apic,那么龙珠就集齐了,可以召唤神龙了~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-02-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AlwaysGeek 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
腾讯云代码分析
腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档