中断

目的:

1.硬件的中断响应---->内核驱动中的中断

2.系统调用的函数响应(sys_call)--->系统调用

3.自定义中断---->软件的软中断模式

4.信号中断---->对了解信号的使用  创建

5.系统的异常和错误---->系统的异常获取   了解系统异常的作用

 

1.Linux的中断机制

      1.1 分类:硬件中断    软件中断

                       硬中断:由电脑主机的B259A类似的硬件中断控制芯片发出的中断

                        软中断: 异常     第一类:CPU自行保留的中断    系统调用异常

 

        1.2代码结构:

                                                   中断前的处理过程,中断的恢复过程                              中断的执行过程

硬件中断的处理过程                                    asm.s                                                                        trap.c

软件及系统调用的处理过程                        system_call.s                                              fork.c   signal.c   exit.c   sys.c

 

2.中断的工作流程:

(1-3)中断前的处理过程   4中断的执行过程      5-6中断的恢复过程

         1.将所有的寄存器值入栈

         2.将异常码入栈(中断号)

         3.将当前的函数返回值进行入栈(为了在中断执行后能找到在哪中断的,能够复原)

 

         4.调用对应的中断服务函数

 

         5.出栈函数返回值

         6.返回所有入栈的寄存器值

_divide_error:
	push dword ptr _do_divide_error ;// 首先把将要调用的函数地址入栈。这段程序的出错号为0。
no_error_code: ;// 这里是无出错号处理的入口处,见下面第55 行等。
	xchg [esp],eax ;// _do_divide_error 的地址 -> eax,eax 被交换入栈。
	push ebx
	push ecx
	push edx
	push edi
	push esi
	push ebp
	push ds ;// !!16 位的段寄存器入栈后也要占用4 个字节。
	push es
	push fs
	push 0 ;// "error code" ;// 将出错码入栈。
	lea edx,[esp+44] ;// 取原调用返回地址处堆栈指针位置,并压入堆栈。
	push edx
	mov edx,10h ;// 内核代码数据段选择符。
	mov ds,dx
	mov es,dx
	mov fs,dx
	call eax ;// 调用C 函数do_divide_error()。
	add esp,8 ;// 让堆栈指针重新指向寄存器fs 入栈处。
	pop fs
	pop es
	pop ds
	pop ebp
	pop esi
	pop edi
	pop edx
	pop ecx
	pop ebx
	pop eax ;// 弹出原来eax 中的内容。
	iretd

这就是asm.s里面的一串代码,也就是中断的处理过程,可以看到第三行是no_error_code,是无错误码的,在asm.s下面的代码还有一串error_code是有错误码的,而代码也正如上面说的,而这里因为没有错误码,压入的错误码是0,然后会调用中断服务函数,也就是它call eax;而在第四行代码可以看到,它其实是将eax和esp里的内容做了一个交换,所以它其实是调用了最开始压入的函数地址,也就是_do_divide_error函数。

这个是一种出错中断的函数。如果是其他的

;// int1 -- debug 调试中断入口点。处理过程同上。
_debug:
	push _do_int3 ;// _do_debug C 函数指针入栈。以下同。
	jmp no_error_code

;// int2 -- 非屏蔽中断调用入口点。
_nmi:
	push _do_nmi
	jmp no_error_code

;// int3 -- 同_debug。
_int3:
	push _do_int3
	jmp no_error_code

;// int4 -- 溢出出错处理中断入口点。
_overflow:
	push _do_overflow
	jmp no_error_code

;// int5 -- 边界检查出错中断入口点。
_bounds:
	push _do_bounds
	jmp no_error_code

;// int6 -- 无效操作指令出错中断入口点。
_invalid_op:
	push _do_invalid_op
	jmp no_error_code

;// int9 -- 协处理器段超出出错中断入口点。
_coprocessor_segment_overrun:
	push _do_coprocessor_segment_overrun
	jmp no_error_code

;// int15 – 保留。
_reserved:
	push _do_reserved
	jmp no_error_code

可以看到还有其他的函数调用,比如debug时,会压入_do_int3函数地址。可以看到,然后就会jmp到no_error_code,也就是走上面的代码了。

这些硬中断函数都在traps.c里。

这个是中断程序初始化子程序。设置它们的中断调用门(中断向量)。

set_trap_gate()与set_system_gate()的主要区别在于前者设置的特权级为0,后者是3。

void trap_init(void)
{
	int i;

	set_trap_gate(0,&divide_error);// 设置除操作出错的中断向量值。以下雷同。
	set_trap_gate(1,&debug);
	set_trap_gate(2,&nmi);
	set_system_gate(3,&int3);	/* int3-5 can be called from all */
	set_system_gate(4,&overflow);
	set_system_gate(5,&bounds);
	set_trap_gate(6,&invalid_op);
	set_trap_gate(7,&device_not_available);
	set_trap_gate(8,&double_fault);
	set_trap_gate(9,&coprocessor_segment_overrun);
	set_trap_gate(10,&invalid_TSS);
	set_trap_gate(11,&segment_not_present);
	set_trap_gate(12,&stack_segment);
	set_trap_gate(13,&general_protection);
	set_trap_gate(14,&page_fault);
	set_trap_gate(15,&reserved);
	set_trap_gate(16,&coprocessor_error);
// 下面将int17-48 的陷阱门先均设置为reserved,以后每个硬件初始化时会重新设置自己的陷阱门。
	for (i=17;i<48;i++)
		set_trap_gate(i,&reserved);
	set_trap_gate(45,&irq13);// 设置协处理器的陷阱门。
	outb_p(inb_p(0x21)&0xfb,0x21);// 允许主8259A 芯片的IRQ2 中断请求。
	outb(inb_p(0xA1)&0xdf,0xA1);// 允许从8259A 芯片的IRQ13 中断请求。
	set_trap_gate(39,&parallel_interrupt);// 设置并行口的陷阱门。
}

 

 

void do_divide_error(long esp, long error_code)
{
	die("divide error",esp,error_code);
}
static void die(char * str,long esp_ptr,long nr)
{
	long * esp = (long *) esp_ptr;
	int i;

	printk("%s: %04x\n\r",str,nr&0xffff);
	printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n",
		esp[1],esp[0],esp[2],esp[4],esp[3]);
	printk("fs: %04x\n",_fs());
	printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17));
	if (esp[4] == 0x17) {
		printk("Stack: ");
		for (i=0;i<4;i++)
			printk("%p ",get_seg_long(0x17,i+(long *)esp[3]));
		printk("\n");
	}
	str(i);
	printk("Pid: %d, process nr: %d\n\r",current->pid,0xffff & i);
	for(i=0;i<10;i++)
		printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0])));
	printk("\n\r");
	do_exit(11);		/* play segment exception */
}

可以看到,其实这个硬中断的函数,就是打印了压入栈中的几个值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MicroBlaze是一种可定制的32位R处理器,常用于嵌入式系统中。它支持中断机制,可以在处理器执行期间暂停当前任务,转而处理其他紧急任务或外部事件。下面是关于MicroBlaze中断的一些介绍: 1. 中断概念:中断是一种机制,用于在处理器执行期间暂停当前任务,转而处理其他紧急任务或外部事件。当发生中断时,处理器会保存当前的上下文信息,并跳转到中断处理程序来处理中断事件。 2. 中断控制器:MicroBlaze使用中断控制器来管理和处理中断中断控制器负责接收和分发中断信号,并将其传递给相应的中断处理程序。 3. 中断优先级:MicroBlaze支持多个中断源,并为每个中断源分配不同的优先级。较高优先级的中断会打断正在执行的较低优先级中断或任务。 4. 中断处理程序:每个中断源都有一个对应的中断处理程序。当中断发生时,处理器会跳转到相应的中断处理程序来执行特定的操作。中断处理程序通常用于保存当前上下文、处理中断事件、清除中断标志等。 5. 中断向量表:MicroBlaze使用中断向量表来存储每个中断源对应的中断处理程序的地址。当中断发生时,处理器会根据中断号查找中断向量表,并跳转到相应的中断处理程序。 6. 中断使能和屏蔽:MicroBlaze提供了使能和屏蔽中断的机制。通过设置相应的中断使能位和中断屏蔽位,可以控制哪些中断可以触发和哪些中断可以被屏蔽。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值