本文主要分析qemu vm中触发 virtblk_done 函数的流程分析,下面列出此函数的函数调用栈信息。
0xffffffffa0167000 : virtblk_done+0x0/0x100 [virtio_blk]
0xffffffffa003e148 : vring_interrupt+0x38/0x90 [virtio_ring]
0xffffffff8111f83e : handle_irq_event_percpu+0x3e/0x1e0 [kernel]
0xffffffff8111fa1d : handle_irq_event+0x3d/0x60 [kernel]
0xffffffff811226b7 : handle_edge_irq+0x77/0x130 [kernel]
0xffffffff81017ee2 : handle_irq+0xe2/0x1a0 [kernel]
0xffffffff81650c3f : do_IRQ+0x4f/0xf0 [kernel]
本文主要是探索virtblk_done中断函数的以下几个关系
- CPU Vector 与 IRQ 之间的对应关系
- IRQ 与 struct irq_desc对象之间的关系
- struct irq_desc对象中irq_data成员的解析
1 CPU Vector 与 IRQ ID之间的对应关系
do_IRQ函数将调用handle_irq函数,中断handle_irq函数得到如下信息
Breakpoint 8, handle_irq (irq=32, regs=0xffffffff8194be28 <init_thread_union+15912>) at arch/x86/kernel/irq_64.c:84
我们可以看出virtblk_done函数的irq很可能就是32,此时regs就是do_IRQ函数传入的寄存器信息。我们把它打印出来。
(gdb) p *regs
$40 = {
r15 = 18446744071588593208,
r14 = 18446744071579552066,
r13 = 18446744071588593296,
r12 = 18446744071579778376,
bp = 18446744071588593360,
bx = 382049427668,
r11 = 0,
r10 = 0,
r9 = 0,
r8 = 238,
ax = 4295049345,
cx = 0,
dx = 18446612134457592096,
si = 134,
di = 134,
orig_ax = 18446744073709551533,
ip = 18446744071579779908,
cs = 16,
flags = 514,
sp = 18446744071588593360,
ss = 24
}
do_IRQ函数实现如下
unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
/* high bit used in ret_from_ code */
unsigned vector = ~regs->orig_ax;
unsigned irq;
irq_enter();
exit_idle();
irq = __this_cpu_read(vector_irq[vector]);
if (!handle_irq(irq, regs)) {
ack_APIC_irq();
if (irq != VECTOR_RETRIGGERED) {
pr_emerg_ratelimited("%s: %d.%d No irq handler for vector (irq %d)\n",
__func__, smp_processor_id(),
vector, irq);
} else {
__this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);
}
}
irq_exit();
set_irq_regs(old_regs);
return 1;
}
在do_IRQ函数计算得到了此IRQ对应的vector," unsigned vector = ~regs->orig_ax ",上面我们已经得到了所有的regs信息,下面我们就可以得到 【IRQ 32】对应的 CPU Vector值是 82。
(gdb) p ~regs->orig_ax
$41 = 82
在do_IRQ函数中也给出了计算 IRQ的方法,通过计算得到的 CPU Vector 值,在当前CPU的vector_irq全局变量数组中找到vector对应的成员即为期望的IRQ。计算方法是 irq = __this_cpu_read(vector_irq[vector ]);
至此我们找到了一个对应关系 Vector:82 <----> IRQ:32
2 IRQ ID 与 struct irq_desc 对象之间的对应关系
继续运行gdb,我们可以得到 handle_edge_irq 函数的调用栈信息
(gdb) bt
#0 handle_edge_irq (irq=898403584, desc=0xffff8800358c8d00) at kernel/irq/chip.c:495
#1 0x0000000000000019 in irq_stack_union ()
#2 0xffff88007c1a3de8 in ?? ()
#3 0xffff88007fd03f70 in ?? ()
#4 0xffffffff81017ee2 in generic_handle_irq_desc (desc=<optimized out>, irq=898403584) at include/linux/irqdesc.h:114
#5 handle_irq (irq=898403584, regs=0xffff8800358c8d84) at arch/x86/kernel/irq_64.c:93
Backtrace stopped: frame did not save the PC
handle_edge_irq函数的irq是个非法值,因为此irq值不做使用,所以它非法我们也就不再细究了,我们来看下第二个参数desc的信息,如下
(gdb) p *desc
$4 = {
irq_data = {
irq = 32,
hwirq = 0,
node = 4294967295,
state_use_accessors = 36864,
chip = 0xffffffff81972860 <msi_chip>,
domain = 0x0 <irq_stack_union>,
handler_data = 0x0 <irq_stack_union>,
chip_data = 0xffff880035bb66c0,
msi_desc = 0xffff880035b12b40,
affinity = 0xffff8800356a9c00
},
kstat_irqs = 0x20b30,
handle_irq = 0xffffffff81122640 <handle_simple_irq+64>,
action = 0xffff8800357eb680,
status_use_accessors = 16384,
core_internal_state__do_not_mess_with_it = 0,
depth = 0,
wake_depth = 0,
irq_count = 102,
last_unhandled = 0,
irqs_unhandled = 0,
lock = {
raw_lock = {
{
head_tail = 29491648,
tickets = {
head = 448,
tail = 450
}
}
}
},
percpu_enabled = 0x0 <irq_stack_union>,
affinity_hint = 0x0 <irq_stack_union>,
affinity_notify = 0x0 <irq_stack_union>,
pending_mask = 0xffff8800356aac00,
threads_oneshot = 0,
threads_active = {
counter = 0
},
wait_for_threads = {
lock = {
{
rlock = {
raw_lock = {
{
head_tail = 0,
tickets = {
head = 0,
tail = 0
}
}
}
}
}
},
task_list = {
next = 0xffff8800358c8dc0,
prev = 0xffff8800358c8dc0
}
},
dir = 0xffff8800357eb480,
parent_irq = 0,
owner = 0x0 <irq_stack_union>,
name = 0xffffffff818e60d1 "edge"
}
我们可以看到中断IRQ 32对应的 chip和struct irq_cfg对象分别是
desc->irq_data.chip 是 msi_chip
desc->irq_data.chip_data 就是 struct irq_cfg对象
IRQ 32对应的 desc->irq_data.chip 详细信息如下
(gdb) p *desc->irq_data.chip
$16 = {
name = 0xffffffff8185d68d "PCI-MSI",
irq_startup = 0x0 <irq_stack_union>,
irq_shutdown = 0x0 <irq_stack_union>,
irq_enable = 0x0 <irq_stack_union>,
irq_disable = 0x0 <irq_stack_union>,
irq_ack = 0xffffffff8150a840 <setup_hpet_msi_remapped+16>,
irq_mask = 0xffffffff81346600 <pci_enable_msix+832>,
irq_mask_ack = 0x0 <irq_stack_union>,
irq_unmask = 0xffffffff81346620 <pci_enable_msix+864>,
irq_eoi = 0xffffffff8150ac70 <compose_remapped_msi_msg+128>,
irq_set_affinity = 0xffffffff8150a7d0 <setup_ioapic_remapped_entry+16>,
irq_retrigger = 0xffffffff8104d070 <ioapic_retrigger_irq>,
irq_set_type = 0x0 <irq_stack_union>,
irq_set_wake = 0x0 <irq_stack_union>,
irq_bus_lock = 0x0 <irq_stack_union>,
irq_bus_sync_unlock = 0x0 <irq_stack_union>,
irq_cpu_online = 0x0 <irq_stack_union>,
irq_cpu_offline = 0x0 <irq_stack_union>,
irq_suspend = 0x0 <irq_stack_union>,
irq_resume = 0x0 <irq_stack_union>,
irq_pm_shutdown = 0x0 <irq_stack_union>,
irq_print_chip = 0xffffffff8150aca0 <ir_ack_apic_level+16>,
flags = 0
}
IRQ 32对应的 desc->irq_data.chip_data,也就是struct irq_cfg对象详细信息如下
(gdb) p *(struct irq_cfg *)desc->irq_data.chip_data
$17 = {
irq_2_pin = 0x0 <irq_stack_union>,
domain = 0xffff88003520b400,
old_domain = 0xffff88003520b000,
vector = 82 'R',
move_in_progress = 0 '\000',
remapped = 1 '\001',
{
irq_2_iommu = {
iommu = 0xffff88007d130600,
irte_index = 32,
sub_handle = 1,
irte_mask = 0 '\000'
},
irq_2_irte = {
devid = 1536,
index = 32019
}
}
}
IRQ 32对应的 desc->irq_data.chip_data->irq_2_iommu->iommu对象 详细信息如下
(gdb) p *(struct intel_iommu *)0xffff88007d130600
$19 = {
reg = 0xffffc90000302000,
reg_phys = 4275634176,
reg_size = 4096,
cap = 5067151449129478,
ecap = 15732494,
gcmd = 2264924160,
register_lock = {
raw_lock = {
{
head_tail = 1835036,
tickets = {
head = 28,
tail = 28
}
}
}
},
seq_id = 0,
agaw = 1,
msagaw = 1,
irq = 24,
segment = 0,
name = "dmar0\000\000\000\000\000\000\000",
domain_ids = 0xffff880077d2a000,
domains = 0xffff880077780000,
lock = {
{
rlock = {
raw_lock = {
{
head_tail = 3145776,
tickets = {
head = 48,
tail = 48
}
}
}
}
}
},
root_entry = 0xffff880077737000,
flush = {
flush_context = 0xffffffff81503520 <qi_global_iec+64>,
flush_iotlb = 0xffffffff815035a0 <qi_flush_context+96>
},
qi = 0xffff88007d132800,
iommu_state = 0x0 <irq_stack_union>,
ir_table = 0xffff88007d002390,
iommu_dev = 0xffff88007be14c00,
node = -1
}