系统调用的三层机制
实验过程
1.克隆MenuOS
rm menu -rf //强制删除当前menu
git clone http://git.shiyanlou.com/mengning/menu.git //重新克隆新版本的menu
cd menu
ls
2.打开test.c并在里面添加上次实验所用的getpid的c函数和汇编代码
3.在main函数中加入MenuConfig
4.make rootfs
5.使用hellp命令可以看到qemu中增加了我们先前添加的命令:
6.执行新增加的命令getpid getpid_asm可得:
7.gdb跟踪分析一个系统调用内核函数
8.在start_kernel处设置断点,继续执行,在qemu窗口的结果:
9.查看我所选用的系统调用的函数:
10.设置断点在sys_getpid处,发现执行命令getpid时并没有停下,在执行getpid_asm时停下了:
11.直接结束若干次单步执行,然后继续往下单步执行,发现出现了进程调度函数,返回了进程调度中的一个当前进程任务的值。
12.设置断点于system_call处。发现可停,而继续执行时,刚才停下的getuid_asm也返回了值。
实验分析
- 系统调用在内核代码中的工作机制和初始化
- main.c中start_kernel函数:trap_init()
- set_system_trap_gate(SYSCALL_VECTOR,&system_call)
- SYSCALL_VECTOR:系统调用的中断向量
- &system_call:汇编代码入口——执行int 0x80,系统直接跳转到system_call。
2.系统调用——一个特殊的中断
- SAVE_ALL:保存现场
- call *sys_call_table(,%eax,4)调用了系统调度处理函数,eax存的是系统调用号,是实际的系统调度程序。
- sys_call_table:系统调用分派表,syscall_after_all:保存返回值
- 若有sys_exit_work,则进入sys_exit_work:会有一个进程调度时机。work_pending -> work_notifysig,用来处理信号 可能call schedule:进程调度代码可能跳转到restore_all,恢复现场。
- 若无sys_exit_work,就执行restore_all恢复,返回用户态INTERRUPT_RETURN <=> iret,结束。
在系统调用返回之前,可能发生进程调度,进程调度里就会出现进程上下文的切换。
进程间通信可能有信号需要处理。
可以将内核视为一系列中断指令的集合。
3.system_call的流程示意图
遇到的问题
在进行gdb调试的时候,我导入文件的时候出现了下面的问题
原因:是因为我进入到了menu里面去了,应该退出来回到LinuxKernel的目录下面来执行调试。
回到上面的目录下载进行调试就可以导入文件了
本章总结
- 通过本章的学习和实验,我首先明白了系统调用是一种特殊的中断,初步理解了系统调用的过程。
- 在系统调用时,我们需要SAVE_ALL,用于保存系统调用时的上下文。同样,中断处理的第一步应该也要保存中断程序现场。目的:在中断处理完之后,可以返回到原来被中断的地方,在原有的运行环境下继续正确的执行下去。
- 在系统调用时,我们需要将系统调用号通过eax传入,通过sys_call_table查询到调用的系统调用,然后跳转到相应的程序进行处理。同样,中断处理时系统也需要有一个中断号,通过检索中断向量表,了解中断的类型和设备。
- 系统调用时最后要restore_all恢复系统调用时的现场,并用iret返回用户态。同样,执行完中断处理程序,内核也要执行特定指令序列,恢复中断时现场,并使得进程回到用户态。
在实验部分我学到了:给menuOS增加命令的方法:
强制删除menu (rm menu -rf)
更新menu代码至最新版本(git clone https://github.com/mengning/menu.git)
在test.c中main函数中增加MenuConfig,以及增加上周自己选择Getegid,GetegidAsm的代码
Make roofts自动编译,生成,和启动根文件系统
使用gdb跟踪调试内核的方法:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
gdb
(gdb)file linux-3.18.6/vmlinux # 在gdb界面中targe remote之前加载符号表
(gdb)target remote:1234 # 建立gdb和gdbserver之间的连接,按c 让qemu上的Linux继续运行
(gdb)break start_kernel # 断点的设置,注意寻找对应的系统调用函数名字,例如time命令对应sys_time