linux内核——2_内核中断体系结构

作者:GWD 时间:2019.7.28

一、课程目的:
1.硬件的中断响应---->内核驱动中的中断
2.系统调用的函数响应(sys_call)—>系统调用
3.自定义中断----->软件的软中断模式
4.信号中断(kill -signalnum)---->对了解信号的使用 创建 等
5.系统的异常和错误-----》系统的异常获取 了解系统异常的作用
二、linux的中断机制
1.1 分类:硬件中断和软件中断
硬中断:由电脑主机的8259A类似的硬件中断控制芯片发出的中断,ARM中断控制器发出的中断;
软中断:异常,CPU自行保留的中断和系统调用异常; 1.2 代码结构:
1.2 代码结构:
在这里插入图片描述
内核中asm.s ,trap.;system_call.s fork.c signal.c exit.c sys.c这些文件与中断有关
三、中断的工作流程:
1、 回忆:
1)、做CPU工作模式的转化
2)、进行寄存器的拷贝与压栈
3)、设置中断异常向量表
4)、保存正常运行的函数返回值
5)、跳转到对应的中断服务函数上运行
6)、进行模式的复原以及寄存器的复原
7)、跳转回正常工作的函数地址继续运行
2、Linux中中断的工作流程:
1)、将所有的寄存器值入栈
(8086中) SS EFLAGS ESP CS EIP (错误码) ARM中的(r0-r15)
2)、将异常码入栈(中断号)
3)、将当前的函数返回值进行入栈(为了在中断执行后能够找到在哪中断的,能够复原)
4)、调用对应的中断服务函数
5)、出栈函数返回值
6)、返回所有入栈的寄存器值
3、
在这里插入图片描述
在这里插入图片描述
四、中断的代码实现过程
在这里插入图片描述
1、打开asm.s分析
在这里插入图片描述
do_divide_error是一个C函数,在trap.c中
在这里插入图片描述
注意:分析汇编代码的时候,看是看不懂的,要边画边看!!!
2、xchg是交换指令,将eax于esp的地址进行交换,也就是将C函数的地址放入中断处理函数中;
在这里插入图片描述
在这里插入图片描述
注意在8086中是EAX………EDX,实际相当于ARM中的R0……R11
3、无错误码的时候(起始代码、终止代码)

;/* passed
;* linux/kernel/asm.s
;*
;* (C) 1991 Linus Torvalds
;*/
.386p
.model flat
.code
_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 入栈处,就是回到了call eax前的地址。
	pop fs
	pop es
	pop ds
	pop ebp
	pop esi
	pop edi
	pop edx
	pop ecx
	pop ebx
	pop eax ;// 弹出原来eax 中的内容。

在这里插入图片描述
4、有错误码的时候

_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


跳转到相应的C函数,执行完后再跳转回没有错误码的情况。

五、static void die(char * str,long esp_ptr,long nr)
1、die函数的三个参数
1)、字符串
2)、栈指针
3)、哪里出错的短号
功能是用来打印错误号,然后打印栈里的信息和错误号,就相当于一个printf

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 */
}

在这里插入图片描述
六、void trap_init(void)
1、整个的中断初始化函数;
2、 set_trap_gate 设置的权限较低,只能由用户程序调用
set_system_gate 设置的权限较高,能有用户和系统所有的进程调用
3、idt中断描述表
在这里插入图片描述
4、

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);// 设置并行口的陷阱门。
}

七、system_call.s
1、系统调用表在sys_call_table中,所有的系统调用C函数放到了一个统一的sys_call_table
中,比如open、write等等
在这里插入图片描述
注:看具体代码时候不用看所有的汇编,只要知道一个汇编在干什么就行,着重看调用的C语言函数。

// 系统调用函数指针表。用于系统调用中断处理程序(int 0x80),作为跳转表。
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
  sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
  sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
  sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
  sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
  sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
  sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
  sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
  sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
  sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
  sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
  sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
  sys_setreuid, sys_setregid
};

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值