system_call中断处理过程分析

        张涛(与最后申请证书的姓名务必一致) + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

        系统调用是上层软件最终与操作系统沟通的唯一途径,于是我们需要分析操作系统调用的整个流程以便于更清楚地知道操作系统如何运作。

        课程中追加调用的方法如下:       

int TimeAsm(int argc, char *argv[])
{
    time_t tt;
    struct tm *t;
    asm volatile(
        "mov $0,%%ebx\n\t"
        "mov $0xd,%%eax\n\t" 
        "int $0x80\n\t" 
        "mov %%eax,%0\n\t"  
        : "=m" (tt) 
    );
    t = localtime(&tt);
    printf("time:%d:%d:%d:%d:%d:%d\n",t->tm_year+1900, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
    return 0;
}

int main()
{
    PrintMenuOS();
    SetPrompt("MenuOS>>");
    MenuConfig("version","MenuOS V1.0(Based on Linux 3.18.6)",NULL);
    MenuConfig("quit","Quit from MenuOS",Quit);
    MenuConfig("time","Show System Time",Time);
    MenuConfig("time-asm","Show System Time(asm)",TimeAsm);	// 将实现的函数加入到命令列表中
    ExecuteMenu();                				// 最终执行体,等待用户交互
}

       以下附上其注册和执行流程:

/* add cmd to menu */
int MenuConfig(char * cmd, char * desc, int (*handler)())
{
    tDataNode* pNode = NULL;
    if ( head == NULL)
    {
        head = CreateLinkTable();
        pNode = (tDataNode*)malloc(sizeof(tDataNode));
        pNode->cmd = "help";
        pNode->desc = "Menu List";
        pNode->handler = Help;
        AddLinkTableNode(head,(tLinkTableNode *)pNode);
    }
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = cmd;
    pNode->desc = desc;
    pNode->handler = handler; 
    AddLinkTableNode(head,(tLinkTableNode *)pNode);  // 关键在这里,添加到命令链表中
    return 0; 
}


/* Menu Engine Execute */
int ExecuteMenu()  // 命令执行程序
{
   /* cmd line begins */
    while(1)
    {
		int argc = 0;
		char *argv[CMD_MAX_ARGV_NUM];
        char cmd[CMD_MAX_LEN];
		char *pcmd = NULL;
        printf("%s",prompt);
        /* scanf("%s", cmd); */
		pcmd = fgets(cmd, CMD_MAX_LEN, stdin);
		if(pcmd == NULL)
		{
			continue;
		}
        /* convert cmd to argc/argv */
		pcmd = strtok(pcmd," ");
		while(pcmd != NULL && argc < CMD_MAX_ARGV_NUM)
		{
			argv[argc] = pcmd;
			argc++;
			pcmd = strtok(NULL," ");
		}
        if(argc == 1)
        {
            int len = strlen(argv[0]);
            *(argv[0] + len - 1) = '\0';
        }
        tDataNode *p = (tDataNode*)SearchLinkTableNode(head,SearchConditon,(void*)argv[0]);
        if( p == NULL)
        {
            continue;
        }
        printf("%s - %s\n", p->cmd, p->desc);
        if(p->handler != NULL) 
        { 
            p->handler(argc, argv);   // 这里最终执行我们添加进命令链表的函数
        }
    }
} 

        以上流程还是比较清晰的。

        接着,步入正轨,具体了解调用流程:

        1.库函数触发中断,并给出系统调用号;2.操作系统通过中断描述符表找到对应的中断处理函数:

       于是我们看到了 : ENTRY(system_call)

        进一步找到对应的宏定义:/linux-3.18.6/include/linux/linkage.h

        #define ENTRY(name) \
                                                .globl name ASM_NL \
                                                ALIGN ASM_NL \

                                                name:

        这里有些不太理解,按照宏中显示此处便定义了标号system_call,但在后面却又看到system_call,希望理解的小伙伴可以告知,觉得这段主要起链接用途,还有个ENDPROC(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
	cmpl $(NR_syscalls), %eax
	jae syscall_badsys
syscall_call:				
	call *sys_call_table(,%eax,4)	# 这里将真正调用对应的系统调用,调用号的意义在这里也表现出来了sys_call_table + 4 * %eax即为系统调用的地址
syscall_after_call:
	movl %eax,PT_EAX(%esp)		# store the return value
syscall_exit:
	LOCKDEP_SYS_EXIT
	DISABLE_INTERRUPTS(CLBR_ANY)	# make sure we don't miss an interrupt
					# setting need_resched or sigpending
					# between sampling and the iret
	TRACE_IRQS_OFF
	movl TI_flags(%ebp), %ecx
	testl $_TIF_ALLWORK_MASK, %ecx	# current->work
	jne syscall_exit_work

restore_all:
	TRACE_IRQS_IRET
restore_all_notrace:
#ifdef CONFIG_X86_ESPFIX32
	movl PT_EFLAGS(%esp), %eax	# mix EFLAGS, SS and CS
	# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
	# are returning to the kernel.
	# See comments in process.c:copy_thread() for details.
	movb PT_OLDSS(%esp), %ah
	movb PT_CS(%esp), %al
	andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax
	cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
	CFI_REMEMBER_STATE
	je ldt_ss			# returning to user-space with LDT SS
#endif
restore_nocheck:
	RESTORE_REGS 4			# skip orig_eax/error_code
irq_return:
	INTERRUPT_RETURN

         一下在附上系统调用表/linux-3.18.6/arch/frv/kernel/entry.S ,摘录了部分
 

###################################################################################################
	.balign		L1_CACHE_BYTES
	.globl		system_call
system_call:
	LEDS		0x6101
	movsg		psr,gr4			; enable exceptions
	ori		gr4,#PSR_ET,gr4
	movgs		gr4,psr

	sti		gr7,@(gr28,#REG_SYSCALLNO)
	sti.p		gr8,@(gr28,#REG_ORIG_GR8)

	subicc		gr7,#nr_syscalls,gr0,icc0
	bnc		icc0,#0,__syscall_badsys

	ldi		@(gr15,#TI_FLAGS),gr4
	andicc		gr4,#_TIF_SYSCALL_TRACE,gr0,icc0
	bne		icc0,#0,__syscall_trace_entry

__syscall_call:
	slli.p		gr7,#2,gr7
	sethi		%hi(sys_call_table),gr5
	setlo		%lo(sys_call_table),gr5
	ld		@(gr5,gr7),gr4
	calll		@(gr4,gr0)


###############################################################################
#
# return to interrupted process
#
###############################################################################
__syscall_exit:
	LEDS		0x6300

	# keep current PSR in GR23
	movsg		psr,gr23

	ldi		@(gr28,#REG_PSR),gr22

	sti.p		gr8,@(gr28,#REG_GR(8))	; save return value





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值