0%

Linux内核实现

内核中断体系结构

分类:硬件中断 软件中断

硬件中断:由电脑主机的8259A类似的硬件发出的中断,ARM中断控制器发出的中断
软中断:异常 第一类:CPU自行保留的中断,系统调用异常

代码结构


中断的工作流程

  1. 做CPU工作模式的转换
  2. 进行寄存器的拷贝与压栈
  3. 设置中断异常向量表
  4. 保存正常运行的函数返回值
  5. 跳转到对应的中断服务函数上
  6. 进行模式的复原及寄存器的复原
  7. 跳转回正常工作的函数地址继续运行

Linux 中断工作流程

  1. 将所有寄存器值 (SS, EFLAG, ESP, CS, EIP) 和错误码入栈
  2. 将异常码入栈(中断号)
  3. 将当前的函数返回值入栈(便于复原)
  4. 进行对应的中断服务函数
  5. 出栈函数返回值
  6. 返回所有入栈的寄存器值

中断过程的代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
_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

有出错码时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
_double_fault:
push _do_double_fault ;// C 函数地址入栈。
error_code:
xchg [esp+4],eax ;// error code <-> %eax,eax 原来的值被保存在堆栈上。
xchg [esp],ebx ;// &function <-> %ebx,ebx 原来的值被保存在堆栈上。
push ecx
push edx
push edi
push esi
push ebp
push ds
push es
push fs
push eax ;// error code ;// 出错号入栈。
lea eax,[esp+44] ;// offset ;// 程序返回地址处堆栈指针位置值入栈。
push eax
mov eax,10h ;// 置内核数据段选择符。
mov ds,ax
mov es,ax
mov fs,ax
call ebx ;// 调用相应的C 函数,其参数已入栈。
add esp,8 ;// 堆栈指针重新指向栈中放置fs 内容的位置。
pop fs
pop es
pop ds
pop ebp
pop esi
pop edi
pop edx
pop ecx
pop ebx
pop eax
iretd

求大佬赏个饭