内核为何无法直接访问用户进程地址?已映射物理页需重映射原因
这问题问到点子上了——刚好触及Linux内核内存管理的核心逻辑,尤其是高端内存区的处理机制。直接给结论:
不行,内核不能依赖用户进程的页表来访问物理页,必须将其重新映射到内核空间的线性地址(高端内存区)
下面具体拆解原因:
内核并非总运行在进程上下文
内核会在很多没有活跃用户进程的场景下执行,比如中断处理程序、软中断或者内核线程。这些时候,当前生效的页表是内核全局页表(init_mm),而非任何用户进程的页表。根本没有用户页表可以依赖,所以内核必须有自己的映射才能访问物理页。用户页表的映射不稳定、不可靠
用户进程可以随时修改自己的页表——比如通过mmap()、munmap()调用,甚至页交换操作。如果内核依赖这些映射,可能在操作中途突然发现物理页已被取消映射(或映射到了其他地址),直接导致崩溃或数据损坏。内核需要的是完全由自己控制的稳定映射。权限与地址空间隔离的限制
用户页表项会标记用户态权限(比如x86架构的PTE_U位)。虽然内核运行在特权级(ring0)理论上能访问,但依赖用户权限会打破内核与用户地址空间的隔离。更关键的是,内核线性地址空间和用户空间是分离的——就算物理页被映射到用户空间,内核地址空间里也没有对应的入口来直接引用它。临时切换到用户页表虽然可行,但会带来巨大的性能开销,还会破坏操作的原子性(原子操作中途不能切换页表)。高端内存区需要内核专属的映射机制
高端内存区存在的原因就是内核的永久线性地址空间无法覆盖所有物理内存。内核会用临时kmap映射、永久kmap槽位或者vmalloc这类专门机制,把高端内存页映射到自己的线性地址空间。这些机制是为了解决内核地址空间不足的问题,而用户页表的映射完全不涉及这个需求——用户映射在自己的地址空间里,根本帮不了内核在自身上下文访问物理页。避免页错误处理的复杂风险
如果内核通过用户映射访问物理页,而该页已经被交换到磁盘,就会触发页错误。在内核上下文处理页错误极度棘手(且往往不安全),因为内核无法轻易暂停执行来等待页被换入。内核自己的映射能确保访问时页驻留在物理内存中,避免这种场景。
内容的提问来源于stack exchange,提问作者user1734905

