上一篇讲到了虚拟cpu的构建过程,接下来就要利用vmm接管vcpu的中断,异常等行为。
一、vcpu退出状态记录
struct kvm_vcpu *vcpu_k;
kvm_run->exit_reason
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
/* in */
__u8 request_interrupt_window;
__u8 padding1[7];
/* out */
__u32 exit_reason;
.......
#define KVM_EXIT_UNKNOWN 0
#define KVM_EXIT_EXCEPTION 1
#define KVM_EXIT_IO 2
#define KVM_EXIT_HYPERCALL 3
#define KVM_EXIT_DEBUG 4
#define KVM_EXIT_HLT 5
#define KVM_EXIT_MMIO 6
#define KVM_EXIT_IRQ_WINDOW_OPEN 7
#define KVM_EXIT_SHUTDOWN 8
#define KVM_EXIT_FAIL_ENTRY 9
#define KVM_EXIT_INTR 10
#define KVM_EXIT_SET_TPR 11
#define KVM_EXIT_TPR_ACCESS 12
vcpu_init
kvm_vm_create_vcpu
vmx_create_vcpu
kvm_vcpu_init_vt
void vcpu_init(struct vm *vm, struct vcpu *vcpu)
{
int vcpu_mmap_size;
long r = 0;
if(vm->kvm)
r= kvm_vm_create_vcpu(vm->kvm, 0);
vcpu->vcpu_k = vm->kvm->vcpus[0];
vcpu->kvm_run = vcpu->vcpu_k->run;
kvm_run 记录了vcpu 运行的各种状态,并且在create_vcpu的时候进行了初始化,分配了page。
int run_vm(struct vm *vm, struct vcpu *vcpu, size_t sz)
{
struct kvm_vcpu *vcpu_k;
struct kvm_regs regs;
uint64_t memval = 0;
//long r =0;
vcpu_k = vcpu->vcpu_k;
for (;;) {
if (kvm_vcpu_ioctl_s(vcpu_k, (unsigned int)KVM_RUN, 0) < 0) {
printk("KVM_RUN error \n");
return -1;
}
printk("exit_reason %lx\n", vcpu->kvm_run);
switch (vcpu->kvm_run->exit_reason) {
case KVM_EXIT_HLT:
goto check;
case KVM_EXIT_IO:
// if (vcpu->kvm_run->io.direction == KVM_EXIT_IO_OUT
// && vcpu->kvm_run->io.port == 0xE9) {
// //char *p = (char *)vcpu->kvm_run;
// // fwrite(p + vcpu->kvm_run->io.data_offset,
// // vcpu->kvm_run->io.size, 1, stdout);
// // fflush(stdout);
// continue;
// }
/* fall through */
default:
//printk( "Got exit_reason %d,"
// " expected KVM_EXIT_HLT (%d)\n",
// vcpu->kvm_run->exit_reason, KVM_EXIT_HLT);
return 0;
}
}
check:
if (kvm_vcpu_ioctl_s(vcpu_k,(unsigned int)KVM_GET_REGS, (unsigned long)®s) < 0) {
printk("KVM_GET_REGS error \n");
return 0;
}
printk("excute success \n");
return 1;
}
由于虚拟机和VMM存在同一份代码,vcpu运行的的逻辑需要区别于VMM。我们需要标记vcpu的状态,处于vcpu将不运行VMM的vm_run逻辑,而跟模式将会进行中断检测处理。
二、kvm中的vm_exit逻辑
int kvm_emulate_halt(struct kvm_vcpu *vcpu)
{
++vcpu->stat.halt_exits;
if (irqchip_in_kernel(vcpu->kvm)) {
vcpu->arch.mp_state = VCPU_MP_STATE_HALTED;
kvm_vcpu_block(vcpu);
if (vcpu->arch.mp_state != VCPU_MP_STATE_RUNNABLE)
return -EINTR;
return 1;
} else {
vcpu->run->exit_reason = KVM_EXIT_HLT;
return 0;
}
}
static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
skip_emulated_instruction(vcpu);
return kvm_emulate_halt(vcpu);
}
handle_exception
kvm_emulate_halt(vcpu);
static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
svm->next_rip = svm->vmcb->save.rip + 1;
skip_emulated_instruction(&svm->vcpu);
return kvm_emulate_halt(&svm->vcpu);
}
__vcpu_run
kvm_x86_ops_vt->prepare_guest_switch(vcpu);
kvm_x86_ops_vt->run(vcpu, kvm_run);
但是,中断这里还没反应。
三、判断代码运行状态
首先我们的代码会运行在两种状态下,跟模式状态,非根模式状态。
static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigne

本文深入探讨了KVM虚拟机中VMM如何接管VCPU的中断和异常行为,详细介绍了VCPU退出状态记录的过程,以及如何通过设置VMCS配置来实现中断接管。


被折叠的 条评论
为什么被折叠?



