3.2.5 宙之CPU的时分复用

news2024/9/29 11:23:04
 点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客
3.2.5.1 __primary_switched开始构建0号进程

        宙者,古往今来,时间为宙。盘古为了开天辟地,必须分开空间和时间。在时间维度,要对CPU的运行时间进行切分,即基于进程调度的时分复用。

        内核要支持多任务运行,本质上就是多个任务分享CPU的时间,轮流上阵占用CPU。接下来内核从__primary_switched开始构建0号进程。为了抓住核心,对其进行精简:     

__primary_switched:				
	adrp	x4, init_thread_union		
	add	sp, x4, #THREAD_SIZE		
	adr_l	x5, init_task		
	msr	sp_el0, x5	// Save thread_info	
				
	adr_l	x8, vectors	// load VBAR_EL0 with virtual	
	msr	vbar_el1, x8	// vector table address	
	isb			
				
	stp	xzr, x30, [sp, #-16]!		
	mov	x29, sp		
				
	add	sp, sp, #16		
	mov	x29, #0		
	mov	x30, #0		
	b	start_kernel		
ENDPROC(__primary_switched)				
3.2.5.2 0号进程内核栈的构建

        第2~3行,是内核从头开始后,第一次进行栈的初始化,让SP_EL1指向内核栈的栈底(内核栈高地址)。0号进程是内核进程,没有用户态,它只有内核栈。它的内核栈是静态定义的变量init_thread_union,类型是union thread_union。

include/linux/sched/task.h:
extern union thread_union init_thread_union;

include/linux/sched.h:
union thread_union {
#ifndef CONFIG_ARCH_TASK_STRUCT_ON_STACK // ia64架构,可忽略
	struct task_struct task;
#endif
#ifndef CONFIG_THREAD_INFO_IN_TASK //默认配置为y
	struct thread_info thread_info;
#endif
	unsigned long stack[THREAD_SIZE/sizeof(long)];
};

arch/arm64/include/asm/memory.h:
#define THREAD_SIZE		(UL(1) << THREAD_SHIFT)

        CONFIG_ARCH_TASK_STRUCT_ON_STACK仅针对ia64架构,可以忽略。

        CONFIG_THREAD_INFO_IN_TASK在ARM64默认配置为yes,所以thread_info会放置在task_struct结构中。

        最终,union thread_union里面最需要关注的是unsigned long stack[]数组,这个数组的大小为THREAD_SIZE字节,通常为4KB或16KB字节,取决于THREAD_SHIFT。

        总之第2~3行执行完毕,内核栈如下图:

        第11行,进行压栈操作,在栈中FP的位置压入0,在栈中LR中的位置压入X30。第12行,X29(FP寄存器)指向SP_EL1。在第12~14行之间精简了代码,实际上可能会调用kasan_early_init和kaslr_early_init函数。

第14~16行,让SP_EL1重新指向栈底(高地址)。如下就是跳转到start_kernel前内核栈的样子:

3.2.5.3 0号进程的task_struct结构

        第4~5行代码,让SP_EL0指向0号进程的task_struct结构体变量init_task。它定义在init/init_task.c。为了方便分析,只留下感兴趣的初始化部分:

struct task_struct init_task
= {
#ifdef CONFIG_THREAD_INFO_IN_TASK
	.thread_info	= INIT_THREAD_INFO(init_task),
	.stack_refcount	= ATOMIC_INIT(1),
#endif
……
	.stack		= init_stack,
……
	.mm		= NULL,
	.active_mm	= &init_mm,
……
	.comm		= INIT_TASK_COMM,
……
};
EXPORT_SYMBOL(init_task);

        首先看.comm字段,它代表0号进程的名字,叫做“swapper”。”comm”应该是command name的缩写。

        include/linux/init_task.h: #define INIT_TASK_COMM "swapper"

        其次看.stack字段,它代表了进程的栈。按照理解,它应该指向上一章节分析的init_thread_union,为什么这里是指向init_stack?最终在include/asm-generic/vmlinux.lds.h找到玄机:init_thread_union的链接地址之后,紧接着是符号init_stack,所以init_stack的值刚好是init_thread_union的高地址即0号进程内核栈的栈底。

节选自include/asm-generic/vmlinux.lds.h:

3.2.5.4 0号进程的内存空间

        struct task_struct init_task中的成员.mm和.active_mm怎么理解?        正解在Documentation/vm/active_mm.rst中,好处见memory management - current->mm gives NULL in linux kernel - Stack Overflow。

        在这里,只要知道如下结论即可:内核进程的mm成员总是为NULL,它运行的时候总是使用active_mm。0号进程的active_mm指向init_mm,定义在mm/init-mm.c。这里特别关注成员.pgd,它指向就是内核镜像页表swapper_pg_dir

struct mm_struct init_mm = {
	.mm_rb		= RB_ROOT,
	.pgd		= swapper_pg_dir,
	.mm_users	= ATOMIC_INIT(2),
	.mm_count	= ATOMIC_INIT(1),
	.mmap_sem	= __RWSEM_INITIALIZER(init_mm.mmap_sem),
	.page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
	.arg_lock	=  __SPIN_LOCK_UNLOCKED(init_mm.arg_lock),
	.mmlist		= LIST_HEAD_INIT(init_mm.mmlist),
	.user_ns	= &init_user_ns,
	.cpu_bitmap	= { [BITS_TO_LONGS(NR_CPUS)] = 0},
	INIT_MM_CONTEXT(init_mm)
};
3.2.5.5 进程调度的起搏器异常向量表

        中断截止到目前都是关闭的,这里只是加载异常向量表。关于异常的具体分析,详见第二章。

adr_l	x8, vectors			// load VBAR_EL1 with virtual
msr	vbar_el1, x8			// vector table address

        为什么说异常是进程调度的起搏器?

  • 只有异常打开的情况下,时钟中断才能开始运行,时间才开始流动,才能对进程的运行时间进行计量,对进程是否需要切换做出判断并标记。
  • Linux在中断和系统调用返回时,才会真正执行进程切换。

        中断真正开启的时机,是在接下来的start_kernel中。详见下文分解。

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2066609.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

netty编程之自定义编解码器

写在前面 源码 。 本文看下netty如何自定义编解码器。为此netty专门定义抽象类io.netty.handler.codec.MessageToByteEncoder和io.netty.handler.codec.ByteToMessageDecoder,后续我们实现自定义的编解码器就继承这两个类来做。 1&#xff1a;正戏 server 启动类&#xff1a…

卖一辆亏6万搞倾销,极越汽车高管掀了小米汽车遮羞布?

"炮轰解决不了极越销量问题" 作者 | 魏 强 编辑 | 卢旭成 8月22日早9点40分&#xff0c;极越汽车公关负责人徐继业发朋友圈炮轰小米汽车创始人雷军&#xff1a;“雷军这样的企业家&#xff0c;有点公德心和羞耻心好不好&#xff1f;每台车亏6万&#xff0c;亏那么…

Springboot中的mapper与entity难以觉察的匹配问题,困扰我几天时间,形成很大的压力!

最近&#xff0c;应好友邀请&#xff0c;替她做了一个心理疗愈项目的小系统&#xff0c;在编制后台API代码时&#xff0c;遇到了一个不易觉察的问题&#xff0c;终于查找出来&#xff0c;并且解决了&#xff0c;现奉献出来&#xff0c;供大家碰到类似问题&#xff0c;进行参考。…

面试题详解

前言&#xff1a;这一期我们专门来巩固所学知识&#xff0c;同时见识一些面试题。对知识做出一个总结。 1 不创建临时变量交换两个整数 . 第一种方法 #include<stdio.h> int main() {int a 0;int b 0;scanf("%d %d", &a, &b);printf("交换前…

中央空调安装8个标准流程指南

1、内机安装施工队进场第一步就是吊装内机&#xff0c;这里只要注意2个点就可以避免后续问题。 ① 内机离房顶距离不得小于1公分&#xff0c;避免机器运行时与墙顶产生共振。② 内机吊装需考虑百分之一的坡度&#xff0c;接冷凝水的一侧要稍微低一些&#xff0c;避免冷凝水排不…

单个像素的威胁:微小的变化如何欺骗深度学习系统

深度学习&#xff08;DL&#xff09;是人工智能&#xff08;AI&#xff09;的基本组成部分。它的目标是使机器能够执行需要决策机制的任务&#xff0c;这些决策机制往往近似于人类推理。深度学习模型是许多先进应用的核心&#xff0c;例如医疗诊断和自动驾驶汽车。不幸的是&…

饿了么后端登录模块

一、回顾 高并发集群 饿了么后端的登录模块 1、数据库 1. 主从复制(高可用) 2. 传统的主从复制 3. gtids事务型的主从复制 4. 注意 1. server_id唯一 2. 8.x版本需要get_ssl_pub_key 3. 5.x不需要 4. change master to 5. stop | start slave 5. 非交互 import pymy…

uniapp 地图map画出地市轮廓

最近做uniapp项目 H5微信小程序&#xff0c;需要在地图中打点并把相对应的区域轮廓给画出来。 首先查看uniapp官方文档&#xff1a;https://uniapp.dcloud.net.cn/component/map.html 想在uniapp中使用map直接写map标签即可 <view class"page-section page-section-…

CSS实现鼠标hover展开菜单

效果图&#xff1a; HTML源码&#xff1a; 背景图地址需要更改 <!-- 软件介绍 --> <div class"software-box"><div class"software-container"><div class"software-title"><h2>&ldquo; 一个软件搞定所有 &am…

创客匠人老蒋在「IP私域发售六脉神剑落地班」现场金句频出

破认知&#xff0c;提新知&#xff0c;老蒋的观点&#xff0c;再一次带你穿越周期 2024&#xff0c;变革不断&#xff0c;知识服务行业到底该怎么做&#xff1f;「IP私域发售六脉神剑落地班」现场&#xff0c;老蒋作为大课导师&#xff0c;再一次为大家带来了新鲜且颠覆的行业知…

基于SpringBoot的在线笔记网站的设计与实现

目录 项目技术和环境 页面展示 登录注册 管理员页面 用户页面 在线网址 源代码 本系统由十大核心模块构成&#xff0c;包括用户登录与注册模块、个人中心模块、笔记分类与笔记管理模块、笔记详情展示模块、分享协作与收藏管理模块、回收站与用户管理模块&#xff0c;以及…

CoppeliaSim(V-Rep)与ROS1、ROS2接口变迁-2024-

Webots&#xff1a;Webots与ROS1、ROS2接口变迁 Gazebo&#xff1a;Gazebo与ROS1、ROS2接口变迁 ROS1 2016&#xff1a;ROS_Kinetic_18 使用V-Rep3.3.1和Matlab2015b&#xff08;vrep_ros_bridge&#xff09;续 vrep_ros_bridge 插件 一、项目背景与目标 vrep_ros_bridge 是…

[数据集][目标检测]光伏发电板红外图像鸟粪检测数据集VOC+YOLO格式173张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;173 标注数量(xml文件个数)&#xff1a;173 标注数量(txt文件个数)&#xff1a;173 标注类别…

Windows—RAW编程

客服端骨架&#xff1a; #include <iostream> #include <WinSock2.h> #pragma comment(lib,"ws2_32.lib")int main() {WORD wVersionRequested MAKEWORD(2, 2);WSADATA lpWSAData;WSAStartup(wVersionRequested, &lpWSAData);SOCKADDR_IN saddr{ …

如何在没有密码的情况下解锁iPhone?

如果您的 iPhone 被锁定&#xff0c;知道如何在没有密码的情况下解锁它会派上用场。有几种方法可以帮助您重新使用无价的小工具&#xff0c;无论您是忘记了密码&#xff0c;还是现在只想使用手机。这篇博客文章将讨论在 iPhone 上设置密码的价值、忘记密码的典型原因以及在没有…

什么是DDOS攻击?DDOS攻击一小时多少钱?DDOS攻击如何防御?

什么是DDOS攻击? 拒绝服务攻击&#xff08;DDOS&#xff09;亦称洪水攻击&#xff0c;是一种网络攻击手法&#xff0c;其目的在于使目标计算机的网络或系统资源耗尽&#xff0c;使服务暂时中断或停止&#xff0c;导致其正常用户无法访问。当黑客使用网络上两个或以上被攻陷的计…

AWK的高级用法、三剑客总结

1、定义引用变量 -v:声明变量 案例一: 将系统的变量a,在awk里赋值为变量b,然后调用变量b -v 选项将其传递给 awk直接调用的话需要先用双引号再用单引号awk直接定义变量并引用调用函数getline,读取一行数据的时候并不是得到当前行而是当前行的下一行打印整个行面下面含有ro…

mp4怎么转换成mp3?看了就会的8种mp4转mp3方法!

mp4怎么转换成mp3&#xff1f;MP4作为广泛应用的视频格式&#xff0c;在日常娱乐与工作中扮演着重要角色&#xff0c;但它在特定情境下也带来了一些不便&#xff0c;你是否曾遇到过这样的困扰&#xff0c;当视频内容中的画面并非焦点&#xff0c;而你只对其中的音频感兴趣时&am…

鸿蒙Harmony编程开发:服务端证书锁定防范中间人攻击示例

1. TLS通讯中间人攻击及防范简介 TLS安全通讯的基础是基于对操作系统或者浏览器根证书的信任&#xff0c;如果CA证书签发机构被入侵&#xff0c;或者设备内置证书被篡改&#xff0c;都会导致TLS握手环节面临中间人攻击的风险。其实&#xff0c;这种风险被善意利用的情况还是很…

EasyCVR视频汇聚技术赋能智慧煤矿:车载设备接入方案助力实时监控与远程监管

在煤矿行业&#xff0c;智慧化转型已成为提升生产效率、保障安全的重要途径。随着物联网、大数据、云计算等技术的快速发展&#xff0c;智慧煤矿建设逐步深入&#xff0c;车载设备作为煤矿生产的重要一环&#xff0c;其接入智慧管理系统显得尤为重要。本文将详细介绍智慧煤矿车…