学号尾号: 155
基于 Ubuntu kylin 18.10 虚拟机
实验准备
下载和编译内核
- wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.tar.xz # 下载内核
- # 解压文件
- xz -d Linux-5.0.1.tar.xz
- tar -xvf Linux-5.0.tar.xz
- cd Linux-5.0
- # 编译内核
- make i386_defconfig
此处出现报错:
执行以下命令
apt-get install flex
再次执行
make i386_defconfig
出现报错
执行以下命令
apt-get install bison
再次执行
- make i386_defconfig
- make
出现报错
执行以下命令
apt-get install libssl-dev
再次执行
make
等待一段时间后, 控制台会输出如下信息, 表示编译完成
制作根文件系统
- cd ..
- mkdir rootfs
- Git clone https://github.com/mengning/menu.git
- cd menu
- gcc -pthread -o init linktable.c menu.c test.c -m32 -static
此处出现问题:
- apt install gcc-multilib
- gcc -pthread -o init linktable.c menu.c test.c -m32 -static
再次出现问题
- apt-get install gcc-4.8 gcc-4.8-multilib g++-4.8 g++-4.8-multilib
- gcc -pthread -o init linktable.c menu.c test.c -m32 -static
成功了
- cd ../rootfs
- cp ../menu/init ./
- find . | cpio -o -Hnewc |gzip -9> ../rootfs.img
制作成功!
启动 MenuOS
- cd ..
- qemu -kernel Linux-5.0/arch/x86/boot/bzImage -initrd rootfs.img
启动成功!
---
跟踪系统调用
我的学号尾号是 155, 在查阅系统调用表后, 发现 155 号系统调用是
#define __NR_sched_getparam 155
函数的原型是
- #include <sched.h>
- // 该函数用于根据进程号获取进程的调度参数, pid 用于指定要获取调度参数的进程号, 为 0 时表示获取当前进程的调度参数
- //param 用于存储获得的进程调度参数
- // 返回 0 时表示成功获得进程的调度参数, 返回 - 1 时表示出错, 并设置 errno
- //errno 有两种, EPERM: 调用进程没有足够的权限来获取调度参数. ESRCH: 进程 pid 不存在.
- int sched_getparam(pid_t pid,struct sched_param * param);
- struct sched_param
- {
- int32_t sched_priority;// 获取调度参数时, 此成员将反映分配给线程或进程的优先级
- int32_t sched_curpriority;// 获取调度参数时, 此成员将设置为线程或进程当前运行的优先级. 这是内核在进行调度决策时使用的值.
- union
- {
- int32_t reserved[8];
- struct
- {
- int32_t __ss_low_priority;
- int32_t __ss_max_repl;
- struct timespec __ss_repl_period;
- struct timespec __ss_init_budget;
- } __ss;
- } __ss_un;
- }
- #define sched_ss_low_priority __ss_un.__ss.__ss_low_priority
- #define sched_ss_max_repl __ss_un.__ss.__ss_max_repl
- #define sched_ss_repl_period __ss_un.__ss.__ss_repl_period
- #define sched_ss_init_budget __ss_un.__ss.__ss_init_budget
对于该系统调用, 我们可以写出如下代码对其进行测试
- // 在 menu 文件夹中的 test.c 文件中加入如下代码
- #include <sched.h>
- int test_get_param()
- {
- struct sched_param param;
- sched_getparam(0,¶m);
- printf("The original priority of the process is %d\n",param.sched_priority);
- }
- int main()
- {
- PrintMenuOS();
- SetPrompt("MenuOS>>");
- MenuConfig("version","MenuOS V1.0(Based on Linux 3.18.6)",NULL);
- MenuConfig("quit","Quit from MenuOS",Quit);
- MenuConfig("time","Show System Time",Time);
- MenuConfig("time-asm","Show System Time(asm)",TimeAsm);
- MenuConfig("get_param","根据进程号获取进程的优先级",test_get_param);
- ExecuteMenu();
- }
重新制作根文件系统
- gcc -pthread -o init linktable.c menu.c test.c -m32 -static
- cd ../rootfs
- cp ../menu/init ./
- find . | cpio -o -Hnewc |gzip -9> ../rootfs.img
使用 gdb 跟踪调试内核
- cd ..
- qemu -kernel Linux-5.0/arch/x86/boot/bzImage -initrd rootfs.img -S -s -append nokaslr
此时启动的 qemu 窗口是 stopped 的状态
另开一个 shell 窗口
- gdb
- file vmlinux # target remote 之前加载符号表
- target remote:1234 # 建立 gdb 和 gdbserver 之间的连接, 按 c 让 qemu 上的 Linux 系统继续运行
- b sys_sched_getparam # 打上断点
在 gdb 窗口中输入
c
在 qemu 窗口中输入
get_param
在 gdb 窗口中输入
c
系统调用分析
可以看到, sched_getparam 系统调用的流程如下:
用户调用 sched_getparam 接口
将系统调用号 155 放入 eax 寄存器
执行 int $0x80 指令产生一个向量为 128 的编程异常, 进入内核态
保护现场
根据系统调用号, 查找系统调用表, 找到中断处理程序的地址并执行中断处理程序
恢复现场, 进入用户态
由此可以看出, 用户态进程是无法访问内核的内存空间的, 只有内核态进程才能访问内核. 因此当执行系统调用时, 必须要先将进程转换成内核态才能执行系统调用, 执行完毕后再恢复到用户态.
来源: http://www.bubuko.com/infodetail-2993095.html