【发布时间】:2019-10-06 09:20:10
【问题描述】:
在研究 Linux 和内存管理的内部结构时,我偶然发现了 Linux 使用的分段分页模型。
如果我错了,请纠正我,但 Linux(保护模式)确实使用分页将线性虚拟地址空间映射到物理地址空间。这个由页构成的线性地址空间,对于进程平面内存模型,被分成四段,即:
- 内核代码段(
__KERNEL_CS); - 内核数据段(
__KERNEL_DS); - 用户代码段(
__USER_CS); - 用户数据段(
__USER_DS);
存在第五个内存段,称为 Null 段,但未使用。
这些段的 CPL(当前权限级别)为 0(主管)或 3(用户空间)。
为简单起见,我将集中于 32 位内存映射,其中 4GiB 可寻址空间,3GiB 用于用户态进程空间(显示为绿色),1GiB 用于主管内核空间(显示为红色) :
所以红色部分由__KERNEL_CS和__KERNEL_DS两段组成,绿色部分由__USER_CS和__USER_DS两段组成。
这些段相互重叠。分页将用于用户空间和内核隔离。
然而,摘自维基百科here:
[...] 许多 32 位操作系统通过将所有段的基数设置为 0 来模拟平面内存模型,以使段与程序无关。
查看 GDT here 的 linux 内核代码:
[GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff),
[GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff),
[GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc093, 0, 0xfffff),
[GDT_ENTRY_DEFAULT_USER32_CS] = GDT_ENTRY_INIT(0xc0fb, 0, 0xfffff),
[GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(0xc0f3, 0, 0xfffff),
[GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(0xa0fb, 0, 0xfffff),
正如彼得指出的那样,每个段都从 0 开始,但那些标志是什么,即0xc09b、0xa09b 等等?我倾向于相信它们是段选择器,如果不是,如果它们的寻址空间都从 0 开始,我将如何从内核段访问用户区段?
不使用分段。只使用分页。段将其seg_base 地址设置为0,将其空间扩展到0xFFFFF,从而提供完整的线性地址空间。这意味着逻辑地址与线性地址没有区别。
另外,既然所有的段相互重叠,那么是分页单元提供了内存保护(即内存分离)吗?
分页提供保护,而不是分段。内核将检查线性地址空间,并根据边界(通常称为TASK_MAX)检查所请求页面的权限级别.
【问题讨论】:
-
将检查所请求页面的权限级别。。不,这不是一个很好的表达方式。对于用户空间提供的地址,内核不需要检查它是用户还是内核,它只需要根据任务的逻辑内存映射(任务使用
mmap和brk管理)来检查它。因为我们有一个平面内存模型,它只是简单的整数比较,内核地址永远不会成为任务有效虚拟地址空间的一部分。 -
内核不依赖硬件在访问无效页面时发出页面错误信号以检测
-EFAULT,因此是否映射了用户空间的无效地址并不重要对于内核(例如,在恰好映射到内核内部的内核地址上调用write())。重要的是有效的用户空间地址在内核模式下仍然有效,在系统调用中。 -
请不要一直尝试编辑问题的答案。如果您有答案,请随意发布作为答案,以便人们可以单独对其进行投票/否决,因此您的答案在其他答案之上没有特殊的位置。在原始问题的某些部分使用删除线是可以的,只要原始问题仍然存在,就可以注意误解,而不会使现有答案无效。通过添加新的误解来重新定义您的问题会为答案创建一个移动的目标。
-
不,内核跟踪与硬件页表分开的逻辑映射。这就是为什么并非所有页面错误都是无效的(在正常的用户空间执行期间,而不是在系统调用内部);例如软和硬页面错误(写时复制或延迟映射,或页面不存在)是硬件中的
#PF异常,因为 PTE 不存在 + 有效(+ 可写),但内核不提供 SIGSEGV;它执行写时复制或其他操作并返回到用户空间,这将成功重新运行错误指令。这是一个“有效的”页面错误。 -
不,关于这句话的几乎所有内容都是倒退和/或错误的。通过将错误地址传递给系统调用,您会得到
-EFAULT返回值。如果您实际上取消引用用户空间中的错误指针,例如mov eax, [0],这不是硬或软页面错误,而是 invalid 页面错误,内核向您的进程提供SIGSEGV信号。页面错误处理程序必须通过根据逻辑内存映射检查地址来判断它是有效还是无效页面错误,就像内核决定是否返回-EFAULT一样。
标签: linux linux-kernel x86 osdev memory-segmentation