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

本文涉及的产品
公网NAT网关,每月750个小时 15CU
简介: 本节书摘来自华章计算机《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,成为名副其实的进程。

相关实践学习
高可用应用架构
欢迎来到“高可用应用架构”课程,本课程是“弹性计算Clouder系列认证“中的阶段四课程。本课程重点向您阐述了云服务器ECS的高可用部署方案,包含了弹性公网IP和负载均衡的概念及操作,通过本课程的学习您将了解在平时工作中,如何利用负载均衡和多台云服务器组建高可用应用架构,并通过弹性公网IP的方式对外提供稳定的互联网接入,使得您的网站更加稳定的同时可以接受更多人访问,掌握在阿里云上构建企业级大流量网站场景的方法。 学习完本课程后,您将能够: 理解高可用架构的含义并掌握基本实现方法 理解弹性公网IP的概念、功能以及应用场景 理解负载均衡的概念、功能以及应用场景 掌握网站高并发时如何处理的基本思路 完成多台Web服务器的负载均衡,从而实现高可用、高并发流量架构
相关文章
|
8天前
|
Linux C语言
Linux内核队列queue.h
Linux内核队列queue.h
|
12天前
|
存储 安全 数据管理
探索Linux的挂载操作🌈
在Linux这个强大的操作系统中,挂载操作是一个基本而重要的概念。它涉及到文件系统、设备和数据访问,对于理解Linux的工作方式至关重要。那么,挂载操作究竟是什么,为什么我们需要它,如果没有它,我们将面临什么问题呢?让我们一起深入探讨。
探索Linux的挂载操作🌈
|
21天前
|
Linux Windows
Linux之基本指令操作
Linux之基本指令操作
|
19天前
|
资源调度 监控 算法
深入理解操作系统:进程管理与调度策略
本文旨在探讨操作系统中进程管理的核心概念及其实现机制,特别是进程调度策略对系统性能的影响。通过分析不同类型操作系统的进程调度算法,我们能够了解这些策略如何平衡响应时间、吞吐量和公平性等关键指标。文章首先介绍进程的基本概念和状态转换,随后深入讨论各种调度策略,如先来先服务(FCFS)、短作业优先(SJF)、轮转(RR)以及多级反馈队列(MLQ)。最后,文章将评估现代操作系统在面对多核处理器和虚拟化技术时,进程调度策略的创新趋势。
|
6天前
|
算法 Linux 调度
深度解析:Linux内核的进程调度机制
【4月更文挑战第12天】 在多任务操作系统如Linux中,进程调度机制是系统的核心组成部分之一,它决定了处理器资源如何分配给多个竞争的进程。本文深入探讨了Linux内核中的进程调度策略和相关算法,包括其设计哲学、实现原理及对系统性能的影响。通过分析进程调度器的工作原理,我们能够理解操作系统如何平衡效率、公平性和响应性,进而优化系统表现和用户体验。
15 3
|
10天前
|
算法 Linux 调度
深入理解操作系统的进程调度策略
【4月更文挑战第8天】本文深入剖析了操作系统中的关键组成部分——进程调度策略。首先,我们定义了进程调度并解释了其在资源分配和系统性能中的作用。接着,探讨了几种经典的调度算法,包括先来先服务(FCFS)、短作业优先(SJF)以及多级反馈队列(MLQ)。通过比较这些算法的优缺点,本文揭示了它们在现实世界操作系统中的应用与局限性。最后,文章指出了未来进程调度策略可能的发展方向,特别是针对多核处理器和云计算环境的适应性。
|
11天前
|
监控 Linux Shell
初识Linux下进程2
初识Linux下进程2
|
11天前
|
算法 调度 UED
深入理解操作系统中的进程调度策略
【4月更文挑战第7天】 在多任务操作系统中,进程调度策略是决定系统性能和响应速度的关键因素之一。本文将探讨现代操作系统中常用的进程调度算法,包括先来先服务、短作业优先、轮转调度以及多级反馈队列等。通过比较各自的优势与局限性,我们旨在为读者提供一个全面的视角,以理解如何根据不同场景选择合适的调度策略,从而优化系统资源分配和提升用户体验。
|
11天前
|
Linux 编译器 Windows
【Linux】10. 进程地址空间
【Linux】10. 进程地址空间
19 4
|
13天前
|
负载均衡 算法 Linux
深度解析:Linux内核调度器的演变与优化策略
【4月更文挑战第5天】 在本文中,我们将深入探讨Linux操作系统的核心组成部分——内核调度器。文章将首先回顾Linux内核调度器的发展历程,从早期的简单轮转调度(Round Robin)到现代的完全公平调度器(Completely Fair Scheduler, CFS)。接着,分析当前CFS面临的挑战以及社区提出的各种优化方案,最后提出未来可能的发展趋势和研究方向。通过本文,读者将对Linux调度器的原理、实现及其优化有一个全面的认识。