我想确切地了解什么是用户空间?我问的每个人都说:“任何不是内核的东西”。但这对我来说不是有形的。当我读到内核可以在用户空间或类似的东西上运行该驱动程序时;我无法想象会发生什么!。因此,如果有人在这方面让我直截了当,我将不胜感激。
Bru*_*ger 42
在一个概念层面上,内核是在“更特权”的硬件保护级别上运行的一切。这就像 x86 处理器上的 ring 0、ARM 上的系统模式、MIPS 上的内核模式、68xxx 上的主管模式等。内核通常是中断驱动的,要么是软件中断(系统调用),要么是硬件中断(磁盘驱动器、网络卡、硬件定时器)。
在相同的概念级别上,“用户空间”是在最低特权模式下运行的(x86 CPU 上的环 3,ARM 或 MIPS 上的用户模式等)。用户空间利用内核平滑微小硬件差异的方式,为所有程序提供相同的 API。例如,一些无线网卡可能有额外的控制寄存器,或者包含更多或更少的用于传入数据包的板载缓冲区。驱动程序代码解释了这些差异(有时会忽略高级或不寻常的功能),并为所有程序提供相同的套接字 API。
一些处理器(例如 x86、VAX、Alpha AXP)有两种以上的模式,但通用 Unix 架构不使用中间模式。
您看到在 Unix 或 Linux 或 *BSD 中运行的程序和进程是用户空间。由于进程是可抢占的,您实际上永远不会看到内核运行,您只会看到副作用,例如read()系统调用返回或信号处理函数运行。
为了回答您的具体问题,在 Unix、Linux、*BSD 中,“驱动程序”通常是一些处理某些硬件特定特性的小型软件:网卡、磁盘驱动器、视频卡。驱动程序软件几乎总是需要在 Ring 0/supervisor 模式/内核空间中运行,以便访问硬件中断,或硬件的映射内存或其他任何东西。驱动程序负责特定的硬件功能,并使硬件适合内核代码关于硬件应该如何工作的标准化或常规视图。因此,在用户态运行驱动程序需要内核向用户态程序显示诸如映射内存或设备寄存器或中断或其他特殊功能等内容。这可能很棘手,因为设备可能需要的特殊功能并不 t 很容易适应呈现给用户土地程序的通常的 Unix 风格的 API。此外,调度也是一个问题,因为用户登陆程序通常不会那么快地响应中断。
Law*_*ceC 10
大多数现代 CPU 都有内核或管理员模式,以及受限用户模式。这是 CPU 的硬件特性。“Userland”是在用户模式下运行的代码的另一个名称。
两种模式之间的一大区别在于大多数现代 CPU 的 MMU 如何在它们下工作。
一个MMU允许使它们看起来象码以不同的顺序内核重新排列的RAM块(或页)比他们在物理上是在RAM中,并且还导致用户模式代码到陷阱或“故障”回内核模式如果某些页面是访问。用户模式不能改变 MMU 的功能,只有内核模式可以做到。
所以,MMU 允许内核模式代码做各种很酷的事情,比如:
您可以看到 MMU 以及内核/用户模式是多任务操作系统的基石,使用这些工具可以创建一个可以处理更高级别事物(例如进程概念)的系统。内核为每个进程维护页表,并在它切换到用户模式之前对 MMU 进行基本上重新编程,并在其时间片上控制进程。malloc进程获取内存之类的东西会导致内核修改 MMU 页表。
同样,用户模式不能对页表做任何事情(并且不需要知道它们的存在),如果它需要内存,它需要调用内核,这会导致从用户模式切换到内核模式。CPU 提供了一种称为软件中断的简单机制来执行此操作,Linux 内核还有其他更快的方法。
由于存在于用户模式中的这种保护,如果程序执行诸如崩溃或失控并覆盖自身之类的事情,内核可以停止此进程。在内核模式下,这种保护不存在,因此内核将停止工作,因此您的整个系统也将停止工作。当内核模式中发生这种不可恢复的错误时,称为内核恐慌。请参阅什么是“内核恐慌”?详情。
内核可以在用户空间上运行该驱动程序
CPU 的内核或主管模式也阻止用户模式直接访问 I/O 设备,其想法是它必须调用内核来做到这一点。在Linux中,代码会谈设备直接(它们在内核模式下运行)的设备驱动程序(一类的内核模块,你可以操纵他们的命令一样lsmod,insmod,modprobe,和rmmod)。
如果您的设备驱动程序(在最简单的设置下以内核模式运行)出现错误并且做了一些令人讨厌的事情,例如覆盖 RAM 中的随机内容(并且由于它处于内核模式,它可以不受限制地访问所有 RAM 并且可以覆盖)会发生什么?内核本身)。如果我们能让设备驱动程序在用户模式下运行,这样它就不能对内核本身或其他进程做任何事情,那就太好了。
不幸的是,从用户模式切换到内核模式(称为上下文切换)很慢,因为基本上 CPU 的整个状态必须为每个进程或内核本身切入和切出。所以,我们有两件事不一致,安全或速度,因此这是一个争论点和设计点。
尝试在用户模式下尽可能多做的内核称为微内核,而 Linux 则相反,称为单片内核。Linux 确实存在用户模式驱动程序(以 FUSE 为例),甚至有一个框架允许它。
根据 Bruce 所说,提供给内核的所有代码都必须是可信的。如果内核可以通过某种方式执行恶意代码,那么游戏就结束了。这就是用户执行代码和内核执行代码的权限分离发挥作用的地方。由用户运行的代码不一定必须 100% 没有恶意。它不会由内核直接执行。
用户态程序只是与内核的暴露部分交互,例如 API 和加载的模块。一个例子是iptables。有几个内核模块 (.ko) 或“驱动程序”实际执行 的工作iptables,它们是netfilter 框架的一部分。当您使用命令执行命令时,/sbin/iptables您使用的是 userland 组件,该组件又与加载到内核中的 netfilter 模块进行通信。这允许分离,以便内核不会无意中执行用户代码。
深入了解这些概念的一种方法是阅读osdev.org或James Molloy 的教程之类的教程。
正如布鲁斯所说,Linux 有一个整体内核,这意味着它的代码完全在 x86 架构上的 ring 0 中运行。因此,拥有对所有资源的完全控制权,内核将管理用户级应用程序(以最低权限级别 3 运行)对它们的所有请求
想一想:如果来自用户空间的应用程序可以完全访问虚拟内存——RAM——他们可以把所有东西都扔掉,从其他进程的堆栈或堆到内核的内部缓冲区。内核将页面映射到每个进程的页面目录,如果应用程序错误地尝试访问不属于其地址空间的位置,那么它将被强制关闭。
接下来,想想如果每个程序都可以直接访问打印机或其他一些输出设备会发生什么。尝试打印到打印机的进程的两个并发实例会将所有内容打乱,但如果这些请求通过内核,则它们将被排队并单独处理,从而产生两个单独的打印页面。
此外,由于机器的处理器数量通常比当前运行的进程少,因此内核使用调度程序在进程之间切换,每个进程都有自己的有限时间来使用处理器。当这个时间到期时,它将被移动到活动进程列表的末尾,或者移动到非活动进程列表 - 如果进程一直在等待来自某个设备的数据。这样,虽然只有一个进程,但所有进程似乎都在并发运行,或者内核在任何给定时刻都可以使用一个处理器。这个概念被称为伪并行。
关于您关于用户空间驱动程序的最后一个问题:这是可能的,但内核仍然完全控制与设备的通信。例如,内核可以将内核内存区域映射到用户空间驱动程序的内存区域,从而使其能够访问设备内存。内核仍然有权将更改转发到设备或不转发。这个用户界面驱动程序将提供一个很好的界面来控制设备到其他用户应用程序,如果驱动程序以某种方式崩溃,仍然有很好的机会重新加载它而不必重置机器。如果驱动程序一直在内核空间,比如说一个模块,如果模块卡住了并且无法卸载,那么它也不能重新加载,因为它的符号已经存在,所以唯一的机会是重置机器。
总而言之,像 cat top 或“hello world”这样的应用程序只能在用户空间中运行,只能通过内核 API 访问系统资源,这是一组称为系统调用的函数。因此,当应用程序发出 read() 系统调用以读取文件时,内核会控制处理器,使用适当的驱动程序(如 HDD 驱动程序)读取数据,然后将此数据复制回由传递给 read() 系统调用的指针,让应用程序在此数据可用时继续运行。
| 归档时间: |
|
| 查看次数: |
20450 次 |
| 最近记录: |