Linux内核分析(第五周)
系统调用的三层皮(下)
一、给MenuOs增加time和time-asm命令
ls
rm menu -rf
git clone xx(克隆新版本)
cd menu
make rootfs(自动编译生成根文件系统)
help
version
time
time asm
vi time.c(增加了time,tim-asm:0)更新menu代码到最新版;1)在main函数中增加menuconfig;2)增加对应的time函数和timeasm函数)3)make rootfs
二、使用gdb跟踪系统调用内核函数 sys_time
qemu -kernel linux -3,18,6/arch/x86/boot/xxxxxxxxxxxxxx(启动qemu)
gdb
file linux -3,18,6/VMlinux (debug加载)
target remote:1234(链接 menuOS)
b start_kernel
c
b sys_time
c
list(如果单步执行会进入schedule函数)
s.
s.
s.
return i;
(sys_time 返回后进入汇编代码处理gdb无法继续跟踪)
(执行 int 0x80之后执行 system_call对应的代码)
b system_call x
c
三、系统调用在内核代码中的处理过程
1.系统调用在内核代码中的工作机制和初始化
2.trap_init();简化后便于理解的system_call伪代码
kernel/entry.32.s
entry(system_call)
处理过程
3.浏览system_call到iret之间的主要代码
xxxxxxxxx
save_all
xxxxxxxxx
syscall_call;
call *sys_call_table(,%eax ,4) (实际调用的系统服务程序)
xxx
xxx
restore_all
四、实验
step1.
git clone https://github.com/mengning/menu.git //克隆新版本的menu
cd menu //进入menu文件夹
step2.
进入test.c 添加需要的函数
step3.
输入make rootfs //生存根文件系统并启动
step4.
gdb跟踪调试分,别在start_kernel和sys_getpid两个函数的位置设置断点
流程图:
开始→保存现场(save_all)→系统调用表(call *sys_call_table)→ sys_call_exit→restore_all→iret→结束
↓ ↑
sys_exit_work(work_pending
working_ restore)
调用机制的初始化在start_kernel里面的trap_init()函数里进行,这个函数里面包含了sys_call汇编代码的入口,初始化好了之后,一旦执行int 0x80,CPU就会自动跳转到sys_call来执行。
sys_call的相关代码的位置是Linux-3.18.6/arch/x86/kernel/entry_32.s,里面的ENTRY(system_call)为int 0x80后的下一条指令,因其不是一个正常的函数,所以CPU还不能对其进行跟踪。
由代码可知,系统调用的过程大致分为三个阶段:保存现场SAVE_ALL、调用系统调用相对应的处理函数如time、getpid等,call *sys_call_table()、恢复现场RESORE_ALL 最后ire结束,返回用户态。在这个过程中,可能 会用到syscall_exit_work,里面有关于进程调度的函数。