Linux内核分析:do_IRQ调用与中断处理

需积分: 10 0 下载量 154 浏览量 更新于2024-08-25 收藏 1.06MB PPT 举报
"Linux操作系统分析 - 科大课程资料" 在深入探讨Linux内核中的`do_IRQ`调用方式之前,我们先要理解一些操作系统和Linux的基本概念。`do_IRQ`是Linux内核中处理中断请求的核心函数,它在硬件中断发生时被调用,用于处理中断事件。这个函数是中断处理程序的关键部分,确保系统能够正确响应外部设备的中断请求。 首先,让我们回顾一下操作系统的基本概念。操作系统是管理计算机硬件和软件资源的软件,它提供了一个平台,使得用户和应用程序可以与硬件交互。在多任务环境中,操作系统通过调度算法管理多个进程的执行,保证系统的高效运行。 堆栈在操作系统中扮演着重要角色,特别是在中断处理中。当一个中断发生时,处理器会保存当前的上下文,包括寄存器状态,这就是`SAVE_ALL`汇编指令的作用,它将当前的处理器状态推入堆栈,以便稍后恢复。这样,中断服务例程可以在不干扰其他任务执行的情况下安全地运行。 在用户态和内核态之间,操作系统提供了不同的权限级别。用户态是普通应用程序运行的模式,而内核态则允许执行更高级别的操作,如直接访问硬件。当中断发生时,处理器会从用户态切换到内核态,因为中断处理通常需要这种更高的权限。`do_IRQ`函数就是在内核态下执行的。 虚拟内存是现代操作系统中的另一个关键特性,它允许每个进程都有自己独立的地址空间,即使这些进程可能同时访问相同的内存地址。通过页表映射,虚拟地址可以转换为物理地址,从而实现内存保护和资源共享。 在Linux中,`do_IRQ`的调用通常由硬件中断控制器触发,如8259A PIC( Programmable Interrupt Controller)或现代的APIC(Advanced Programmable Interrupt Controller)。中断控制器识别中断源,并向CPU发送中断信号。CPU响应这个信号,停止当前执行的指令,保存现场,然后跳转到预先定义的中断处理程序,即`do_IRQ`。 `do_IRQ`函数会根据中断号来确定具体的中断处理程序,然后调用相应的设备驱动程序去处理中断事件。中断处理完成后,`ret_from_intr`指令会被执行,它会恢复先前保存的处理器状态并返回到中断发生前的状态,继续执行被打断的指令。 在分析和实验验证环境中,开发者通常会使用虚拟机软件如VMware、QEMU或VirtualBox,以及代码编辑和分析工具如SourceInsight,来研究Linux内核的行为。此外,GNU工具集,包括gcc编译器、gdb调试器等,是Linux开发和分析不可或缺的一部分。 总结来说,`do_IRQ`的调用是Linux内核中断处理机制的核心,它涉及到操作系统的基础概念,如堆栈、用户态与内核态的切换、虚拟内存管理和中断处理。通过理解和分析`do_IRQ`的工作原理,我们可以更深入地了解Linux内核如何有效地响应硬件事件,确保系统的稳定性和性能。

static void nvme_calc_irq_sets(struct irq_affinity *affd, unsigned int nrirqs) { struct nvme_dev *dev = affd->priv; unsigned int nr_read_queues, nr_write_queues = dev->nr_write_queues; if (!nrirqs) { nrirqs = 1; nr_read_queues = 0; } else if (nrirqs == 1 || !nr_write_queues) { nr_read_queues = 0; } else if (nr_write_queues >= nrirqs) { nr_read_queues = 1; } else { nr_read_queues = nrirqs - nr_write_queues; } dev->io_queues[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues; affd->set_size[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues; dev->io_queues[HCTX_TYPE_READ] = nr_read_queues; affd->set_size[HCTX_TYPE_READ] = nr_read_queues; affd->nr_sets = nr_read_queues ? 2 : 1; }static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) { struct pci_dev *pdev = to_pci_dev(dev->dev); struct irq_affinity affd = { //ָ���ж��׺��Եļ��㷽���Ͳ��� .pre_vectors = 1, .calc_sets = nvme_set_irq_affinity, //nvme_calc_irq_sets, .priv = dev, }; unsigned int irq_queues, poll_queues; poll_queues = min(dev->nr_poll_queues, nr_io_queues - 1); dev->io_queues[HCTX_TYPE_POLL] = poll_queues; dev->io_queues[HCTX_TYPE_DEFAULT] = 1; dev->io_queues[HCTX_TYPE_READ] = 0; irq_queues = 1; if (!(dev->ctrl.quirks & NVME_QUIRK_SINGLE_VECTOR)) irq_queues += (nr_io_queues - poll_queues); return pci_alloc_irq_vectors_affinity(pdev, 1, irq_queues, PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd); } 在 Linux 5.17.12 内核版本中,如何修改 pci_alloc_irq_vectors_affinity() 函数的 affinity_hint 参数来绑定 NVMe 驱动的所有 I/O 队列到同一 CPU 核心上。代码展示

2023-06-09 上传

static void nvme_calc_irq_sets(struct irq_affinity *affd, unsigned int nrirqs) { struct nvme_dev *dev = affd->priv; unsigned int nr_read_queues, nr_write_queues = dev->nr_write_queues; if (!nrirqs) { nrirqs = 1; nr_read_queues = 0; } else if (nrirqs == 1 || !nr_write_queues) { nr_read_queues = 0; } else if (nr_write_queues >= nrirqs) { nr_read_queues = 1; } else { nr_read_queues = nrirqs - nr_write_queues; } dev->io_queues[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues; affd->set_size[HCTX_TYPE_DEFAULT] = nrirqs - nr_read_queues; dev->io_queues[HCTX_TYPE_READ] = nr_read_queues; affd->set_size[HCTX_TYPE_READ] = nr_read_queues; affd->nr_sets = nr_read_queues ? 2 : 1; }static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) { struct pci_dev *pdev = to_pci_dev(dev->dev); struct irq_affinity affd = { //ָ���ж��׺��Եļ��㷽���Ͳ��� .pre_vectors = 1, .calc_sets = nvme_set_irq_affinity, //nvme_calc_irq_sets, .priv = dev, }; unsigned int irq_queues, poll_queues; poll_queues = min(dev->nr_poll_queues, nr_io_queues - 1); dev->io_queues[HCTX_TYPE_POLL] = poll_queues; dev->io_queues[HCTX_TYPE_DEFAULT] = 1; dev->io_queues[HCTX_TYPE_READ] = 0; irq_queues = 1; if (!(dev->ctrl.quirks & NVME_QUIRK_SINGLE_VECTOR)) irq_queues += (nr_io_queues - poll_queues); return pci_alloc_irq_vectors_affinity(pdev, 1, irq_queues, PCI_IRQ_ALL_TYPES | PCI_IRQ_AFFINITY, &affd); } 在 Linux 5.17.12 内核版本中,可以通过修改 pci_alloc_irq_vectors_affinity() 函数的 affinity_hint 参数来绑定 NVMe 驱动的所有 I/O 队列到同一 CPU 核心上。

2023-06-09 上传