CPU检测中断
CPU在执行每条程序之前会检测是否有中断到达,即中断控制器是否有发送中断信号过来
查找IDT
CPU根据中断向量到IDT中读取对应的中断描述符表项,根据段选择符合偏移确定中断服务程序的地址见附录2
interrupt数组
在分析一中,我们看到,填充IDT中断服务程序的是interrupt数组的内容,所以第2步跳转到interrupt数组对应的表项,表项的内容之前也已分析过
push vector num and jmp to common_interrupt
778 /*
779 * the CPU automatically disables interrupts when executing an IRQ vector,
780 * so IRQ-flags tracing has to follow that:
781 */
782 .p2align CONFIG_X86_L1_CACHE_SHIFT
783 common_interrupt:
784 ASM_CLAC
785 addl $-0x80,(%esp) /* Adjust vector into the [-256,-1] range */
786 SAVE_ALL
787 TRACE_IRQS_OFF
788 movl %esp,%eax
789 call do_IRQ
790 jmp ret_from_intr
791 ENDPROC(common_interrupt)
792 CFI_ENDPROC
addl $-0x80,(%esp)
根据第一篇分析,此时栈顶是(~vector + 0x80),这里减去0x80,所以值为vector num取反,范围在[-256, -1]。这么做是为了和系统调用区分,正值为系统调用号,负值为中断向量。
SAVE_ALL
保存现场,将所有寄存器的值压栈(cs eip ss esp由系统自动保存)
186 .macro SAVE_ALL
187 cld
188 PUSH_GS
189 pushl_cfi %fs
190 /*CFI_REL_OFFSET fs, 0;*/
191 pushl_cfi %es
192 /*CFI_REL_OFFSET es, 0;*/
193 pushl_cfi %ds
194 /*CFI_REL_OFFSET ds, 0;*/
195 pushl_cfi %eax
196 CFI_REL_OFFSET eax, 0
197 pushl_cfi %ebp
198 CFI_REL_OFFSET ebp, 0
199 pushl_cfi %edi
200 CFI_REL_OFFSET edi, 0
201 pushl_cfi %esi
202 CFI_REL_OFFSET esi, 0
203 pushl_cfi %edx
204 CFI_REL_OFFSET edx, 0
205 pushl_cfi %ecx
206 CFI_REL_OFFSET ecx, 0
207 pushl_cfi %ebx
208 CFI_REL_OFFSET ebx, 0
209 movl $(__USER_DS), %edx
210 movl %edx, %ds
211 movl %edx, %es
212 movl $(__KERNEL_PERCPU), %edx
213 movl %edx, %fs
214 SET_KERNEL_GS %edx
215 .endm
movl %esp,%eax
将esp的值赋值给eax,eax作为do_IRQ的第一个参数,esp的值是以上压栈的寄存器的内容,以pt_reg形式传过去。
call do_IRQ
175 /*
176 * do_IRQ handles all normal device IRQ's (the special
177 * SMP cross-CPU interrupts have their own specific
178 * handlers).
179 */
180 __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
181 {
182 struct pt_regs *old_regs = set_irq_regs(regs);
183
184 /* high bit used in ret_from_ code */
185 unsigned vector = ~regs->orig_ax; //获取向量号,这里有一个取反的操作,与之前的取反相对应得到正的向量号
186 unsigned irq;
187
188 irq_enter();
189 exit_idle();
190
191 irq = __this_cpu_read(vector_irq[vector]); //通过向量号得到中断号
192
193 if (!handle_irq(irq, regs)) {
194 ack_APIC_irq();
195
196 if (irq != VECTOR_RETRIGGERED) {
197 pr_emerg_ratelimited("%s: %d.%d No irq handler for vector (irq %d)\n",
198 __func__, smp_processor_id(),
199 vector, irq);
200 } else {
201 __this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);
202 }
203 }
204
205