引言
哪里是操作系统?
Linux Kernel 的维护者说,提供Syscall的是操作系统。
汇编爱好者说,提供系统调用库函数的下面的是操作系统。
ArchLinux佳豪说,上面这些加上一些Terminal,一些Network Manager,和一个Pacman,就是操作系统。
Ubuntu用户说,这个桌面和内置的小软件以下是操作系统。
余承东说鸿蒙是操作系统。
正在许愿Vibe coding的文科生说,deepseek帮我复刻一些windowsxp。
操作系统的上面。
在内存中心呼唤系统的自陷
要找到操作系统的上边界,让我们深入所谓用户软件和操作系统在书上所定义的,发生切换的一瞬间。
目态与管态
要理解为什么会有“切换的瞬间”,就要知道为什么需要这么做,他们在切换什么。
另外的一组名字叫做用户态和内核态,原因很简单,互联网上的软件千千万万,良莠不齐,需要给内核操作和用户操作彻底隔离开(不只是在两种状态,后面会提到)。包括系统指令的地址空间都是用户不可达的,需要让用户软件不触及操作系统的正常允许。
你也不想qq崩溃直接给系统拉闸了吧。
但是那些系统方法总得用吧,不能用户程序啥也不做,所以需要用一种特殊的方式来切换系统模式
系统调用
对于一般的程序员,能够碰到最下面的地方就是库函数,这里我们以c语言举例。
比如write()方法,write(fd, buf, count)
- 传递参数
首先这几个参数(标识符,写入内容地址头,长度)会被重写为汇编能识别的参数,然后调用write函数
mov edx, 5
lea rsi, [rip + hello]
mov edi, 1
call write
注意这下面的call是正常汇编的调用函数,此时PC的值改为call+指令长+偏移指向write函数开头。
返回地址(RSP)压入用户栈。此时我们的参数们还在刚才塞进去的寄存器里面。
- 执行系统调用
此时执行系统调用(ABI)前,必须填写以下的规范化系统调用参数,这个过程具体有点太具体了,远远超过了408会考察的范围,总之会把刚才的参数传递进去。
RAX = 系统调用号
RDI = 参数1
RSI = 参数2
RDX = 参数3
R10 = 参数4
R8 = 参数5
R9 = 参数6在这一堆参数传递完毕后,终于到了那传说中操作系统的边界
syscall- 硬件隐指令
首先硬件会自动关中断,保存现场(原始PSW),给原函数syscall的地址入栈(RCX=syscall地址+指令长)。
值得注意的是这个地方新旧系统并不一样,64位系统通常用MSR寄存器直接表明syscall的各种内核入口内存地址,但是32位老系统(也就是408)参考书上的农逼系统一般是通过中断向量寻址,查询IDT(中断描述符表)和中断向量号来寻找syscall的入口地址。考试建议假装是后者。
这个过程纯自动,然后开中断。
然后切换CPU模式,把CPL从3(用户)改为0(内核)。
- 取得参数
因为刚才已经往寄存器传递了参数,所以内核可以从寄存器取得这些参数的值。
- 内核函数真正执行
这个时候内核函数才开始真正执行write函数实际的内容,这里就不细讲了,和主题没啥关系。
- 恢复现场,返回用户态
此时把栈顶的保护现场的PC值出栈,PSW写回原来的样子,需要传回的参数也写入寄存器传回。
然后执行
sysretq此时回到原始程序syscall的下一条位置。
之后从write函数的ret地址跳回write下一个指令位置,这个过程结束。
408辩经
值得注意的,考过的,这些系统调用的库函数并不是操作系统的边界,是他们的最后一行执行的syscall(农逼老电脑可能是INT)会切换到内核态执行系统调用。
操作系统的下面
硬件和OS的冒险 Episode00
相比上一个问题,这个问题就变得没有答案了,因为OS的底层和硬件深度耦合,不太可能清楚地分开。
我们用上面那个write的瞬间举例子
回到syscall发生的那一瞬间。
硬件隐指令
在syscall之后,硬件而非os开始接管。
切换内核态,关中断,保存寄存器,保存现场,压栈地址,跳到内核syscall开始的地方,这些步骤就是硬件自己执行的,在这之后才是OS执行的地方。
配置与自动
OS与硬件更多的是一种配置和自动执行的关系。
页表
比如所谓的内存管理。首先是操作系统来建立了你所见到的树上的页表,告诉了硬件虚实地址的映射关系,这就是配置
之后每次访存OS直接传递的就是虚拟地址而非物理地址,此时查表,地址转换都是硬件自动执行,但是,但是,如果缺页错误,将会调回操作系统执行缺页处理程序。
进程调度
又比如所谓调度过程,本质上并不是CPU自己知道什么时候该调度什么进程,相反的。
是OS通过定时器中断给CPU打入内核态,然后执行调度器,这个时候才决定要不要切换上下文,切换进程。
硬件中断
当外部控制器(I/O中断)发出中断的一瞬间,CPU停止当前程序,保存现场,找到中断向量表的入口,进入内核态,之后OS接入,执行USB驱动程序(或者别的什么驱动程序),驱动程序再来处理这个外部中断具体内容。
总结
不难发现OS对于上层的边界是非常非常清晰的,但是和硬件是揉在一起的。
但是这是假象,操作系统这个词语的边界在2026年绝对不是所谓syscall的一瞬间。