分析system_call中断处理过程
在MenuOS中添加上周所运用到的系统调用
即在Linuxkernel/menu/test.c文件中,添加代码如下:
int Mkdir() { const char *ch = "test"; //创建的文件夹名称 mode_t mode = 0700; //创建的文件夹的权限 int flag = 0; //是否创建成功新的文件夹的标识符 flag = mkdir(ch,mode); //调用mkdir if(flag==0) //flag=0则创建成功,否则失败 { printf("succeed"); } else printf("error"); return 0; } int MkdirAsm() { char *ch="test-asm"; //创建文件夹的名称 mode_t mode=S_IRWXU; //创建新的文件夹的权限 int flag=0; //标识符 asm volatile( "mov $0x27,%%eax\n\t" //系统调用号赋给eax寄存器 "mov %1,%%ebx\n\t" //将文件夹的名称赋给ebx寄存器 "mov %2,%%ecx\n\t" //将文件夹的权限赋给ecx寄存器 "int $0x80\n\t" //开启中断,执行mkdir系统调用 "mov %%eax,%0\n\t" //将返回值赋给flag :"=m"(flag) //输出变量flag :"d"(ch),"D"(mode) //输入变量ch与mode ); if(flag==0) //flag=0则创建成功,否则失败 printf("succeed"); else printf("error"); return 0; } int main() { PrintMenuOS(); SetPrompt("MenuOS>>"); MenuConfig("version","XXX V1.0(Menu program v1.0 inside)",NULL); MenuConfig("quit","Quit from XXX",Quit); MenuConfig("mkdir","Make up a new director",Mkdir); MenuConfig("Mkdirasm","Make up a new director by asm",MkdirAsm); ExecuteMenu(); }
- make rootfs即可完成功能的添加
gdb单步调试系统调用mkdir
设置断点:
在MenuOS界面输入mkdir,则发现停在了system_mkdir该函数处:
进行单步调试,发现其步骤大约为读取pathname(所需要创建文件夹的名称),配置权限,完成创建:
同理输入命令mkdirasm,完成单步调试,与mkdir一样的结果(因为都是调用系统调用mkdir)
输入c,将程序进行完,则出现最终结果:
system_call到iret的步骤
代码如下:
.macro INTERRUPT_RETURN ; 中断返回 iret .endm .macro SAVE_ALL ; 保护现场 ... .macro RESTORE_INT_REGS ... .endmENTRY(system_call) SAVE_ALL syscall_call: call *sys_call_table(,%eax,4) movl %eax, PT_EAX(%esp) ; store the return value syscall exit: testl $_TIF_ALLWORK_MASK, %ecx # current->work jne syscall_exit_work restore_all: RESTORE_INT_REGS irq_return: INTERRUPT_RETURN ; 到这里就算执行完了 ENDPROC(system_call) syscall_exit_work: testl $_TIF_WORK_SYSCALL_EXIT, %ecx jz work_pending END(syscall_exit_work) work_pending: testb $_TIF_NEED_RESCHED, %cl jz work_notifysig work_resched: call schedule jz restore_all work_notifysig: ... ; deal with pending signals END(work_pending)
流程图如下:
SAVE_ALL宏可以在栈中保存中断处理程序可能会使用的所有CPU寄存器,以此起到保护现场的作用
根据sys_call_table查找所需要的中断程序的中断号,从而执行system_call
系统调用完成后,则执行iret结束该操作。