内核空间和用户空间有什么区别?内核空间,内核线程,内核进程和内核堆栈是否意味着相同的事情?另外,为什么我们需要这种差异化呢?
答案 0 :(得分:109)
真正的简化答案是内核在内核空间中运行,而普通程序在用户空间中运行。用户空间基本上是一种沙盒形式 - 它限制了用户程序,因此它们不会弄乱其他程序或操作系统内核拥有的内存(和其他资源)。这限制了(但通常并没有完全消除)他们做坏事的能力,比如撞毁机器。
内核是操作系统的核心。它通常可以完全访问所有内存和机器硬件(以及机器上的所有其他内容)。为了使机器尽可能稳定,通常只需要最可信,经过良好测试的代码在内核模式/内核空间中运行。
堆栈只是内存的另一部分,所以它自然会与内存的其余部分一起隔离。
答案 1 :(得分:61)
随机存取存储器(RAM)可以在逻辑上划分为两个不同的区域,即内核空间和用户空间。(The Physical Addresses of the RAM are not actually divided only the Virtual Addresses,所有这些都由{{3}实现}})
内核运行在有权使用它的内存部分。这部分内存不能由普通用户的进程直接访问,而内核可以访问内存的所有部分。要访问内核的某些部分,用户进程必须使用预定义的系统调用,即open
,read
,write
等。此外,C
库函数如{ {1}}依次调用系统调用printf
。
系统调用充当用户进程和内核进程之间的接口。访问权限放在内核空间上,以便在不知不觉中阻止用户搞乱内核。
因此,当发生系统调用时,会向内核发送软件中断。 CPU可以将控制暂时移交给相关的中断处理程序例程。在中断处理程序例程完成其工作后,中断停止的内核进程将恢复。
答案 2 :(得分:22)
内核空间&虚拟空间是虚拟内存的概念......它并不意味着Ram(你的实际内存)被分为内核和内存。用户空间。 每个进程都有虚拟内存,分为内核和内核。用户空间。
所以说 "随机存取存储器(RAM)可以分为两个不同的区域,即内核空间和用户空间。"是错的。
&安培;关于"内核空间与用户空间"事
当创建进程并将其虚拟内存划分为用户空间和内核空间时,其中用户空间区域包含数据,代码,堆栈,进程堆和堆。 kernel-space包含诸如进程的页表,内核数据结构和内核代码等内容。 要运行内核空间代码,控制必须转换到内核模式(使用0x80软件中断进行系统调用)&内核堆栈基本上是在当前在内核空间中执行的所有进程之间共享的。
答案 3 :(得分:11)
CPU响铃是最明显的区别
在x86保护模式下,CPU始终处于4个环之一。 Linux内核仅使用0和3:
这是kernel vs userland最硬,最快的定义。
为什么Linux不使用第1和第2环:CPU Privilege Rings: Why rings 1 and 2 aren't used?
目前的戒指是如何确定的?
当前的戒指是通过以下组合选择的:
全局描述符表:GDT条目的内存表,每个条目都有一个字段Privl
,用于对环进行编码。
LGDT指令将地址设置为当前描述符表。
段注册CS,DS等,它指向GDT中条目的索引。
例如,CS = 0
表示GDT的第一个条目当前对执行代码有效。
每枚戒指可以做什么?
CPU芯片是物理构建的,因此:
ring 0可以做任何事情
ring 3无法运行多条指令并写入多个寄存器,最值得注意的是:
无法改变自己的戒指!否则,它可以将自己设置为响铃0并且响铃将是无用的。
换句话说,无法修改当前确定当前响铃的当前segment descriptor。
无法修改页面表:How does x86 paging work?
换句话说,无法修改CR3寄存器,并且分页本身会阻止修改页表。
这可以防止一个进程看到其他进程的内存,以确保安全/易于编程。
无法注册中断处理程序。这些是通过写入内存位置来配置的,这也可以通过分页来防止。
处理程序在环0中运行,会破坏安全模型。
换句话说,不能使用LGDT和LIDT指令。
无法执行in
和out
等IO指令,因此可以进行任意硬件访问。
否则,例如,如果任何程序可以直接从磁盘读取,则文件权限将毫无用处。
更确切地说,感谢Michael Petch:操作系统实际上可以在环3上允许IO指令,这实际上是由Task state segment控制的。
如果戒指3首先没有这样做,那么戒指3是否允许这样做是不可能的。
Linux总是不允许它。另见:Why doesn't Linux use the hardware context switch via the TSS?
程序和操作系统如何在响铃之间转换?
当CPU打开时,它开始在环0中运行初始程序(很好,但它是一个很好的近似值)。您可以将此初始程序视为内核(但它通常是一个引导加载程序,然后仍然在内环0中调用内核)。
当userland进程希望内核为其执行某些操作(如写入文件)时,它会使用生成中断的指令(如int 0x80
or syscall
)来通知内核。 x86-64 Linux系统调用hello world示例:
.data
hello_world:
.ascii "hello world\n"
hello_world_len = . - hello_world
.text
.global _start
_start:
/* write */
mov $1, %rax
mov $1, %rdi
mov $hello_world, %rsi
mov $hello_world_len, %rdx
syscall
/* exit */
mov $60, %rax
mov $0, %rdi
syscall
编译并运行:
as -o hello_world.o hello_world.S
ld -o hello_world.out hello_world.o
./hello_world.out
当发生这种情况时,CPU会调用内核回调处理程序,内核在引导时注册该处理程序。这是concrete baremetal example that registers a handler and uses it。
此处理程序在ring 0中运行,它决定内核是否允许此操作,执行操作,并在ring 3中重新启动userland程序.x86_64
当使用exec
系统调用(或内核will start /init
)时,新用户空间进程的内核prepares the registers and memory,然后它跳转到入口点,将CPU切换到响铃3
如果程序试图做一些顽皮的事情,比如写入禁止的寄存器或内存地址(因为分页),CPU也会调用第0环中的一些内核回调处理程序。
但是由于用户区很淘气,这次内核可能会杀死进程,或者发出信号警告。
内核启动时,会设置一个固定频率的硬件时钟,定时产生中断。
此硬件时钟生成运行0的中断,并允许它安排唤醒哪些用户进程。
这样,即使进程没有进行任何系统调用,也可能发生调度。
有多个戒指有什么意义?
分离内核和用户空间有两个主要优点:
如何玩它?
我创建了一个裸机设置,应该是直接操纵戒指的好方法:https://github.com/cirosantilli/x86-bare-metal-examples
不幸的是,我没有耐心做出用户名的例子,但我确实做了分页设置,所以userland应该是可行的。我很乐意看到拉动请求。
或者,Linux内核模块在ring 0中运行,因此您可以使用它们来尝试特权操作,例如:读取控制寄存器:How to access the control registers cr0,cr2,cr3 from a program? Getting segmentation fault
这是一个convenient QEMU + Buildroot setup来试用它而不会杀死你的主机。
内核模块的缺点是其他kthread正在运行并且可能会干扰您的实验。但理论上你可以用内核模块接管所有中断处理程序并拥有系统,这实际上是一个有趣的项目。
否定次数
虽然在英特尔手册中实际上没有引用负环,但实际上CPU模式还具有比环0本身更多的功能,因此非常适合负极环#34;名。
一个例子是虚拟化中使用的虚拟机管理程序模式。
有关详细信息,请参阅:https://security.stackexchange.com/questions/129098/what-is-protection-ring-1
<强> ARM 强>
在ARM中,环被称为异常级别,但主要思想保持不变。
ARMv8中存在4个异常级别,通常用作:
EL0:userland
EL1:内核(&#34;主管&#34;在ARM术语中)。
使用svc
指令(SuperVisor Call)输入,以前称为swi
before unified assembly,这是用于进行Linux系统调用的指令。 Hello world ARMv8示例:
.text
.global _start
_start:
/* write */
mov x0, 1
ldr x1, =msg
ldr x2, =len
mov x8, 64
svc 0
/* exit */
mov x0, 0
mov x8, 93
svc 0
msg:
.ascii "hello syscall v8\n"
len = . - msg
在Ubuntu 16.04上使用QEMU进行测试:
sudo apt-get install qemu-user gcc-arm-linux-gnueabihf
arm-linux-gnueabihf-as -o hello.o hello.S
arm-linux-gnueabihf-ld -o hello hello.o
qemu-arm hello
EL2:hypervisors,例如Xen。
使用hvc
指令(HyperVisor Call)输入。
虚拟机管理程序是指操作系统,操作系统属于用户空间。
例如,Xen允许您同时在同一系统上运行多个操作系统(如Linux或Windows),并且它将操作系统彼此隔离,以确保安全性和调试的简便性,就像Linux用于用户程序一样。
虚拟机管理程序是当今云基础架构的关键部分:它们允许多台服务器在单个硬件上运行,使硬件使用率始终接近100%并节省大量资金。
例如,AWS使用Xen直到2017年its move to KVM made the news。
EL3:又一个级别。 TODO的例子。
使用smc
指令(安全模式呼叫)输入
ARMv8 Architecture Reference Model DDI 0487C.a - 第D1章 - AArch64系统级程序员模型 - 图D1-1说明了这一点:
请注意,ARM可能由于后见之明的优势而具有比x86更好的命名约定,而不需要负级别:0表示较低级别,3表示最高级别。较高级别往往比较低级别创建更多。
可以使用MRS
指令查询当前的EL:what is the current execution mode/exception level, etc?
ARM不要求存在所有异常级别,以允许不需要该功能的实现来节省芯片区域。 ARMv8&#34;异常级别&#34;表示:
实现可能不包括所有异常级别。所有实现必须包括EL0和EL1。 EL2和EL3是可选的。
例如,QEMU默认为EL1,但可以使用命令行选项启用EL2和EL3:qemu-system-aarch64 entering el1 when emulating a53 power up
在Ubuntu 18.10上测试的代码片段。
答案 4 :(得分:10)
内核空间和用户空间是特权操作系统功能与受限用户应用程序的分离。分离是必要的,以防止用户应用程序洗劫您的计算机。如果任何旧的用户程序可以开始将随机数据写入硬盘驱动器或从另一个用户程序的内存空间读取内存,那将是一件坏事。
用户空间程序无法直接访问系统资源,因此操作系统内核代表程序处理访问。用户空间程序通常通过系统调用向操作系统发出此类请求。
内核线程,进程,堆栈并不意味着相同的事情。它们是内核空间的类似结构,与用户空间中的对应物一样。
答案 5 :(得分:7)
每个进程都有自己的4GB虚拟内存,通过页表映射到物理内存。虚拟内存大多分为两部分:3 GB用于进程,1 GB用于内核。您创建的大多数变量都位于地址空间的第一部分。那部分称为用户空间。最后一部分是内核所在的位置,并且对于所有进程都是通用的。这称为内核空间,大部分空间都映射到启动时加载内核映像的物理内存的起始位置。
答案 6 :(得分:5)
地址空间的最大大小取决于CPU上地址寄存器的长度。
在具有32位地址寄存器的系统上,地址空间的最大大小为2 32 字节或4 GiB。 类似地,在64位系统上,可以寻址2个 64 字节。
此类地址空间称为虚拟内存或虚拟地址空间。它实际上与物理RAM大小无关。
在Linux平台上,虚拟地址空间分为内核空间和用户空间。
一个名为任务大小限制的架构特定常量,或TASK_SIZE
,标记拆分发生的位置:
地址范围从0到TASK_SIZE
- 1被分配给用户空间;
从TASK_SIZE
到2 32 -1(或2 64 -1)的余数被分配给内核空间。
例如,在特定的32位系统上,可以为用户空间占用3 GiB,为内核空间占用1 GiB。
类Unix操作系统中的每个应用程序/程序都是一个过程;每个都有一个称为进程标识符的唯一标识符(或简称进程ID ,即PID)。 Linux提供了两种创建流程的机制:1。fork()
系统调用,或2. exec()
调用。
内核线程是一个轻量级进程,也是一个正在执行的程序。
单个进程可能包含多个共享相同数据和资源但通过程序代码采用不同路径的线程。 Linux提供clone()
系统调用来生成线程。
内核线程的示例用法是:RAM的数据同步,帮助调度程序在CPU之间分配进程等。
答案 7 :(得分:3)
简单地说:内核在Kernel Space中运行,内核空间可以完全访问所有内存和资源,你可以说内存分为两部分,一部分用于内核,一部分用于用户自己的进程,(用户空间)运行正常程序,用户空间无法直接访问内核空间,因此它要求内核使用资源。通过syscall(在glibc中预定义的系统调用)
有一条声明可以简化不同的“ 用户空间只是内核的测试负载 ”...
非常明确:处理器架构允许CPU以两种模式运行,内核模式和用户模式,硬件指令允许从一种模式切换到另一种模式。
内存可以标记为用户空间或内核空间的一部分。
当CPU在用户模式下运行时,CPU只能访问用户空间中的内存,而cpu尝试访问内核空间中的内存,结果是“硬件异常”,当CPU在内核模式下运行时,CPU可以直接访问内核空间和用户空间......
答案 8 :(得分:2)
Linux内核是指在内核模式下运行的所有内容 由几个不同的层组成。在最低层,内核 通过HAL与硬件交互。在中间层面, UNIX内核分为4个不同的区域。四个中的第一个 区域处理字符设备,原始和熟的TTY和终端 处理。第二个区域处理网络设备驱动程序,路由 协议和套接字。第三个区域处理磁盘设备驱动程序, 页面和缓冲区高速缓存,文件系统,虚拟内存,文件命名和 映射。第四个也是最后一个区域处理进程调度, 调度,创建和终止以及信号处理。 最重要的是,我们有内核的顶层,包括 系统调用,中断和陷阱。这个级别作为 每个低级功能的接口。程序员使用 各种系统调用和中断与功能交互 操作系统。
答案 9 :(得分:2)
简短的内核空间是Linux内核运行的内存部分(Linux的情况下,前置1 GB的虚拟空间),用户空间是用户应用程序运行的内存部分(Linux的情况下,底部3 GB的虚拟内存)如果您想了解更多,请参阅下面给出的链接:)
http://learnlinuxconcepts.blogspot.in/2014/02/kernel-space-and-user-space.html
答案 10 :(得分:2)
内核空间意味着只能由内核触及内存空间。在32位linux上它是1G(从0xC0000000到0xffffffff作为虚拟内存地址)。内核创建的每个进程也是一个内核线程,所以对于一个进程,有两个堆栈:一个堆栈在用户空间用于此进程,另一个堆栈在内核中内核线程的空间。
内核堆栈占用了2个页面(32位linux中的8k),包括一个task_struct(大约1k)和真正的堆栈(大约7k)。后者用于在内核函数中存储一些自动变量或函数调用参数或函数地址。这是代码(Processor.h(linux \ include \ asm-i386)):#define THREAD_SIZE (2*PAGE_SIZE)
#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
#define free_task_struct(p) free_pages((unsigned long) (p), 1)
__ get_free_pages(GFP_KERNEL,1))表示将内存分配为2 ^ 1 = 2页。
但是进程堆栈是另一回事,它的地址只是低于0xC0000000(32位linux),它的大小可以相当大,用于用户空间函数调用。所以这是一个系统调用的问题,它在内核空间运行但是在用户空间中被进程调用,它是如何工作的? linux会将其params和函数地址放在内核堆栈或进程堆栈中吗? Linux的解决方案:所有系统调用都由软件中断INT 0x80触发。 在entry.S(linux \ arch \ i386 \ kernel)中定义,这里有一些行例如:
ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/
.long SYMBOL_NAME(sys_exit)
.long SYMBOL_NAME(sys_fork)
.long SYMBOL_NAME(sys_read)
.long SYMBOL_NAME(sys_write)
.long SYMBOL_NAME(sys_open) /* 5 */
.long SYMBOL_NAME(sys_close)
答案 11 :(得分:1)
尝试提供非常简化的解释
虚拟内存分为内核空间和用户空间。 内核空间是运行内核进程的虚拟内存区域,用户空间是用户进程将运行的虚拟内存区域。
此分区是内存访问保护所必需的。
每当引导加载程序在将内核加载到RAM中的位置后(通常在基于ARM的控制器上)启动内核时,它需要确保控制器处于管理员模式,并且FIQ和IRQ被禁用。
答案 12 :(得分:0)
正确的答案是:没有内核空间和用户空间这样的东西。处理器指令集具有特殊权限,可以设置破坏性内容,如页表映射的根,或访问硬件设备内存等。
内核代码具有最高级别权限,用户代码最低。这可以防止用户代码崩溃系统,修改其他程序等。
通常,内核代码保存在与用户代码不同的内存映射下(就像用户空间保存在不同的内存映射中一样)。这就是&#34;内核空间&#34;和&#34;用户空间&#34;术语来自。但这不是一个硬性规定。例如,由于x86间接要求其中断/陷阱处理程序始终被映射,因此必须将内核的一部分(或一些所有操作系统)映射到用户空间。同样,这并不意味着此类代码具有用户权限。
为什么内核/用户划分必要?一些设计师不同意它实际上是必要的。微内核架构基于以下思想:代码的最高特权部分应尽可能小,所有重要操作都在用户特权代码中完成。你需要研究为什么这可能是一个好主意,它不是一个简单的概念(并且因为有优点和缺点而闻名)。
答案 13 :(得分:0)
内核空间和用户空间是逻辑空间。
大多数现代处理器都设计为以不同的特权模式运行。 x86机器可以在4种不同的特权模式下运行。
当在特定特权模式中/上方时,可以执行特定的机器指令。
由于这种设计,您可以提供系统保护或打包执行环境。
内核是一段代码,它管理您的硬件并提供系统抽象。所以它需要访问所有机器指令。它是最值得信赖的软件。所以我应该以最高特权执行。 Ring level 0 是最有特权的模式。所以 Ring Level 0 也被称为内核模式。
User Application是来自任何第三方供应商的软件,您无法完全信任它们。如果有完全访问所有机器指令的话,有恶意的人可以编写代码来使系统崩溃。因此,应该向应用程序提供对有限指令集的访问。 Ring Level 3 是最低权限模式。所以你的所有应用程序都以该模式运行。因此, Ring Level 3 也称为用户模式。
注意:我没有获得Ring Levels 1和2.它们基本上是具有中间特权的模式。因此可能是使用此权限执行设备驱动程序代码。 AFAIK,linux仅使用Ring Level 0和3分别用于内核代码执行和用户应用程序。
因此,在内核模式下发生的任何操作都可以被视为内核空间。 在用户模式下发生的任何操作都可以视为用户空间。
答案 14 :(得分:0)
内存获取分为两个不同的区域:
在用户空间下运行的进程只能访问内存的有限部分,而内核可以访问所有内存。在用户空间中运行的进程也无权访问内核空间。用户空间进程只能通过内核公开的接口访问一小部分内核-系统调用。如果进程执行系统调用,则会向内核发送软件中断,然后分派适当的中断处理程序并继续处理程序完成后的工作。
答案 15 :(得分:-6)
在Linux中有两个空间,第一个是用户空间,另一个是内核空间。用户空间仅包含您想要运行的用户应用程序。作为核心服务,存在进程管理,文件管理,信号处理,内存管理,线程管理等,并且存在许多服务。如果你从用户空间运行应用程序,应用程序只与内核服务交互。并且该服务与硬件和内核之间存在的设备驱动程序进行交互。 核心空间和用户空间分离的主要好处是我们可以通过用户空间中存在的所有用户应用程序的virus.bcaz来实现安全性,并且服务存在于核心空间中。这就是为什么linux不会影响病毒。