中断学习之触发原理

中断处理程序是如何获取中断向量号的

CPU控制单元在最后会跳到中断IDT+n的地方,也就是中断源对应的IDT表的位置

ENTRY(irq_entries_start)
	RING0_INT_FRAME
vector=0
.rept NR_IRQS
	ALIGN
 .if vector
	CFI_ADJUST_CFA_OFFSET -4
 .endif
1:	pushl $~(vector) //中断向量压栈
	CFI_ADJUST_CFA_OFFSET 4
	jmp common_interrupt
 .previous
	.long 1b
 .text
vector=vector+1 //展开后每个IDT加1,用于计算中断向量用于do_IRQ进一步处理
.endr
END(irq_entries_start)

压栈的寄存器对应结构体如下

对应
struct pt_regs {
	long ebx;
	long ecx;
	long edx;
	long esi;
	long edi;
	long ebp;
	long eax;
	int  xds;
	int  xes;
	int  xfs;
	/* int  xgs; */
	long orig_eax;  //恰好是压栈的中断向量号
	long eip;
	int  xcs;
	long eflags;
	long esp;
	int  xss;
};

用户态程序运行时出现中断,那么特权级发生变化,栈要切换,切换的流程如下

__switch_to
	=>load_esp0(tss, next);
		=>native_load_esp0(tss, thread);
			=>tss->x86_tss.esp0 = thread->esp0;

esp0的定义如下:

struct thread_struct {
/* cached TLS descriptors. */
	struct desc_struct tls_array[GDT_ENTRY_TLS_ENTRIES];
	unsigned long	esp0;
	unsigned long	sysenter_cs;
	unsigned long	eip;
	unsigned long	esp;
	unsigned long	fs;
	unsigned long	gs;
/* Hardware debugging registers */
	unsigned long	debugreg[8];  /* %%db0-7 debug registers */
/* fault info */
	unsigned long	cr2, trap_no, error_code;
/* floating point info */
	union i387_union	i387;
/* virtual 86 mode info */
	struct vm86_struct __user * vm86_info;
	unsigned long		screen_bitmap;
	unsigned long		v86flags, v86mask, saved_esp0;
	unsigned int		saved_fs, saved_gs;
/* IO permissions */
	unsigned long	*io_bitmap_ptr;
 	unsigned long	iopl;
/* max allowed port in the bitmap, in bytes: */
	unsigned long	io_bitmap_max;
};

esp0初始化位置

#define INIT_THREAD  {							\
	.esp0 = sizeof(init_stack) + (long)&init_stack,			\  //来源于thread_info的内核栈
	.vm86_info = NULL,						\
	.sysenter_cs = __KERNEL_CS,					\
	.io_bitmap_ptr = NULL,						\
	.fs = __KERNEL_PERCPU,						\
}

 

异常返回的定义
DO_VM86_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->eip)

#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
	siginfo_t info; \
	info.si_signo = signr; \
	info.si_errno = 0; \
	info.si_code = sicode; \
	info.si_addr = (void __user *)siaddr; \
	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
						== NOTIFY_STOP) \
		return; \
	do_trap(trapnr, signr, str, 1, regs, error_code, &info); \
        =>do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, long error_code, siginfo_t *info)
			tsk->thread.error_code = error_code;
			tsk->thread.trap_no = trapnr;
			if (info)//用户态发信号
				force_sig_info(signr, info, tsk);
			else
				force_sig(signr, tsk);
}
设置和调用
set_trap_gate(0,÷_error);

ENTRY(divide_error)
	RING0_INT_FRAME
	pushl $0			# no error code
	CFI_ADJUST_CFA_OFFSET 4
	pushl $do_divide_error
	CFI_ADJUST_CFA_OFFSET 4
	jmp error_code
	CFI_ENDPROC
END(divide_error)
void __init init_IRQ(void)
	x86_init.irqs.intr_init();//X86_init.c (arch\x86\kernel):		.intr_init		= native_init_IRQ,
		=>void __init native_init_IRQ(void)
			x86_init.irqs.pre_vector_init();//X86_init.c (arch\x86\kernel):		.pre_vector_init	= init_ISA_irqs,
				=>void __init init_ISA_irqs(void)
					init_bsp_APIC();
					legacy_pic->init(0);
					/*
					 * 16 old-style INTA-cycle interrupts:
					 */
					for (i = 0; i < legacy_pic->nr_legacy_irqs; i++) {
						struct irq_desc *desc = irq_to_desc(i);

						desc->status = IRQ_DISABLED;
						desc->action = NULL;
						desc->depth = 1;

						set_irq_chip_and_handler_name(i, &i8259A_chip,
										  handle_level_irq, "XT");
					}
			apic_intr_init();
void __init native_init_IRQ(void)
	for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
		/* IA32_SYSCALL_VECTOR could be used in trap_init already. */
		if (!test_bit(i, used_vectors))
			set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]);//将中断处理函数挂接到中断门上
	}
struct legacy_pic default_legacy_pic = {
	.nr_legacy_irqs = NR_IRQS_LEGACY,
	.chip  = &i8259A_chip,
	.mask_all  = mask_8259A,
	.restore_mask = unmask_8259A,
	.init = init_8259A,
	.irq_pending = i8259A_irq_pending,
	.make_irq = make_8259A_irq,
		=>static void make_8259A_irq(unsigned int irq)
			disable_irq_nosync(irq);
			io_apic_irqs &= ~(1<<irq);
			set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
							  "XT");
			enable_irq(irq);
};	

 

 

参考资料

i8259A中断控制器分析 二
http://blog.sina.com.cn/s/blog_70dd169101019wzw.html

内核随记(一)——理解中断
http://blog.sina.com.cn/s/blog_5d0e8d0d01019cds.html

8259A工作原理描述
https://blog.csdn.net/aaaaatiger/article/details/2357395

8259a pic 原理收集
https://blog.csdn.net/github_30220885/article/details/47139671

x86保护模式的几点思考——IRQ、中断号和中断向量
http://blog.51cto.com/snower/557678

理解Linux中断 (1)
https://blog.csdn.net/tommy_wxie/article/details/7425685

理解Linux中断 (2)
https://blog.csdn.net/tommy_wxie/article/details/7425692

x86 kernel 中断机制分析一——IDT             文章不错
https://blog.csdn.net/yin262/article/details/53928178

linux对TSS(任务状态描述符)的使用---Linux内核笔记
https://blog.csdn.net/shinesi/article/details/1933851

x86体系下linux中的任务切换与TSS
https://blog.csdn.net/dog250/article/details/6203529

linux下X86架构IDT解析
http://blog.chinaunix.net/uid-27717694-id-3942170.html

linux内核中断、异常、系统调用的分析以及实践

https://blog.csdn.net/icyfire0105/article/details/1898523

LINUX中断描述符初始化  经典文章
http://www.cnblogs.com/icanth/archive/2012/06/04/2535251.html

linux不可屏蔽中断异常处理函数定义
https://blog.csdn.net/wyfwx/article/details/6740478

linux中断源码分析 - 概述(一)           文章不错
https://www.cnblogs.com/tolimit/p/4390724.html

linux中断源码分析 - 概述(一)      好文
https://www.cnblogs.com/tolimit/p/4390724.html

linux源码entry_32.S中interrupt数组的分析
https://blog.csdn.net/jinhongzhou/article/details/6015551

细说Linux内核中断机制
https://blog.csdn.net/yiqiaoxihui/article/details/81133950

kernel 3.10内核源码分析--中断--中断和异常返回流程
http://zzjlzx.blog.chinaunix.net/uid-14528823-id-4761421.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值