system_call中断处理过程分析

来源:互联网 发布:黑马大数据培训 编辑:程序博客网 时间:2024/05/16 11:17

        张涛(与最后申请证书的姓名务必一致) + 原创作品转载请注明出处 + 《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) \
                                                .globlname 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 anywayASM_CLACpushl_cfi %eax# save orig_eaxSAVE_ALL# 保存现场GET_THREAD_INFO(%ebp)# system call tracing in operation / emulationtestl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)jnz syscall_trace_entrycmpl $(NR_syscalls), %eaxjae syscall_badsyssyscall_call:call *sys_call_table(,%eax,4)# 这里将真正调用对应的系统调用,调用号的意义在这里也表现出来了sys_call_table + 4 * %eax即为系统调用的地址syscall_after_call:movl %eax,PT_EAX(%esp)# store the return valuesyscall_exit:LOCKDEP_SYS_EXITDISABLE_INTERRUPTS(CLBR_ANY)# make sure we don't miss an interrupt# setting need_resched or sigpending# between sampling and the iretTRACE_IRQS_OFFmovl TI_flags(%ebp), %ecxtestl $_TIF_ALLWORK_MASK, %ecx# current->workjne syscall_exit_workrestore_all:TRACE_IRQS_IRETrestore_all_notrace:#ifdef CONFIG_X86_ESPFIX32movl 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), %ahmovb PT_CS(%esp), %alandl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eaxcmpl $((SEGMENT_LDT << 8) | USER_RPL), %eaxCFI_REMEMBER_STATEje ldt_ss# returning to user-space with LDT SS#endifrestore_nocheck:RESTORE_REGS 4# skip orig_eax/error_codeirq_return:INTERRUPT_RETURN

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

###################################################################################################.balignL1_CACHE_BYTES.globlsystem_callsystem_call:LEDS0x6101movsgpsr,gr4; enable exceptionsorigr4,#PSR_ET,gr4movgsgr4,psrstigr7,@(gr28,#REG_SYSCALLNO)sti.pgr8,@(gr28,#REG_ORIG_GR8)subiccgr7,#nr_syscalls,gr0,icc0bncicc0,#0,__syscall_badsysldi@(gr15,#TI_FLAGS),gr4andiccgr4,#_TIF_SYSCALL_TRACE,gr0,icc0bneicc0,#0,__syscall_trace_entry__syscall_call:slli.pgr7,#2,gr7sethi%hi(sys_call_table),gr5setlo%lo(sys_call_table),gr5ld@(gr5,gr7),gr4calll@(gr4,gr0)################################################################################# return to interrupted process################################################################################__syscall_exit:LEDS0x6300# keep current PSR in GR23movsgpsr,gr23ldi@(gr28,#REG_PSR),gr22sti.pgr8,@(gr28,#REG_GR(8)); save return value





0 0
原创粉丝点击