Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1359726
  • 博文数量: 488
  • 博客积分: 161
  • 博客等级: 入伍新兵
  • 技术积分: 5064
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-01 07:37
个人简介

只有偏执狂才能生存

文章分类

全部博文(488)

文章存档

2016年(10)

2015年(112)

2014年(66)

2013年(272)

2012年(28)

分类: LINUX

2013-08-22 15:43:31

在(1)中详细阐述了KVM是如何模拟内核PIT以及如何将timer中断注入到guest中去的。但是,那时对这一整套的机制理解还不够深,现在通过研究代码,理解又上升了一层,所以加深的总结一下。
核心想搞清楚的问题是如下几个:
1. 假如guest中设定PIT的频率为1000Hz,那么KVM如何为模拟PIT产生这个1000Hz的时钟源
2. 当时钟周期到时,会产生物理中断,KVM是如何将这个物理中断最终注入到guest中,使guest产生一个虚拟时钟中断的
第一个问题在(1)中讲的比较清楚,总的来讲就是,KVM的内核模拟PIT实际是用host Linux的hrtimer机制来产生时钟源。模拟PIT时钟源周期是1ms,那么KVM就创建一个hrtimer,过期时间是now+1ms。
第二个问题比较复杂。首先,当now+1ms到时,host hrtimer所利用的物理时钟设备,如物理PIT,会产生一个物理中断。这里就要分两种情况来讨论了:
1. 第一种情况是,物理中断产生的这一刻是guest在运行,这种情况下又有两种方式可以将虚拟时钟中断注入guest中:
1.1 直接注入进去
1.1.1 先要发生VM exit,在vmx_vcpu_run的最后调用complete_interrupt,会将vcpu.arch.interrupt_pending位置1,并从VMCS中取出中断信息保存到vcpu控制结构中去。
1.1.2 下一次迭代重新进入vcpu_guest_enter后,在vmx_vcpu_run之前会调用inject_pending_event。它会检测vcpu->arch.interrupt_pending位,发现是1,那么调用kvm_x86_ops->set_irq将中断真正注入VMCS中去,在VM entry时guest就能响应虚拟中断了。
1.2 通过模拟PIC或模拟APIC注入虚拟中断
1.2.1 先要发生VM exit,随后vmx_vcpu_run返回到vcpu_guest_enter中后将开中断,立刻进入host中断处理流程。
1.2.2 host ISR发现为模拟PIT创建的hrtimer到期,将在softirq中调用它的回调函数kvm_timer_fn。
1.2.3 kvm_timer_fn将设置ktimer.pending为1,其实就是vcpu.kvm->arch.pit->pit_state.pit_timer. pending这是模拟了PIT设备产生一次时钟信号的操作。
1.2.4 之后vcpu_guest_enter返回到__vcpu_enter中,将调用kvm_cpu_has_pending_timer,其实就是去检测那个pending位,将发现已经有了pending timer,那么会调用kvm_inject_pending_timer_irqs将这个时钟中断注入到模拟PIC或模拟APIC中去,这是模拟了一次PIT设备向PIC或APIC发送一个中断信号的操作
1.2.5 下一次迭代重新进入vcpu_guest_enter后,在vmx_vcpu_run之前会调用inject_pending_event。它中间会调用kvm_cpu_has_interrupt去检测模拟PIC或模拟APIC中是否有中断触发,发现有,将首先设置vcpu->arch.interrupt_pending位为1,再调用kvm_x86_ops->set_irq将中断真正注入VMCS中去,在VM entry时guest就能响应了,这是模拟了一次PIC或APIC向CPU发送一个中断信号的操作
上述两种情况会同时发生,只有在最后inject_pending_event中,如果前一种方式存在,那么后面这种方式就不用注入了,因为检测vcpu->arch.interrupt_pending在前,如果为1后面会直接返回了。
2. 第二种情况时,物理中断发生时guest并没有在运行。那么将直接进入host ISR,此时只能是通过上述第二种方式将虚拟时钟中断注入到guest中去。这应该就是为什么要设计两种注入方式的原因吧。

1. Interrupt occurs when guest code is running
1. vmx_vcpu_run--> complete_interrupt --> vcpu.arch.interrupt.pending = 1
2. vcpu_enter_guest (before vmx_vcpu_run) --> inject_pending_event --> kvm_x86_ops->set_irq (vmx_inject_irq) --> vmcs_write (VM_ENTRY_INTR_INFO_FIELD)

2. Timer ISR --> hrtimer_func (kvm_timer_fn) --> timer->pending --> __vcpu_run (after vcpu_enter_guest return) -->

阅读(552) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册