Sal*_*ali 45
这些是计算机可以运行的两种不同模式.在此之前,当计算机就像一个大房间,如果有什么东西崩溃 - 它会停止整个计算机.所以计算机架构师决定改变它.现代微处理器在硬件中实现至少2种不同的状态.
用户模式:
内核模式:
切换如何发生.
从用户模式切换到内核模式不是由CPU自动完成的.CPU被中断(定时器,键盘,I/O)中断.当发生中断时,CPU停止执行当前运行的程序,切换到内核模式,执行中断处理程序.此处理程序保存CPU的状态,执行其操作,恢复状态并返回到用户模式.
http://en.wikibooks.org/wiki/Windows_Programming/User_Mode_vs_Kernel_Mode
http://tldp.org/HOWTO/KernelAnalysis-HOWTO-3.html
http://en.wikipedia.org/wiki/Direct_memory_access
http://en.wikipedia.org/wiki/Interrupt_request
Cir*_*四事件 12
CPU环是最明显的区别
在 x86 保护模式下,CPU 始终处于 4 个环之一。Linux内核只使用0和3:
这是内核与用户空间的最严格和快速的定义。
为什么 Linux 不使用环 1 和 2:CPU 特权环:为什么不使用环 1 和 2?
当前环是如何确定的?
当前环由以下组合选择:
全局描述符表:内存中的 GDT 条目表,每个条目都有一个Privl
对环进行编码的字段。
LGDT 指令将地址设置为当前描述符表。
段寄存器 CS、DS 等,它们指向 GDT 中条目的索引。
例如,CS = 0
表示 GDT 的第一个条目当前对于正在执行的代码是活动的。
每个戒指能做什么?
CPU 芯片的物理构造使得:
ring 0 可以做任何事情
ring 3 不能运行多个指令并写入多个寄存器,最显着的是:
不能换自己的戒指!否则,它可以将自己设置为环 0,而环将毫无用处。
换句话说,不能修改当前段描述符,它决定了当前环。
无法修改页表:x86 分页如何工作?
换句话说,不能修改 CR3 寄存器,分页本身阻止了页表的修改。
出于安全/易于编程的原因,这可以防止一个进程看到其他进程的内存。
不能注册中断处理程序。这些是通过写入内存位置来配置的,这也可以通过分页来防止。
处理程序在环 0 中运行,并且会破坏安全模型。
换句话说,不能使用 LGDT 和 LIDT 指令。
不能执行in
和这样的 IO 指令out
,因此可以任意访问硬件。
否则,例如,如果任何程序可以直接从磁盘读取,文件权限将毫无用处。
更准确地说,感谢Michael Petch:操作系统实际上可以允许环 3 上的 IO 指令,这实际上是由任务状态段控制的。
如果环 3 首先没有它,那么它不可能允许自己这样做。
Linux 总是不允许它。另请参阅:为什么 Linux 不通过 TSS 使用硬件上下文切换?
程序和操作系统如何在环之间转换?
当 CPU 打开时,它开始在环 0 中运行初始程序(很好,但它是一个很好的近似值)。您可以将这个初始程序视为内核(但它通常是一个引导加载程序,然后调用仍在 ring 0 中的内核)。
当用户态进程希望内核为它做一些事情,比如写入文件时,它会使用一条指令来生成中断,例如int 0x80
或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
Run Code Online (Sandbox Code Playgroud)
编译并运行:
as -o hello_world.o hello_world.S
ld -o hello_world.out hello_world.o
./hello_world.out
Run Code Online (Sandbox Code Playgroud)
发生这种情况时,CPU 调用内核在启动时注册的中断回调处理程序。这是一个注册处理程序并使用它的具体裸机示例。
这个处理程序在 ring 0 中运行,它决定内核是否允许这个动作,执行这个动作,并在 ring 3 中重新启动用户态程序。 x86_64
当exec
系统调用被使用时(或内核将启动时/init
),内核准备新用户态进程的寄存器和内存,然后跳转到入口点并将CPU切换到ring 3
如果程序试图做一些诸如写入禁止寄存器或内存地址(由于分页)之类的顽皮事情,CPU 还会调用 ring 0 中的某些内核回调处理程序。
但是由于用户空间是顽皮的,内核这次可能会杀死进程,或者给它一个信号警告。
当内核启动时,它会设置一个具有固定频率的硬件时钟,它会定期产生中断。
该硬件时钟生成运行 ring 0 的中断,并允许它安排唤醒哪些用户级进程。
这样,即使进程没有进行任何系统调用,也可以进行调度。
拥有多个戒指有什么意义?
分离内核和用户空间有两个主要优点:
如何玩弄它?
我创建了一个裸机设置,应该是直接操作环的好方法:https : //github.com/cirosantilli/x86-bare-metal-examples
不幸的是,我没有耐心制作用户空间示例,但我确实进行了分页设置,因此用户空间应该是可行的。我很想看到一个拉取请求。
或者,Linux 内核模块在 ring 0 中运行,因此您可以使用它们来尝试特权操作,例如读取控制寄存器:如何从程序访问控制寄存器 cr0、cr2、cr3?获取分段错误
这是一个方便的 QEMU + Buildroot 设置,可以在不杀死主机的情况下进行尝试。
内核模块的缺点是其他 kthread 正在运行,可能会干扰您的实验。但理论上你可以用你的内核模块接管所有的中断处理程序并拥有系统,这实际上是一个有趣的项目。
负环
虽然 Intel 手册中实际上并未引用负环,但实际上有 CPU 模式比环 0 本身具有更多功能,因此非常适合“负环”名称。
一个例子是虚拟化中使用的管理程序模式。
有关更多详细信息,请参阅:
手臂
在 ARM 中,环被称为异常级别,但主要思想保持不变。
ARMv8 中存在 4 个异常级别,通常用作:
EL0:用户空间
EL1:内核(ARM 术语中的“主管”)。
与svc
指令(SuperVisor Call)一起输入,以前称为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
Run Code Online (Sandbox Code Playgroud)
在 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
Run Code Online (Sandbox Code Playgroud)
这是一个具体的裸机示例,它注册 SVC 处理程序并执行 SVC 调用。
随hvc
指令输入(HyperVisor 调用)。
管理程序之于操作系统,就像操作系统之于用户空间。
例如,Xen 允许您在同一系统上同时运行多个操作系统,例如 Linux 或 Windows,并且为了安全和易于调试,它将操作系统彼此隔离,就像 Linux 对用户程序所做的那样。
管理程序是当今云基础架构的关键部分:它们允许多个服务器在单个硬件上运行,使硬件使用率始终接近 100% 并节省大量资金。
例如,AWS 一直使用 Xen,直到 2017 年它转向 KVM 成为新闻。
EL3:又一个层次。待办事项示例。
随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 power up 时输入 el1
在 Ubuntu 18.10 上测试的代码片段。
小智 9
运行Windows的计算机中的处理器有两种不同的模式:用户模式和内核模式.处理器根据处理器上运行的代码类型在两种模式之间切换.应用程序以用户模式运行,核心操作系统组件以内核模式运行.虽然许多驱动程序以内核模式运行,但某些驱动程序可能以用户模式运行
启动用户模式应用程序时,Windows会为应用程序创建一个进程.该过程为应用程序提供私有虚拟地址空间和私有句柄表.由于应用程序的虚拟地址空间是私有的,因此一个应用程序无法更改属于另一个应用程序的数据.每个应用程序都是独立运行的,如果应用程序崩溃,则崩溃仅限于该应用程序.其他应用程序和操作系统不受崩溃的影响.
除了私有之外,用户模式应用程序的虚拟地址空间也是有限的.以用户模式运行的处理器无法访问为操作系统保留的虚拟地址.限制用户模式应用程序的虚拟地址空间可防止应用程序更改并可能损坏关键操作系统数据.
在内核模式下运行的所有代码共享一个虚拟地址空间.这意味着内核模式驱动程序不会与其他驱动程序和操作系统本身隔离.如果内核模式驱动程序意外写入错误的虚拟地址,则属于操作系统或其他驱动程序的数据可能会受到危害.如果内核模式驱动程序崩溃,整个操作系统崩溃.
如果您是Windows用户,请通过此链接获得更多信息.
我打算在黑暗中捅一下,猜猜你在谈论Windows.简而言之,内核模式可以完全访问硬件,但用户模式则没有.例如,许多(如果不是大多数)设备驱动程序是以内核模式编写的,因为它们需要控制其硬件的更精细细节.
另见这个wikibook.
归档时间: |
|
查看次数: |
179761 次 |
最近记录: |