kvm tick中断模拟

1:创建irq设备

KVM_CREATE_IRQCHIP

KVM_CREATE_PIT


2:

struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
{
	struct kvm_pit *pit;
	struct kvm_kpit_state *pit_state;
	struct pid *pid;
	pid_t pid_nr;
	int ret;

	pit = kzalloc(sizeof(struct kvm_pit), GFP_KERNEL);
	if (!pit)
		return NULL;

	pit->irq_source_id = kvm_request_irq_source_id(kvm);
	if (pit->irq_source_id < 0)
		goto fail_request;

	mutex_init(&pit->pit_state.lock);

	pid = get_pid(task_tgid(current));
	pid_nr = pid_vnr(pid);
	put_pid(pid);

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

	kthread_init_work(&pit->expired, pit_do_work);

	pit->kvm = kvm;

	pit_state = &pit->pit_state;
	hrtimer_init(&pit_state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
	pit_state->timer.function = pit_timer_fn;

	pit_state->irq_ack_notifier.gsi = 0;
	pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq;
	pit->mask_notifier.func = pit_mask_notifer;

	kvm_pit_reset(pit);

	kvm_pit_set_reinject(pit, true);

	mutex_lock(&kvm->slots_lock);
	kvm_iodevice_init(&pit->dev, &pit_dev_ops);
	ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, KVM_PIT_BASE_ADDRESS,
				      KVM_PIT_MEM_LENGTH, &pit->dev);
	if (ret < 0)
		goto fail_register_pit;

	if (flags & KVM_PIT_SPEAKER_DUMMY) {
		kvm_iodevice_init(&pit->speaker_dev, &speaker_dev_ops);
		ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS,
					      KVM_SPEAKER_BASE_ADDRESS, 4,
					      &pit->speaker_dev);
		if (ret < 0)
			goto fail_register_speaker;
	}
	mutex_unlock(&kvm->slots_lock);

	return pit;

fail_register_speaker:
	kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &pit->dev);
fail_register_pit:
	mutex_unlock(&kvm->slots_lock);
	kvm_pit_set_reinject(pit, false);
	kthread_destroy_worker(pit->worker);
fail_kthread:
	kvm_free_irq_source_id(kvm, pit->irq_source_id);
fail_request:
	kfree(pit);
	return NULL;

}

初始化hrtimerhrtimer中断处理函数为pit_timer_fn,hrtimer的启动在kvm_pit_reset里,每个1ms产生一次中断

3:进入hrtimer中断处理函数

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;
}

这里的worker在kvm_create_pit函数里设置好(kthread_init_work(&pit->expired,pit_do_work))

4

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);
}

kvm_apic_nmi_wd_deliver最终会调用到__apic_accept_irq,在该函数里,设置中断标志位,然后通过kvm_kick_vcpuvcpu拉回到host,等到vcpu重新进入guest时,将中断信息注入到vmcs结构体里,这样vcpu回到guest后就可以处理tick中断了。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值