当前位置: 首页 > news >正文

x86虚拟机中的时钟

【概述】

虚拟机中看到的关于时间的硬件都是假的,rtc/pit/hpet/tsc/lapic local timer都可以是假的,那么guest读clock当前时间就会导致exit出来,exit出来后kvm计算出一个值返回给guest。guest写timer的超时时间就会导致exit出来,exit出来后kvm给一个软件定时器设置超时时间,等这个软件定时器超后,kvm生成一个时间虚拟中断,把这个中断注入给虚拟机。

虚拟机里看clocksource和clockevent,clocksource用的是kvm-clock那就是因为kernel检测到自己运行在kvm上,并且kvm提供了kvmclock特性。

[root@syh2021v ~]# cat /sys/devices/system/clocksource/clocksource0/available_clocksource
kvm-clock tsc
hpet acpi_pm
[root@syh2021v ~]# cat /sys/devices/system/clocksource/clocksource0/current_clocksource
kvm-clock
[root@syh2021v ~]# cat /sys/devices/system/clockevents/broadcast/current_device

hpet
[root@syh2021v ~]# cat /sys/devices/system/clockevents/clockevent0/current_device
lapic-deadline

kvm虚拟机中的clocksource有:kvm-clock、tsc、hpet、acpi_pm、pit等

【clocksource management】

主要逻辑在kernel/time/clocksource.c

clocksource_register_hz

__clocksource_register_scale

clocksource_enqueue

/*

 * Enqueue the clocksource sorted by rating

 */

static void clocksource_enqueue(struct clocksource *cs)

{

    struct list_head *entry = &clocksource_list;

    struct clocksource *tmp;

    list_for_each_entry(tmp, &clocksource_list, list) {

        /* Keep track of the place, where to insert */

        if (tmp->rating < cs->rating)

            break;

        entry = &tmp->list;

    }

    list_add(&cs->list, entry);

}

可见,所有的clocksource是根据rating参数大小被组织到了一个list中。linux默认使用rating最高的clocksource,或者用户修改过clocksource,通过clocksource_select函数指定clocksource

在arch/x86/kernel/kvmclock.c中:

struct clocksource kvm_clock = {

    .name   = "kvm-clock",

    .read   = kvm_clock_get_cycles,

    .rating = 400,

    .mask   = CLOCKSOURCE_MASK(64),

    .flags  = CLOCK_SOURCE_IS_CONTINUOUS,

};

设置了,kvmclockrating400

同理,在arch/x86/kernel/tsc.c中,可以看到tsc的rating是300

arch/x86/kernel/hpet.c中,hpet的rating是250

drivers/clocksource/acpi_pm.c中,acpi_pm的rating是200

drivers/clocksource/i8253.c中,pit的rating是110

所以,linux内核中clocksource框架选择的顺序是:kvmclock>tsc>hpet>acpi_pm>pit 。

【kvmclock】

参见单独文章。

【TSC】

Guest中可以配置为TSC Passthrough,也可以配置为vmm截获。这在vmcb或vmcs中都有相应的配置,下图是vmcb中的配置位:

以配置为vmm截获为例,如果Guest中使用rdtsc指令,则会被Host拦截,Host中处理后返回给Guest:

em_rdtsc [arch/x86/kvm/emulate.c]

svm_get_msr/vmx_get_msr

kvm_get_msr_common

    case MSR_IA32_TSC:

        msr_info->data = kvm_scale_tsc(vcpu, rdtsc()) + vcpu->arch.tsc_offset;

        break;

这里会将host tsc值进行缩放(scaling)并添加上offset之后,返回guest。为什么要scaling和添加offset?猜测scaling是因为不同cpu平台的模拟(host和guest的cpu不同,当然tsc频率也就不同);而offset主要是解决热迁移问题。

【HPET】

Hpet在kvm+qemu平台是个用户态纯模拟出来的:qemusource_root_dir/hw/timer/hpet.c 。

/*作为clocksource,提供counter*/

hpet_init

memory_region_init_io //注册hpet_ram_ops

hpet_ram_ops提供read函数hpet_ram_read、和write函数hpet_ram_write供前端读写设置hpet counter。

/*作为clockevent,提供timer定时器中断*/

hpet_realize

hpet_timer

update_irq

qemu_irq_raise / qemu_irq_pulse

qemu模拟了hpet device,并在用户态周期性的inject irq,在Guest中就觉得是一个timer了。

【PIT】

实现代码在linux kvm源码arch/x86/kvm/i8254.c中。

kvm_create_pit

    pit->worker = kthread_create_worker(0, "kvm-pit/%d", pid_nr);

    kthread_init_work(&pit->expired, pit_do_work);

    hrtimer_init(&pit_state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);

    pit_state->timer.function = pit_timer_fn;

static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)

{

    struct kvm_kpit_state *ps = container_of(data, struct kvm_kpit_state, timer);

    struct kvm_pit *pt = pit_state_to_pit(ps);

    if (atomic_read(&ps->reinject))

        atomic_inc(&ps->pending);

    kthread_queue_work(pt->worker, &pt->expired);

    if (ps->is_periodic) {

        hrtimer_add_expires_ns(&ps->timer, ps->period);

        return HRTIMER_RESTART;

    } else

        return HRTIMER_NORESTART;

}

static void pit_do_work(struct kthread_work *work)

{

    struct kvm_pit *pit = container_of(work, struct kvm_pit, expired);

    struct kvm *kvm = pit->kvm;

    struct kvm_vcpu *vcpu;

    int i;

    struct kvm_kpit_state *ps = &pit->pit_state;

    if (atomic_read(&ps->reinject) && !atomic_xchg(&ps->irq_ack, 0))

        return;

    kvm_set_irq(kvm, pit->irq_source_id, 0, 1, false);

    kvm_set_irq(kvm, pit->irq_source_id, 0, 0, false);

    /*

     * Provides NMI watchdog support via Virtual Wire mode.

     * The route is: PIT -> LVT0 in NMI mode.

     *

     * Note: Our Virtual Wire implementation does not follow

     * the MP specification.  We propagate a PIT interrupt to all

     * VCPUs and only when LVT0 is in NMI mode.  The interrupt can

     * also be simultaneously delivered through PIC and IOAPIC.

     */

    if (atomic_read(&kvm->arch.vapics_in_nmi_mode) > 0)

        kvm_for_each_vcpu(i, vcpu, kvm)

            kvm_apic_nmi_wd_deliver(vcpu);

}

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

Host中调用hrtimer_init函数创建一个hr timer。hr timer会在interval后调用callback函数---pit_timer_fn。 pit_timer_fn就是把一个work加入到worker queue中,刚刚创建的kvm-pit kworker线程就可以执行了。kvm-pit真正执行的,就是pit_do_work函数。

当然,pit也是既可以作为timer,也可以作为clocksource。同hpet一样,它也提供了read、write函数来供前端读取配置及counter值信息。

【说明】

1、

需要说明的是,即使有这么多clocksource,一个虚拟机当然没必要全部都用,尤其是拥有靠前的几个高精度时钟源,pit、hpet都可以选择性配置,如下:

<clock offset='utc'>
<timer name='pit' tickpolicy='delay'/>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='hpet' present='no'/>
</clock>
-rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=delay -no-hpet

看这台虚拟机就模拟rtc和pit,没有hpet。

2、

细心的读者可以发现,前面在介绍pit的时候,linux内核出现了两个路径:

1>drivers/clocksource/i8253.c

2>arch/x86/kvm/i8254.c

第一个路径其实是guest在注册clocksource的时候使用的pit驱动文件;第二个路径则是host在模拟pit设备时,使用的驱动文件。一个作为前端,另一个作为后端。

另外,在x86中8254和8253基本可以理解为同一个东西-PIT(Pro

grammable Interval Timer),8254是8253的改良版,支持更精确的时钟频率,通常具有更高的稳定性和准确性。

http://www.dtcms.com/a/428023.html

相关文章:

  • Genome Med|RAG-HPO做表型注释:学习一下大语言模型怎么作为发文思路
  • 阳江网站建设推广迅雷2t免费空间活动
  • Python 之可变参数作为默认值的坑
  • 高数第一问:极限定义
  • Vue 3 —— L / 11-Vue3全家桶
  • 建设网站审批手续如何编辑 wordpress 主题
  • SLF4J 日志学习
  • 外贸网站推广中山网站手机模板源码下载
  • 网站后台管理模板免费下载网站建设 人性的弱点
  • nodejs动态创建sql server表
  • 做平面设计什么素材网站好使张家港网站建设优化
  • Java 进阶--函数式编程
  • 《道德经》第九章
  • 网站首页怎么做ps中国营销传播网
  • 镇江网友之家百度上如何做优化网站
  • 网站分辨率自适应代码模板网站定制网站
  • 建设网站的网站安全建设银行网站怎么修改手机号码吗
  • 网站后台可以做两个管理系统么wordpress wpenqueuestyle
  • 两种常见的ACM风格笔试题
  • 图神经网络分享系列-transe(Translating Embeddings for Modeling Multi-relational Data) (一)
  • ENVI系列教程(十九)——目标探测与识别
  • 校园超市网站开发整站优seo排名点击
  • 服务器放n个网站自己做鞋子网站
  • Spring核心 - 控制反转 IOC , 用来大量例子来解释
  • 关键词查询的分析网站有网打不开网页咋回事
  • 大型电子商务网站建设成本双流区的规划建设局网站
  • 从引流到生态:排队免单如何重构商家私域流量?
  • 云网站制作的流程图烟台网站制作厂家联系方式
  • 做视频网站要多大的主机中国建设人才信息网查
  • 网站建设发文章几点发比较合适网站开发 平均工资