(一)给MenuOs增加time和time-asm命令
- 更新menu代码到最新版
- 在main函数中增加MenuConfig
- 增加对应的Ttime和TimeAsm函数
- make rootfs
(二)使用gdb跟踪系统调用内核函数sys_time
1.sys_time返回后进入汇编代码处理gdb无法继续跟踪
2.执行0x80之后执行system_call对应的代码
3.entry32.s中system_call 不是一个函数,只是一段汇编代码的起点,gdb不能跟踪它。
(三)系统调用在内核代码中的处理过程
1.系统调用在内核代码中的工作机制和初始化
- 系统调用的工作机制:
通知内核的机制是靠软中断实现的:在x86系统上预定义的软中断是中断号128,通过int$0x80指令触发该中断,这条指令会触发一个异常导致系统切换到内核态并执行128号异常处理程序,即system_call().
- 系统调用机制的初始化:
2.简化后便于理解的system_call伪代码
1.系统调用其实就是一个特殊的中断
2.伪代码如下:
3.代码分析:
# system call handler stub
ENTRY(system_call) #系统调用处理入口(内核态)RING0_INT_FRAME # can't unwind into user space anywayASM_CLACpushl_cfi %eax # save orig_eax #保存eax,也就是调用号 SAVE_ALL # 保存寄存器 GET_THREAD_INFO(%ebp) # 获取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) # 在系统调用表中的调用相应的服务例程,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 syscall_exit_work: testl $_TIF_WORK_SYSCALL_EXIT, %ecx jz work_pending # 测试是否退出前还有工作要处理,如果有的话跳转到work_pending TRACE_IRQS_ON # 开启系统中断跟踪 ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call # 允许中断 # schedule() instead movl %esp, %eax call syscall_trace_leave jmp resume_userspace # 恢复用户空间 END(syscall_exit_work) work_pending: testb $_TIF_NEED_RESCHED, %cl # 是否有需要继续调度的相关信号 jz work_notifysig # 跳转到处理信号相关的代码处 work_resched: call schedule # 时间调度, 进程调度的时机在这里处理 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 andl $_TIF_WORK_MASK, %ecx # is there any work to be done other 是否还有其他工作要处理 # than syscall tracing? jz restore_all #如果没有的话就恢复中断上下文,也就是恢复进入之前保存的寄存器相关内容 testb $_TIF_NEED_RESCHED, %cl jnz work_resched work_notifysig: # deal with pending signals and # notify-resume requests #ifdef CONFIG_VM86 testl $X86_EFLAGS_VM, PT_EFLAGS(%esp) movl %esp, %eax jne work_notifysig_v86 # returning to kernel-space or # vm86-space 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
4.流程图:
- 在系统调用返回之前,可能发生进程调度,进程调度里就会出现进程上下文的切换
- 进程间通信可能有信号需要处理