《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》——2.14 进程0由0特权级翻转到3特权级,成为真正的进程

简介: 本节书摘来自华章计算机《Linux内核设计的艺术:图解Linux操作系统架构设计与实现原理》一书中的第2章,第2.14节,作者:新设计团队著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

2.14 进程0由0特权级翻转到3特权级,成为真正的进程

Linux操作系统规定,除进程0之外,所有进程都要由一个已有进程在3特权级下创建。在Linux 0.11中,进程0的代码和数据都是由操作系统的设计者写在内核代码、数据区,并且,此前处在0特权级,严格说还不是真正意义上的进程。为了遵守规则,在进程0正式创建进程1之前,要将进程0由0特权级转变为3特权级。方法是调用move_to_user_mode()函数,模仿中断返回动作,实现进程0的特权级从0转变为3。
执行代码如下:

//代码路径:init/main.c:
void main(void)
{
    …
    move_to_user_mode();
    …
}

//代码路径:include/system.h:    //参看1.3.4节
#define move_to_user_mode() \    //模仿中断硬件压栈,顺序是ss、esp、eflags、cs、eip
__asm__("movl %%esp,%%eax\n\t" \    
         "pushl $0x17\n\t" \    //SS进栈,0x17即二进制的10111(3特权级、LDT、数据段)
         "pushl %%eax\n\t" \     //ESP进栈
         "pushfl\n\t" \        //EFLAGS进栈    
         "pushl $0x0f\n\t" \    //CS进栈,0x0f即1111(3特权级、LDT、代码段)
         "pushl $1f\n\t" \    //EIP进栈
         "iret\n" \        //出栈恢复现场、翻转特权级从0到3
         "1:\tmovl $0x17,%%eax\n\t" \    //下面的代码使ds、es、fs、gs与ss一致
               "movw %%ax,%%ds\n\t" \
               "movw %%ax,%%es\n\t" \
               "movw %%ax,%%fs\n\t" \
               "movw %%ax,%%gs" \
            :::»ax»)

IA-32体系结构翻转特权级的方法之一是用中断。第1章介绍过,当CPU接到中断请求时,能中断当前程序的执行序,将CS:EIP切换到相应的中断服务程序去执行,执行完毕又执行iret指令返回被中断的程序继续执行。
这期间,CPU硬件还做了两件事:一件是硬件保护现场和恢复现场,另一件是可以翻转特权级。
从代码的执行序上看,中断类似函数调用,都是从一段正在执行的代码跳转到另一段代码执行,执行之后返回原来的那段代码继续执行。为了保证执行完函数或中断服务程序的代码之后能准确返回原来的代码继续执行,需要在跳转到函数或中断服务程序代码之前,将起跳点的下一行代码的CS、EIP的值压栈保存,保护现场。函数或中断服务程序的代码执行完毕,再将栈中保存的值出栈给CS、EIP,此时的CS、EIP指向的就是起跳点的下一行,恢复现场。所以,CPU能准确地执行主调程序或被中断的程序。实际需要保护的寄存器还有EFLAGS等。
中断与函数调用不同的是,函数调用是程序员事先设计好的,知道在代码的哪个地方调用,编译器可以预先编译出压栈保护现场和出栈恢复现场的代码;而中断的发生是不可预见的,无法预先编译出保护、恢复的代码,只好由硬件完成保护、恢复的压栈、出栈动作。所以,int指令会引发CPU硬件完成SS、ESP、EFLAGS、CS、EIP的值按序进栈,同理,CPU执行iret指令会将栈中的值自动按反序恢复给这5个寄存器。
CPU响应中断的时候,根据DPL的设置,可以实现指定的特权级之间的翻转。前面的sched_init函数中的set_system_gate(0x80,&system_call)就是设置的int 0x80中断由3特权级翻转到0特权级,3特权级的进程做了系统调用int 0x80,CPU就会翻转到0特权级执行系统代码。同理,iret又会从0特权级的系统代码翻转回3特权级执行进程代码。
move_to_user_mode()函数就是根据这个原理,利用iret实现从0特权级翻转到3特权级。
由于进程0的代码到现在一直处在0特权级,并不是从3特权级通过int翻转到0特权级的,栈中并没有int自动压栈的5个寄存器的值。为了iret的正确使用,设计者手工写压栈代码模拟int的压栈,当执行iret指令时,CPU自动将这5个寄存器的值按序恢复给CPU,CPU就会翻转到3特权级的段,执行3特权级的进程代码。
为了iret能翻转到3特权级,不仅手工模拟的压栈顺序必须正确,而且SS、CS的特权级还必须正确。注意:栈中的SS值是0x17,用二进制表示就是00010111,最后两位表示3,是用户特权级,倒数第3位是1,表示从LDT中获取段描述符,第4~5位的10表示从LDT的第3项中得到进程栈段的描述符。
当执行iret时,硬件会按序将5个push压栈的数据分别出栈给SS、ESP、EFLAGS、CS、EIP。压栈顺序与通常中断返回时硬件的出栈动作一样,返回的效果也是一样的。
执行完move_to_user_mode( ),相当于进行了一次中断返回,进程0的特权级从0翻转为3,成为名副其实的进程。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
相关文章
|
7月前
|
安全 网络协议 Linux
深入理解Linux内核模块:加载机制、参数传递与实战开发
本文深入解析了Linux内核模块的加载机制、参数传递方式及实战开发技巧。内容涵盖模块基础概念、加载与卸载流程、生命周期管理、参数配置方法,并通过“Hello World”模块和字符设备驱动实例,带领读者逐步掌握模块开发技能。同时,介绍了调试手段、常见问题排查、开发规范及高级特性,如内核线程、模块间通信与性能优化策略。适合希望深入理解Linux内核机制、提升系统编程能力的技术人员阅读与实践。
679 1
|
7月前
|
Ubuntu Linux
Ubuntu 23.04 用上 Linux 6.2 内核,预计下放到 22.04 LTS 版本
Linux 6.2 带来了多项内容更新,修复了 AMD 锐龙处理器设备在启用 fTPM 后的运行卡顿问题,还增强了文件系统。
|
7月前
|
Ubuntu Linux
Ubuntu 23.10 现在由Linux内核6.3提供支持
如果你想在你的个人电脑上测试一下Ubuntu 23.10的最新开发快照,你可以从官方下载服务器下载最新的每日构建ISO。然而,请记住,这是一个预发布版本,所以不要在生产机器上使用或安装它。
|
7月前
|
传感器 监控 Ubuntu
10 月发布,Ubuntu 23.10 已升级到 Linux Kernel 6.3 内核
硬件方面,Linux 6.3 引入了在 HID 中引入了原生的 Steam Deck 控制器接口,允许罗技 G923 Xbox 版赛车方向盘在 Linux 上运行;改善 8BitDo Pro 2 有线控制器的行为;并为一系列华硕 Ryzen 主板添加传感器监控。
|
7月前
|
Ubuntu Linux
Ubuntu24.04LTS默认采用Linux 6.8内核,实验性版本可通过PPA获得
IT之家提醒,当下的 Ubuntu 23.10 也是一个“短期支持版本”,该版本将在今年 7 月终止支持,而今年 4 月推出的 Ubuntu 24.04 LTS 长期支持版本将获得 5 年的更新支持。
|
7月前
|
监控 Ubuntu Linux
什么Linux,Linux内核及Linux操作系统
上面只是简单的介绍了一下Linux操作系统的几个核心组件,其实Linux的整体架构要复杂的多。单纯从Linux内核的角度,它要管理CPU、内存、网卡、硬盘和输入输出等设备,因此内核本身分为进程调度,内存管理,虚拟文件系统,网络接口等4个核心子系统。
457 0
|
7月前
|
Web App开发 缓存 Rust
|
7月前
|
Ubuntu 安全 Linux
Ubuntu 发行版更新 Linux 内核,修复 17 个安全漏洞
本地攻击者可以利用上述漏洞,攻击 Ubuntu 22.10、Ubuntu 22.04、Ubuntu 20.04 LTS 发行版,导致拒绝服务(系统崩溃)或执行任意代码。
|
7月前
|
Ubuntu 机器人 物联网
Linux Ubuntu 22.04 LTS 测试版实时内核已可申请
请注意,在启用实时内核后您需要手动配置 grub 以恢复到原始内核。更多内容请参考:

热门文章

最新文章