分析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
" //系统调用号赋给eax寄存器
"mov %1,%%ebx
" //将文件夹的名称赋给ebx寄存器
"mov %2,%%ecx
" //将文件夹的权限赋给ecx寄存器
"int $0x80
" //开启中断,执行mkdir系统调用
"mov %%eax,%0
" //将返回值赋给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结束该操作。