首先是对函数的调用堆栈有了深刻的理解,在实验中通过gdb分析汇编,知道了调用一个函数时候栈中的rbp、rsp是如何变换的。
然后主要学习了x86和ARM64指令集架构,了解到这两种指令集的区别,并且完成了对RISC-V具体代码的堆栈分析。
在编写一个最精简的操作系统内核实验中了解到一个计算机系统的基本工作原理,计算机中的存储程序计算机、函数调用堆栈、中断是计算机中的三大法宝
之后对操作系统的系统调用做了深入分析,了解系统调用的流程:
- 应用程序 代码调用系统调用( xyz ),该函数是一个包装系统调用的 库函数 ;
- 库函数 ( xyz )负责准备向内核传递的参数,并触发 软中断 以切换到内核;
- CPU 被 软中断 打断后,执行 中断处理函数 ,即 系统调用处理函数 ( system_call);
- 系统调用处理函数 调用 系统调用服务例程 ( sys_xyz ),真正开始处理该系统调用。
软中断指令int 0x80执行时,系统调用号会被放入eax寄存器,同时,sys_call_table每一项占用4个字节。这样,system_call函数可以读取eax寄存器获得当前系统调用的系统调用号,将其乘以4生成偏移地址,然后以sys_call_table为基址,基址加上偏移地址所指向的内容即是应该执行的系统调用服务例程的地址。此时, 可以真正执行sys_xyz()。
之后详细介绍了操作系统的中断系统
CPU 硬件级的中断信号处理过程 :
1. 确定与中断或异常相关联的向量 i
2. 读取 idtr 寄存器的值,找到 IDT 的基址,通过查询 IDT,找到第 i 项对应的内容。
3. 从 gdtr 寄存器获得 GDT 的基地址,并在 GDT 中查找,以读取IDT 表项中的段选择符所标识的段描述符。
4. 确定中断是由授权的发生源发出的。
5. 检查是否发生了特权级的变化,一般指的是用户态陷入内核态。
如果是用户态陷入内核态,控制单元要使用新的特权级堆栈。保存 ss 和 esp,并用新的堆栈的值填充。
6. 如果是故障,用引起故障的指令修改 cs 和 eip,以便异常处理后再次执行。
7. 在堆栈中保存 eflags/cs/eip 的内容。
8. 如果有硬件出错码,则保存。
9. 使用 IDT 中第 i 项中的段描述符和偏移量填充 cs 和 eip。
在mykernel的基础上实现一个极简内核,配置步骤如下:
wget https://raw.github.com/mengning/mykernel/master/mykernel-2.0_for_linux-5.4.34.patch sudo apt install axel axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz xz -d linux-5.4.34.tar.xz tar -xvf linux-5.4.34.tar cd linux-5.4.34 patch -p1 < ../mykernel-2.0_for_linux-5.4.34.patch sudo apt install build-essential gcc-multilib sudo apt install qemu # install QEMU sudo apt install libncurses5-dev bison flex libssl-dev libelf-dev make defconfig # Default configuration is based on 'x86_64_defconfig' make -j$(nproc) qemu-system-x86_64 -kernel arch/x86/boot/bzImage
实验结果:
可以看到my_start_kernel在执行,同时my_timer_handler时钟中断处理程序周期性执行。
-
安装开发工具 vscode
-
下载内核源代码(上一个实验已经安装)
-
准备配置文件.config
-
make menuconfig:
配置内核选项
配置:Kernel hacking —> Compile-time checks and compiler options —> [*] Compile the kernel with debug info [*] Provide GDB scripts for kernel debugging [*] Kernel debugging Processor type and features ----> [] Randomize the address of the kernel image (KASLR)
-
make [-j #] 编译内核
make -j$(nproc) # 测试内核运行是否正常 qemu-system-x86_64 -kernel arch/x86/boot/bzImage
-
生成initramfs根文件系统镜像,习惯于命名为rootfs
首先从https://www.busybox.net下载 busybox源代码解压,解压完成后,跟内核一样先配置编译,并安装。
axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2 tar -jxvf busybox-1.31.1.tar.bz2 cd busybox-1.31.1 make menuconfig # 编译成静态链接 Settings ---> [*] Build static binary (no shared libs) # 编译安装 make -j$(nproc) && make install
然后制作内存根文件系统镜像,大致过程如下
mkdir rootfs
cd rootfs
cp ../_install/* ./ -rf
mkdir dev proc sys home
sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/
准备init脚本文件放在根文件系统跟目录下(rootfs/init)
#!/bin/sh mount -t proc none /proc mount -t sysfs none /sys echo "Wellcome MengningOS!" echo "--------------------" cd home /bin/sh
给init脚本添加可执行权限
打包成镜像文件并测试
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz
7. 命令行debug linux kernel
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"
再打开一个窗口,启动gdb,把内核符号表加载进来,建立连接:
gdb vmlinux (gdb) target remote:1234 (gdb) b start_kernel c、bt、list、next、step....
8. VScode debug linux kernel
配置文件:https://github.com/mengning/linuxkernel/tree/master/src/kerneldebuging
配置.vscode/tasks.json和.vscode/launch.json
配置好之后将断点设在init/main.c中的start_kernel函数中,然后Qemu 开启GDB调试,vscode start debug即可开始调试内核。
参考资料https://gitee.com/mengning997/linuxkernel《庖丁解牛Linux操作系统分析》 孟宁



