给MenuOS添加系统调用
打开终端,输入以下命令:
cd ~/LinuxKernel
rm -rf menu
git clone https://github.com/mengning/menu.git
cd menu
vi test.c
在test.c
中加入如下图所示两段代码:
然后在终端中输入make rootfs
重新编译内核,可以在打开的qemu
界面看到,此时MenuOS
中有了getpid
的命令选项:
使用gdb跟踪系统调用内核函数
打开终端shell1
,输入
cd ~/LinuxKernel
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -S -s
打开另一个终端shell2
,启动gdb
,输入
file linux-3.18.6/vmlinux
target remote:1234
b start_kernel
c
b sys_getpid
c
可以在qemu
界面看到MenuOS
在调用getpid
时中断
分析system_call处理过程
在linux-3.18.6/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 //在eax寄存器中存入系统调用号
SAVE_ALL //保存现场
GET_THREAD_INFO(%ebp) //存放当前进程thread_info结构的地址
# system call tracing in operation / emulation
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
jnz syscall_trace_entry
cmpl $(NR_syscalls), %eax //将检查系统调用号(系统调用号应小于NR_syscalls)
jae syscall_badsys //检查出错,跳入异常处理
syscall_call:
call *sys_call_table(,%eax,4) //根据系统调用表,调取相应的系统调用处理函数
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 //有任务,进入system_exit_work进行进程调度
restore_all:
TRACE_IRQS_IRET //恢复现场
restore_nocheck:
RESTORE_REGS 4 # skip orig_eax/error_code
irq_return:
INTERRUPT_RETURN //系统调用返回
其流程图如图