用户模式和内核模式之间有什么区别?为什么以及如何激活它们中的任何一个?它们的用例是什么?
用户模式和内核模式之间有什么区别?为什么以及如何激活它们中的任何一个?它们的用例是什么?
Answers:
内核模式
在内核模式下,执行代码对底层硬件具有完全且不受限制的访问权限。它可以执行任何CPU指令并引用任何内存地址。内核模式通常保留给操作系统的最低级别,最受信任的功能。内核模式下的崩溃是灾难性的;他们将停止整个PC。
用户模式
在用户模式下,执行代码无法直接访问硬件或参考存储器。在用户模式下运行的代码必须委托给系统API才能访问硬件或内存。由于这种隔离提供了保护,因此用户模式下的崩溃总是可以恢复的。您计算机上运行的大多数代码都将在用户模式下执行。
阅读更多
这是计算机可以运行的两种不同模式。在此之前,当计算机像一个大房间时,如果发生某些故障,它将使整个计算机停止运行。因此,计算机架构师决定更改它。现代微处理器在硬件中实现至少两个不同的状态。
用户模式:
内核模式:
切换如何发生。
CPU不会自动完成从用户模式到内核模式的切换。CPU被中断(定时器,键盘,I / O)中断。发生中断时,CPU停止执行当前正在运行的程序,切换到内核模式,执行中断处理程序。该处理程序保存CPU的状态,执行其操作,恢复状态并返回到用户模式。
http://zh.wikibooks.org/wiki/Windows_Programming/User_Mode_vs_Kernel_Mode
http://tldp.org/HOWTO/KernelAnalysis-HOWTO-3.html
运行Windows的计算机中的处理器具有两种不同的模式:用户模式和内核模式。处理器根据处理器上运行的代码类型在两种模式之间切换。应用程序以用户模式运行,而核心操作系统组件以内核模式运行。尽管许多驱动程序在内核模式下运行,但某些驱动程序可能在用户模式下运行。
启动用户模式应用程序时,Windows会为该应用程序创建一个进程。该过程为应用程序提供了专用虚拟地址空间和专用句柄表。因为应用程序的虚拟地址空间是私有的,所以一个应用程序无法更改属于另一应用程序的数据。每个应用程序都是独立运行的,如果一个应用程序崩溃,则崩溃仅限于该一个应用程序。其他应用程序和操作系统不受崩溃的影响。
除了私有之外,用户模式应用程序的虚拟地址空间也受到限制。在用户模式下运行的处理器无法访问为操作系统保留的虚拟地址。限制用户模式应用程序的虚拟地址空间可防止应用程序更改甚至可能损坏关键操作系统数据。
在内核模式下运行的所有代码共享一个虚拟地址空间。这意味着内核模式驱动程序不会与其他驱动程序以及操作系统本身隔离。如果内核模式驱动程序意外写入错误的虚拟地址,则可能会破坏属于操作系统或其他驱动程序的数据。如果内核模式驱动程序崩溃,则整个操作系统崩溃。
如果您是Windows用户,一旦通过此链接,您将获得更多。
CPU环是最明显的区别
在x86保护模式下,CPU始终处于4个振铃之一。Linux内核仅使用0和3:
这是内核vs用户态的最难,最快速的定义。
为什么Linux不使用环1和2:CPU特权环:为什么不使用环1和2?
如何确定当前铃声?
当前铃声是通过以下方式选择的:
全局描述符表:GDT条目的内存表,每个条目都有一个Privl
对环进行编码的字段。
LGDT指令将地址设置为当前描述符表。
段寄存器CS,DS等指向GDT中条目的索引。
例如,CS = 0
意味着GDT的第一个条目当前对于执行代码是活动的。
每个环能做什么?
CPU芯片的物理构造是:
环0可以做什么
环3无法运行多个指令并无法写入多个寄存器,最值得注意的是:
不能改变自己的戒指!否则,它可能会将自己设置为环0,并且环将无用。
无法修改页表:x86分页如何工作?
换句话说,不能修改CR3寄存器,分页本身会阻止页表的修改。
出于安全性/易于编程的原因,这可防止一个进程看到其他进程的内存。
无法注册中断处理程序。通过写入存储位置来配置这些地址,这也可以通过分页来防止。
处理程序在环0中运行,并且会破坏安全模型。
换句话说,不能使用LGDT和LIDT指令。
无法执行IO指令(如in
和)out
,因此可以进行任意硬件访问。
否则,例如,如果任何程序可以直接从磁盘读取,则文件权限将无用。
更确切地说,要感谢Michael Petch:操作系统实际上可能在环3上允许IO指令,这实际上是由Task状态段控制的。
如果环3最初没有它,则它不可能允许自己这样做。
Linux总是不允许这样做。另请参阅:Linux为什么不通过TSS使用硬件上下文切换?
程序和操作系统如何在环之间转换?
当CPU开启时,它会在环0中开始运行初始程序(虽然不错,但这是一个很好的近似值)。您可以认为此初始程序是内核(但通常是引导加载程序,然后仍在环0中调用内核)。
当用户级进程希望内核为其执行某项操作(例如写入文件)时,它将使用生成中断的指令,例如int 0x80
或syscall
向内核发出信号。x86-64 Linux syscall你好世界示例:
.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会调用内核在引导时注册的中断回调处理程序。这是一个注册处理程序并使用它的裸机示例。
该处理程序在环0中运行,该环决定内核是否允许该操作,执行该操作并在环3中重新启动userland程序。x86_64
当使用exec
系统调用时(或内核将启动时/init
),内核准备新的userland进程的寄存器和内存,然后跳转到入口点并将CPU切换到第3环
如果程序试图做一些顽皮的事情,例如写入禁止的寄存器或内存地址(由于页面调度),CPU还会在环0中调用一些内核回调处理程序。
但是由于用户空间很顽皮,内核这次可能会终止进程,或者发出警告并带有信号。
内核启动时,它将设置一个固定频率的硬件时钟,该时钟会定期生成中断。
该硬件时钟生成运行于环0的中断,并允许其计划唤醒哪些用户区进程。
这样,即使进程未进行任何系统调用,调度也可能发生。
多环有什么意义?
分离内核和用户域有两个主要优点:
怎么玩呢?
我创建了一个裸机设置,应该是直接操作环的好方法:https : //github.com/cirosantilli/x86-bare-metal-examples
不幸的是,我没有耐心举一个用户区示例,但是我确实进行了分页设置,因此用户区应该是可行的。我很乐意看到拉取请求。
另外,Linux内核模块在环0中运行,因此您可以使用它们来尝试特权操作,例如读取控制寄存器:如何从程序中访问控制寄存器cr0,cr2,cr3?获取细分错误
这是一个方便的QEMU + Buildroot设置,可以在不杀死主机的情况下进行尝试。
内核模块的缺点是其他kthreads正在运行,并且可能会干扰您的实验。但是从理论上讲,您可以使用内核模块来接管所有的中断处理程序并拥有系统,这实际上是一个有趣的项目。
负环
尽管英特尔手册中并未实际提及负环,但实际上有一些CPU模式具有比环0本身更多的功能,因此非常适合“负环”名称。
一个示例是虚拟化中使用的管理程序模式。
有关更多详细信息,请参见:
臂
在ARM中,环被称为“异常级别”,但主要思想保持不变。
ARMv8中存在4个异常级别,通常用作:
EL0:用户区
EL1:内核(ARM术语中的“主管”)。
与svc
指令(SuperVisor调用)一起输入,该指令以前称为swi
统一汇编之前,它是用于进行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
这是一个注册SVC处理程序并进行SVC调用的裸机示例。
与hvc
指令一起输入(HyperVisor调用)。
虚拟机管理程序是针对操作系统的,就像操作系统是针对用户的。
例如,Xen允许您在同一系统上同时运行多个操作系统,例如Linux或Windows,并且为了安全性和调试的方便性,它们相互隔离,就像Linux对用户层程序所做的那样。
虚拟机管理程序是当今云基础架构的关键部分:它们允许多个服务器在单个硬件上运行,从而使硬件使用率始终接近100%,并节省了大量资金。
例如,直到2017年AWS 迁移到KVM时才使用Xen 。
EL3:再上一层。TODO示例。
输入smc
说明(安全模式调用)
在ARMv8架构参考模型DDI 0487C.a - D1章-的AArch64系统级编程模型-图D1-1说明了这美丽的:
随着ARMv8.1虚拟化主机扩展(VHE)的出现,ARM情况发生了一些变化。此扩展允许内核有效地在EL2中运行:
之所以创建VHE,是因为KVM之类的Linux内核内部虚拟化解决方案已经超过Xen(例如,AWS向上述KVM的迁移),因为大多数客户端仅需要Linux VM,并且可以想象,它们全部集成在一个虚拟机中在项目中,KVM比Xen更简单,效率更高。因此,现在在这些情况下,主机Linux内核将充当管理程序。
请注意,也许是由于事后观察的好处,ARM如何比x86具有更好的特权级别命名约定,而又不需要否定级别:0为最低,3为最高。较高的级别往往比较低的级别创建的频率更高。
可以通过以下MRS
指令查询当前的EL :当前的执行模式/异常级别等是什么?
ARM不需要提供所有异常级别,以允许不需要该功能的实现来节省芯片面积。ARMv8“异常级别”说:
一个实现可能不包括所有的异常级别。所有实现都必须包括EL0和EL1。EL2和EL3是可选的。
例如,QEMU默认为EL1,但是可以使用命令行选项启用EL2和EL3:qemu-system-aarch64在模拟a53通电时输入el1
代码片段已在Ubuntu 18.10上进行了测试。
in
并且out
可用于环3的TSS可以指向一个IO权限表的当前任务授权给所有或特定端口的读/写访问。
其他答案已经解释了用户模式和内核模式之间的区别。如果您真的想详细介绍,则应该获得Windows Internals的副本 ,这是Mark Russinovich和David Solomon撰写的一本非常出色的书,描述了各种Windows操作系统的体系结构和内部细节。
什么
基本上,内核模式和用户模式之间的差异不依赖于操作系统,并且仅通过限制某些指令通过硬件设计在内核模式下运行才可以实现。诸如内存保护之类的所有其他目的只能通过该限制来完成。
怎么样
这意味着处理器处于内核模式或用户模式。使用某些机制,该体系结构可以保证只要将其切换到内核模式,就可以获取OS代码以运行。
为什么
有了这种硬件基础架构,可以在常见的操作系统中实现这些功能: