Operating system 在操作系统的上下文中,环0和环3是什么?
我一直在学习Windows中驱动程序开发的基础知识,我一直在寻找术语环0和环3。这些是指什么?它们是否与内核模式和用户模式相同?英特尔处理器(x86和其他处理器)允许应用程序使用有限的电源。为了限制(保护)关键资源,如IO、内存、端口等,与操作系统(本例中为Windows)联系的CPU提供特权级别(0为最高特权,3为最低特权),分别映射到内核模式和用户模式 因此,操作系统运行环0中的内核代码——由CPU提供的最高特权级别(0)——以及环3中的用户代码Operating system 在操作系统的上下文中,环0和环3是什么?,operating-system,driver,Operating System,Driver,我一直在学习Windows中驱动程序开发的基础知识,我一直在寻找术语环0和环3。这些是指什么?它们是否与内核模式和用户模式相同?英特尔处理器(x86和其他处理器)允许应用程序使用有限的电源。为了限制(保护)关键资源,如IO、内存、端口等,与操作系统(本例中为Windows)联系的CPU提供特权级别(0为最高特权,3为最低特权),分别映射到内核模式和用户模式 因此,操作系统运行环0中的内核代码——由CPU提供的最高特权级别(0)——以及环3中的用户代码 有关更多详细信息,请参阅Linux x86环
有关更多详细信息,请参阅Linux x86环使用概述 了解环在Linux中的使用方式将使您对它们的设计目的有一个很好的了解 在x86保护模式下,CPU始终处于4个环中的一个环中。Linux内核仅使用0和3:
- 0表示内核
- 3为用户提供
- 全局描述符表:GDT项的内存表,每个项都有一个字段
,用于对环进行编码 LGDT指令将地址设置为当前描述符表 另见:Privl
- 段寄存器CS、DS等,它们指向GDT中某个条目的索引
例如,
意味着GDT的第一个条目当前对于正在执行的代码是活动的CS=0
- 环0可以做任何事情
- 环3不能运行多条指令并写入多个寄存器,最明显的是:
- 不能改变自己的戒指!否则,它会将自身设置为环0,环将无效 换言之,无法修改电流,这决定了当前环
- 无法修改页面表: 换句话说,不能修改CR3寄存器,而分页本身阻止了对页表的修改 出于安全/易于编程的原因,这会防止一个进程看到其他进程的内存
- 无法注册中断处理程序。这些都是通过写入内存位置来配置的,这也是通过分页来阻止的 处理程序在环0中运行,将破坏安全模型 换句话说,不能使用LGDT和LIDT指令
- 无法执行输入/输出指令,如
和输入
,因此具有任意硬件访问 否则,例如,如果任何程序都可以直接从磁盘读取,则文件权限将毫无用处 更确切地说,这要归功于:操作系统实际上可以在环3上允许IO指令,这实际上是由控制的 不可能的是,如果环3一开始没有它,它就允许自己这样做 Linux总是不允许它。另见:输出
- 当CPU打开时,它开始运行环0中的初始程序(这是一种很好的近似值)。您可以将此初始程序视为内核(但通常是)
- 当userland进程希望内核为其执行某些操作(如写入文件)时,它使用一条生成中断的指令(如向内核发送信号)。x86-64 Linux系统调用hello world示例:
as-o hello\u world.o hello\u world.S
ld-o hello_world.out hello_world.o
/您好,我们的世界
当这种情况发生时,CPU调用内核在引导时注册的中断回调处理程序。这是一本书
此处理程序在环0中运行,它决定内核是否允许此操作,执行该操作,并在环3中重新启动userland程序。x86_64
- 当使用
系统调用(或内核)时,新userland进程的内核将跳转到入口点,并将CPU切换到环3exec
- 如果程序试图做一些顽皮的事情,比如写入禁止的寄存器或内存地址(因为分页),CPU还会调用环0中的某个内核回调处理程序 但是,由于userland是顽皮的,内核这次可能会终止进程,或者给它一个带有信号的警告
- 当内核启动时,它设置一个固定频率的硬件时钟,该时钟周期性地产生中断 此硬件时钟生成运行环0的中断,并允许它计划唤醒哪些userland进程 这样,即使进程没有进行任何系统调用,也可以进行调度
- 制作程序更容易,因为您更确定其中一个不会干扰另一个。例如,一个userland进程不必担心由于分页而覆盖另一个程序的内存,也不必担心将另一个进程的硬件置于无效状态
- 它更安全。例如,文件权限和内存分离可防止黑客应用程序读取您的银行数据。当然,这假设您信任内核
.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
.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
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