是否可以在不映射内核的情况下将进程映射到内存中?

Tre*_*rey 5 x86 assembly memory-management osdev linux-kernel

OSDev维基说:

在每个用户进程中映射内核是传统的并且通常很好

那为什么呢?这个过程不能单独映射到内存吗?映射内核有什么好处,这不会浪费空间吗?

此外,是否可以从用户空间访问内核空间,为什么我会这样做?

Pet*_*des 11

在每个用户进程中映射内核是传统的并且通常很好

因此,当您进行系统调用时,内核不必更改页表以访问它自己的内存.例如,一直映射所有物理内存会使read系统调用从页面缓存中的任何位置复制内容变得更便宜.

是否可以从用户空间访问内核空间,为什么我会这样做?

通常内核会禁用它.页表条目有一个用户/管理程序位,用于控制是否可以在内核模式下使用它(即我认为是环3).因此,内核可以保留其内存映射,同时仍然保护它免受用户空间的读/写.(另请参阅此页面以获取页面目录的嵌套图.)

CPU具有支持这种用例的性能特性:每个PTE中都有一个"全局"位(如果设置)意味着即使CR3发生更改(即跨内核交换机,内核安装时),CPU也可以将其缓存在TLB中一个新的页面表).内核为每个进程中包含的内核映射设置它.

而且,对于那些内核映射,可能只有一个表的物理副本,每个不同的用户空间页表树的顶层页面映射级别4表(PML4)仅指向相同的内核PDPTE结构(大多数/所有这些实际上都是1GiB hugepage映射,而不是指向更多级别的条目).请参阅上面链接的图表.


内核实际上有少量内存允许用户空间读取(和执行):内核将称为VDSO区域的几个4k页面映射到每个进程的地址空间(位于虚拟内存的最顶端).

对于像gettimeofday()和这样的一些简单但常见的系统调用getpid(),用户空间可以call在这些页面中起作用(例如rdtsc,通过内核导出的常量运行和缩放结果),而不是使用syscall进入内核模式并在那里执行相同的操作.对于现代x86 CPU上的内核模式往返,这可节省50到100个时钟周期,而更多的是在分派到正确的系统调用之前不需要内核中的所有内容的保存/恢复.


是否可以在不映射内核的情况下将进程映射到内存中?

通过64位内核上的32位进程,整个4GiB虚拟地址空间可用于用户空间. (除了3个左右的4k VDSO页面.)

否则(当用户空间虚拟地址与内核空间虚拟地址一样宽时)Linux将上半部分用于所有物理内存的内核映射(在x86上使用1G largepages).

i386 Linux有一个配置选项,可以分割1:3,IIRC,进一步限制内核,但允许更多的虚拟地址空间用于用户空间进程.IDK,如果这对于其他体系结构上的32位内核或仅x86是常见的.

这不是浪费空间吗?

它占用了一些虚拟地址空间,但你应该拥有比物理内存更多的空间.如果不这样做,则必须支付更频繁地重新映射内存的速度成本.

这就是我们拥有x86-64的原因,因此虚拟地址空间非常庞大.48位是256 TiB,因此其中一半是128 TiB的地址空间.如果必要/有用,未来的CPU可以为更广泛的虚拟地址实现硬件支持.(页表格式最多支持52位物理地址.).对于非易失性DIMM而言,这可能会成为一个问题,提供比DRAM更高密度的内存映射存储,以及使用大量这两种地址空间的原因.

如果在单个进程中需要超过2GiB的虚拟地址空间,请使用64位系统.(或者如果你需要一个极好的进程/线程,至少使用一个64位内核.带有PAE的32位内核有时会遇到内存分配问题.请参阅一些https://serverfault.com/问题.)

有人在他们的博客上重新发布了一些Linus Torvalds关于PAE(物理地址扩展)的评论,该评论允许在仅32位的x86系统上拥有超过4GB的物理内存.总结:哎呀,即使有一个很好的内核端实现,它肯定比64位内核慢.除了英特尔工程师更有趣的侮辱,他们认为这对于32位操作系统来说是个好主意并解决问题.