用户态无法执行int 0x80等特权指令,因CPU硬件强制Ring 3权限隔离,触发#GP异常;read()需两次上下文切换与内存拷贝;用户/内核空间内存隔离,跨态数据传输必须经系统调用等明确通道;内核崩溃导致整机停摆。

用户态连 int 0x80 都执行不了,这是硬性权限隔离
不是“功能少一点”,而是 CPU 直接拦住——x86-64 架构下,用户态运行在 Ring 3,所有特权指令(比如关中断、写 CR3 寄存器、直接发 I/O 端口命令)一执行就触发 #GP(通用保护异常),CPU 立刻跳转到内核的异常处理流程。你写个汇编想手动切到内核?不行。想绕过 syscall 直接调驱动?也不行。这种限制由硬件强制实施,操作系统只是坐享其成。
read() 看似简单,背后是两次上下文切换 + 内存拷贝
每次调用 read(),实际发生的是:
- 用户进程从
Ring 3切到Ring 0:保存用户寄存器、切换栈、加载内核页表 - 内核在内核态执行设备驱动逻辑,把数据从磁盘/网卡读进内核缓冲区
- 再把数据从内核缓冲区
copy_to_user()拷贝到用户提供的地址(这个地址必须是用户空间合法地址,否则返回-EFAULT) - 最后切回用户态,恢复寄存器,继续执行下一条指令
这四步加起来,一次 read() 调用开销远高于纯计算。高频小包 I/O(比如每毫秒读 16 字节)会把大量 CPU 时间耗在切换上,而不是干活。
用户空间和内核空间内存互不可见,kmalloc() 分的地址用户态根本用不了
Linux 把虚拟地址空间劈成两半:低地址归每个进程私有(用户空间),高地址是所有进程共享的内核空间(32 位通常是 0xc0000000 以上,64 位更靠后)。关键点在于:
- 用户态指针(比如
char *buf = malloc(4096))的值,在内核看来就是个无效数字;直接传给驱动当 DMA 地址?硬件会访问错地方甚至崩溃 - 内核用
kmalloc()或__get_free_page()分配的内存,用户态无法mmap、无法read()、无法任何方式触达 - 跨态传数据必须走明确通道:系统调用参数、
copy_from_user()/copy_to_user()、ioctl、procfs、sysfs、netlink等——没走这些,数据就过不去
内核态崩溃等于整机停摆,但用户态段错误只杀自己
一个 segfault 只会让当前进程收到 SIGSEGV 然后退出,不影响其他进程;而内核里一个空指针解引用(比如驱动里写了 dev->ops->probe(NULL))、或竞态导致链表乱掉,结果就是 Kernel panic 或静默死锁——没有“重启应用”这回事,只有硬重启。这也是为什么内核模块开发必须极度谨慎:没单元测试、没 ASan、没 UBSan,全靠人眼和经验扛着走。
真正难的不是理解“谁权限高”,而是意识到:用户态和内核态之间那道墙,既是保护伞,也是数据搬运的必经关卡;越想绕开它提性能,越得先吃透它怎么砌的砖。










