gpt4 book ai didi

linux - 产生中断(调用irqfd)如何在KVM虚拟机上调用中断?

转载 作者:行者123 更新时间:2023-12-05 05:58:35 25 4
gpt4 key购买 nike

KVM irqfd ioctl为文件描述符启动 irqfd。它这样做:

       case KVM_IRQFD: {
struct kvm_irqfd data;

r = -EFAULT;
if (copy_from_user(&data, argp, sizeof(data)))
goto out;
r = kvm_irqfd(kvm, &data);
break;
}

其中 kvm_irqfdhere并调用 kvm_irqfd_assign启动唤醒队列:

       init_waitqueue_func_entry(&irqfd->wait, irqfd_wakeup);

irqfd_wakeup这样做:

       if (flags & EPOLLIN) {
u64 cnt;
eventfd_ctx_do_read(irqfd->eventfd, &cnt);

idx = srcu_read_lock(&kvm->irq_srcu);
do {
seq = read_seqcount_begin(&irqfd->irq_entry_sc);
irq = irqfd->irq_entry;
} while (read_seqcount_retry(&irqfd->irq_entry_sc, seq));
/* An event has been signaled, inject an interrupt */
if (kvm_arch_set_irq_inatomic(&irq, kvm,
KVM_USERSPACE_IRQ_SOURCE_ID, 1,
false) == -EWOULDBLOCK)
schedule_work(&irqfd->inject);
srcu_read_unlock(&kvm->irq_srcu, idx);
ret = 1;
}

正如您在 schedule_work(&irqfd->inject) 中所见,它调度了 inject 函数,即 here :

static void
irqfd_inject(struct work_struct *work)
{
struct kvm_kernel_irqfd *irqfd =
container_of(work, struct kvm_kernel_irqfd, inject);
struct kvm *kvm = irqfd->kvm;

if (!irqfd->resampler) {
kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1,
false);
kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0,
false);
} else
kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
irqfd->gsi, 1, false);
}

它调用kvm_set_irq定义here这是这样做的:

int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
bool line_status)
{
struct kvm_kernel_irq_routing_entry irq_set[KVM_NR_IRQCHIPS];
int ret = -1, i, idx;

trace_kvm_set_irq(irq, level, irq_source_id);

/* Not possible to detect if the guest uses the PIC or the
* IOAPIC. So set the bit in both. The guest will ignore
* writes to the unused one.
*/
idx = srcu_read_lock(&kvm->irq_srcu);
i = kvm_irq_map_gsi(kvm, irq_set, irq);
srcu_read_unlock(&kvm->irq_srcu, idx);

while (i--) {
int r;
r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level,
line_status);
if (r < 0)
continue;

ret = r + ((ret < 0) ? 0 : ret);
}

return ret;
}

看起来它终于在以下位置调用了一些东西:

        r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level,
line_status);

这个set函数由this填充.它设置为 this function :

static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id,
int level, bool line_status)
{
unsigned int spi_id = e->irqchip.pin + VGIC_NR_PRIVATE_IRQS;

if (!vgic_valid_spi(kvm, spi_id))
return -EINVAL;
return kvm_vgic_inject_irq(kvm, 0, spi_id, level, NULL);
}

调用kvm_vgic_inject_irq最后调用vgic_put_irq这叫this :

void __vgic_put_lpi_locked(struct kvm *kvm, struct vgic_irq *irq)
{
struct vgic_dist *dist = &kvm->arch.vgic;

if (!kref_put(&irq->refcount, vgic_irq_release))
return;

list_del(&irq->lpi_list);
dist->lpi_list_count--;

kfree(irq);
}

但是我没看到这里是怎么调用GIC的,只看到被删除的列表。

我认为这里它会将中断发送到 GIC,然后它会以某种方式调用 VM。我试图了解调用 irqfd 文件描述符如何最终调用 VM 中的中断。

最佳答案

VGIC 是针对 arm 的,你应该检查 arm 支持文件。 x86 使用 APIC 或 PIC。现在主要是APIC。您可以查看这些 IRQ 芯片如何将外部信号传输到目标核心 (vcpu) 的规范。

例如,如果您使用的是使用 IOAPIC 的 x86 虚拟机(我不知道 VGIC),例如(模拟)有 24 个引脚,并且您应该了解 APIC(硬件),那么您就知道它是如何工作的。

https://elixir.bootlin.com/linux/v5.2.12/source/arch/x86/kvm/irq_comm.c#L271

https://elixir.bootlin.com/linux/v5.2.12/source/arch/x86/kvm/irq_comm.c#L38

关于linux - 产生中断(调用irqfd)如何在KVM虚拟机上调用中断?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68456407/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com