我是一个操作系统初学者,我有一个关于操作系统内核的问题。
我已经习惯了每个用户进程都有一个包含堆栈、堆、数据和代码的虚拟地址空间的标准概念。我的问题是,当OS内核发生上下文切换时,内核中运行的代码是否被视为具有堆栈、堆、数据和代码的进程?
我知道有一个专用的内核堆栈,用户程序无法访问它。这是否位于用户程序地址空间?
我知道操作系统需要维护一些数据结构来完成它的工作,比如进程控制块。这些数据结构位于哪里?他们在用户程序地址空间吗?它们是否位于内核数据结构的专用内存段中?它们是否散落在有空间的物理记忆周围?
最后,我看到了一些图表,其中OS代码位于用户程序地址空间的顶部。整个操作系统内核都在这里吗?如果没有,操作系统内核的代码还驻留在哪里?
谢谢你的帮忙!
发布于 2019-01-08 08:03:09
是的,内核有自己的堆栈、堆、数据结构和代码,与每个用户进程的堆栈、堆、数据结构和代码是分开的。
在内核中运行的代码本身并不被视为“进程”。代码是特权的,意思是它可以修改内核中的任何数据,在处理器寄存器中设置特权位,发送中断,与设备交互,执行特权指令等等。它不像用户进程中的代码那样受到限制。
所有内核内存和用户进程内存都存储在计算机中的物理内存中(如果数据已从内存中交换,则可能存储在磁盘上)。
回答其他问题的关键是理解物理内存和虚拟内存之间的区别。请记住,如果您使用虚拟内存地址访问数据,则该虚拟地址在数据被获取到确定的物理地址之前被转换为物理地址。
每个进程都有自己的虚拟地址空间。这意味着一个进程中的某个虚拟地址与另一个进程中的同一个虚拟地址相比,可以映射到不同的物理地址。虚拟内存有许多重要的用途,但我不打算在这里讨论它们。最重要的一点是,虚拟内存加强了内存隔离。这意味着进程A不能访问进程B的内存。进程A的所有虚拟地址映射到一些物理地址集,而进程B的所有虚拟地址映射到不同的物理地址集。只要这两组物理地址不重叠,进程就无法看到或修改彼此的内存。用户进程不能直接访问物理内存地址--它们只能使用虚拟地址进行内存访问。
有时,两个进程可能有一些虚拟地址来映射到相同的物理地址,例如,如果它们都mmap相同的文件,两者都使用共享库等等。
现在来回答关于内核地址空间和用户地址空间的问题。
内核可以从每个用户进程中拥有一个独立的虚拟地址空间。这就像在每个上下文开关上更改cr3寄存器(在x86处理器中)中的页面目录指针一样简单。由于内核具有不同的虚拟地址空间,只要内核的虚拟内存地址没有一个映射到与用户进程的任何地址空间中的任何虚拟地址相同的物理地址,任何用户进程都无法访问内核内存。
这可能会导致一个小问题。如果用户进程进行系统调用并将指针作为参数传递(例如,指向read系统调用中的缓冲区的指针),内核如何知道哪个物理地址对应于该缓冲区?指针中的虚拟地址映射到内核空间中的不同物理地址,因此内核不能仅仅取消对指针的引用。有两种选择:
内核通常采用第二种选择,因为它更方便、更高效。选项1的效率较低,因为每次发生上下文切换时,地址空间都会发生变化,因此需要刷新TLB,现在需要丢失所有缓存的映射。我在这里简化了一些事情,因为内核已经开始以不同的方式处理事情,因为最近发现了熔毁漏洞。
这就引出了另一个问题。如果内核在用户进程地址空间中包含它的映射,那么是什么阻止用户进程访问内核内存呢?内核在页面表中设置保护位,从而导致处理器禁止用户进程访问映射到包含内核内存的物理地址的虚拟地址。
有关更多信息,请查看这些幻灯片。
发布于 2019-01-08 19:39:34
我已经习惯了每个用户进程都有一个包含堆栈、堆、数据和代码的虚拟地址空间的标准概念。我的问题是,当OS内核发生上下文切换时,内核中运行的代码是否被视为具有堆栈、堆、数据和代码的进程?
我所知道的每一个现代操作系统中都没有上下文切换到内核。内核在进程的上下文中执行(一些系统使用简化的进程上下文。
当进程通过异常或中断进入内核模式时,“内核”将执行。
每个进程(线程)通常在异常后使用自己的内核模式堆栈。通常每个处理器都有一个单一的中断堆栈。
我知道有一个专用的内核堆栈,用户程序无法访问它。这是否位于用户程序地址空间?
每个进程都有自己的内核堆栈。它通常位于具有保护内存的用户空间中,但可能位于系统空间中。中断堆栈总是在系统空间中。
这些数据结构位于哪里?他们在用户程序地址空间吗?
它们一般都在系统空间中。然而,有些系统确实将一些结构放在用户空间中的受保护内存中。
它们是否位于内核数据结构的专用内存段中?
如果它们位于用户空间中,则通常用于比用户模式更特权的访问模式,以及比内核模式更少的特权模式。
它们是否散落在有空间的物理记忆周围?
认为可以随机分布在物理记忆上。
发布于 2022-09-16 12:09:11
问题中的数据结构通常是由内核分配器分配给内核的RAM中的常规C结构。
由于内存保护和分页(虚拟内存)的正常机制,它们通常不能从常规进程访问。
这方面的一种例外是没有用户空间地址空间的内核线程,因此它们执行的代码总是与内核空间数据结构一起工作的内核代码,因此具有独立的内核内存。
现在,关于有趣的部分:64位Linux使用了一个名为Direct的内存组织,这意味着所有可用的物理内存都被映射到内核页面表中,作为一个连续块。对于32位则不是这样,因为使用HIGHMEM是为了避免4GB地址空间的限制。
由于内核的所有物理RAM都是可见的,并且可以由它自己的分配器使用,因此所讨论的内核数据结构可以相对于物理地址被随机地放置。
您可以在那里搜索以获得更多信息:
https://stackoverflow.com/questions/54084215
复制相似问题