Chinaunix首页 | 论坛 | 博客
  • 博客访问: 35354
  • 博文数量: 9
  • 博客积分: 128
  • 博客等级: 入伍新兵
  • 技术积分: 142
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-21 11:28
文章分类
文章存档

2015年(3)

2012年(6)

我的朋友

分类: LINUX

2015-04-04 22:51:09

聂新桥 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程

在内核源码的start_kernel函数里,调用的初始化中断的trap_init()
trap_init()会设定硬件中断相应的处理代码和系统调用处理代码
(, &);
SYSCALL_VECTOR = 0x80  system_call是汇编起点地址。
在arch/x86/kernel/entry_32.S里可以找到符号system_call

ENTRY(system_call)
    RING0_INT_FRAME            # can't unwind into user space anyway
    ASM_CLAC
    pushl_cfi %eax            # save orig_eax
    SAVE_ALL
    GET_THREAD_INFO(%ebp)
                    # system call tracing in operation / emulation
    testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
    jnz syscall_trace_entry


要知道系统调用与中断都被cpu当成异常,硬件会自动保存用户态的ss,esp, eflags 和cs eip在内核态的堆栈上。
然后的SAVE_ALL宏会保存其他的寄存器。最后的几句汇编修改了段寄存器fs,gs,es不知道是怎么意思。
.macro SAVE_ALL
    cld
    PUSH_GS
    pushl_cfi %fs
    /*CFI_REL_OFFSET fs, 0;*/
    pushl_cfi %es
    /*CFI_REL_OFFSET es, 0;*/
    pushl_cfi %ds
    /*CFI_REL_OFFSET ds, 0;*/
    pushl_cfi %eax
    CFI_REL_OFFSET eax, 0
    pushl_cfi %ebp
    CFI_REL_OFFSET ebp, 0
    pushl_cfi %edi
    CFI_REL_OFFSET edi, 0
    pushl_cfi %esi
    CFI_REL_OFFSET esi, 0
    pushl_cfi %edx
    CFI_REL_OFFSET edx, 0
    pushl_cfi %ecx
    CFI_REL_OFFSET ecx, 0
    pushl_cfi %ebx
    CFI_REL_OFFSET ebx, 0
    movl $(__USER_DS), %edx
    movl %edx, %ds
    movl %edx, %es
    movl $(__KERNEL_PERCPU), %edx
    movl %edx, %fs
    SET_KERNEL_GS %edx
.endm
最后用户态进程的整个状态被完整的记录到内核的栈上了。他的状态映像如下:
 *     0(%esp) - %ebx
 *     4(%esp) - %ecx
 *     8(%esp) - %edx
 *       C(%esp) - %esi
 *    10(%esp) - %edi
 *    14(%esp) - %ebp
 *    18(%esp) - %eax
 *    1C(%esp) - %ds
 *    20(%esp) - %es
 *    24(%esp) - %fs
 *    28(%esp) - %gs        saved iff !CONFIG_X86_32_LAZY_GS
 *    2C(%esp) - orig_eax
 *    30(%esp) - %eip
 *    34(%esp) - %cs
 *    38(%esp) - %eflags
 *    3C(%esp) - %oldesp
 *    40(%esp) - %oldss
内核此刻可以处理用户进程的请求了,首先是判断用户要调用的是合法的系统调用,超过最大系统调用NR_syscall就不合法了。
接着call *sys_call_table(,%eax,4)这个相当于查找系统调用的地址,sys_call_table相当于一系列系统调用的函数指针数组的首地址。
也就是调用sys_call_table+4*eax地址保存的函数指针指向的函数。
    cmpl $(NR_syscalls), %eax
    jae syscall_badsys
syscall_call:
    call *sys_call_table(,%eax,4)

以getppid为例,他应该调用sys_getppid,可是居然源码里面找不到sys_getppid在哪里,用gdb试一下

可以看出符号表在kernel/sys.c里面
()
{
  int ;
   rcu_read_lock();
= (rcu_dereference(current->));
   rcu_read_unlock();
return ; }
又是宏定义。
处理完系统调用相关的函数后,这个进程不一定会立即恢复执行,内核会处理进程收到的信号,并进行调度。
处理完这些以后内核态iret进入用户态。执行用户进程。
大致的处理过程就是这个样子。具体的细节实在太复杂,还得继续努力。
阅读(2239) | 评论(2) | 转发(0) |
0

上一篇:linux系统调用机制

下一篇:linux fork 过程

给主人留下些什么吧!~~

farewellbuaa2015-04-12 14:00:50

pingandezhufu:最后用户态进程的整个状态被完整的记录到内核的栈上了。他的状态映像如下:
 *     0(%esp) - %ebx
 *     4(%esp) - %ecx
 *     8(%esp) - %edx
 *       C(%esp) - %esi
 *    10(%esp) - %edi
 *    14(%esp) - %ebp
你怎么查看的??请教一下

这个是linux源代码里面的注释啊。

回复 | 举报

pingandezhufu2015-04-07 18:44:59

最后用户态进程的整个状态被完整的记录到内核的栈上了。他的状态映像如下:
 *     0(%esp) - %ebx
 *     4(%esp) - %ecx
 *     8(%esp) - %edx
 *       C(%esp) - %esi
 *    10(%esp) - %edi
 *    14(%esp) - %ebp
你怎么查看的??请教一下