UEFI 多任务

news2024/12/26 1:18:29

一般而言,UEFI 的主要作用是检测和初始化设备,加载操作系统的引导程序,然后将控制权交给操作系统,整个过程不需要大量的运算,在单个 CPU 核上运行单线程程序已经可以满足需求,因此,EDK2 没有提供多线程机制。

如果需要在 UEFI 应用中支持多任务,则可以使用 EFI_MP_SERVICES_PROTOCOL启动从 CPU,也可以自己实现一个多线程库,在每个CPU上运行并发任务。

多处理器服务

在多处理器系统中,系统初始化时,总是由一个处理器执行这些初始化指令,这个 CPU 称为 BSP ( Boot-Strap Processor )。系统中 BSP 之外的 CPU 称为 AP ( Application Processor )

EFI_MP_SERVICES_PROTOCOL 功能及用法

PI (Platform Initalization) 标准中定义了 EFI_MP_SERVICES_PROTOCOL (简称 MP 服务),这个 Protocol 用于在多处理器系统中管理处理器,包括查询处理器信息、启动或停止AP、设定 BSP,
在这里插入图片描述

除了 WhoAmI 服务外,EFI_MP_SERVICES_PROTOCOL 中的其他服务都只能在 BSP 上调用,在 AP上调用这些服务时会返回EFI_DEVICE_ERROR错误。

1.查询服务

EFI_MP_SERVICES_PROTOCOL提供的查询服务有三个:

GetNumberOfProcessors	// 用于查询系统中的逻辑处理器个数,以及启用的逻辑处理器
GetProcessorInfo		// 用于获取指定处理器的相关信息
WhoAmI					// 用于获取当前处理器的编号

GetNumberOfProcessors 服务的函数原型:

在这里插入图片描述

其功能是查询指定逻辑处理器有关多处理器的信息。此服务仅返回多处理器相关信息(如处理器编号、处理器状态等),不提供平台相关的处理器信息(如Cache 大小、处理器频率等)。

查询时通过处理器编号(参数ProcessorNumber)指定待查询的处理器。处理器编号从0开始。系统启动后,UEFI 把系统中的处理器从 0 开始编号,ProcessorNumber 就是这个编号 EFI_MP_SERVICES_PROTOCOL 中其他服务中的 ProcessorNumber 意义与之相同。如果指定的处理器编号超出系统中存在的处理器个数,则返回EFI_NOT_FOUND

在这里插入图片描述

GetProcessorInfo服务返回的处理器信息存放在EFI_PROCESSOR_INFORMATION结构体内:
在这里插入图片描述

其中,ProcessorId是由系统硬件决定的地址。对 IA32 和 x64 处理器来说,它与本地 APIC ID 地址相同,低 8 位有效。对安腾处理器来说,低 16 位地址有效。要注意 ProcessorIdProcessorNumber (处理器编号)不同。
StatusFlag 是处理器状态:
0 位是 BSP 位(PROCESSOR_AS_BSP_BIT),为 0 时说明该处理器是 AP;为 1 时说明该处理器是 BSP;
1 位是 EnabIed 位(PROCESSOR_ENABLED_BIT),0 表示该处理器被禁用;1表示该处理器被启用;
2 位是 Health 位(PROCESSOR_HEALTH_STATUS_BIT),0表示该处理器出现故障;1表示该处理器正常。
3~31位必须是 0

处理器信息还包含一个域 Location,它是 EFI_CPU_PHYSICAL_LOCATION 类型的变量,表示处理器的物理地址,用于给每一个 CPU 定位。在一个计算机系统中,可能有多颗处理器(一颗处理器称为一个 Package),每颗处理器可能有多个物理核(物理核称为 Core),每个物理核又可能有多个逻辑核(逻辑核称为Thread)。所有的编号都从0开始。

EFI_CPU_PHYSICAL_LOCATION 结构体:
在这里插入图片描述

对于一个逻辑处理器,有三种地址:
1)ProcessNumber,作为 MPService 服务的参数,假设系统中有 n 个处理器,ProcessNumber0~n-1 之间,称为处理器编号;
2)Location是由 PackageCoreThread 组成的三元组,可给一个逻辑处理器定位;
3)Processorld,由系统硬件决定的地址。

WhoAmI 用于获得当前处理器的编号 (ProcessorNumber)。
在这里插入图片描述

2.管理处理器

EFI_MP_SERVICES_PROTOCOL 中用于管理处理器的服务有以下 4 个:

  • StartupThisAP 服务用在指定的 AP上执行传入的函数;
  • StartupAIlAPS 服务用于在所有 AP 上执行传入的函数;‘
  • SwitchBSP 服务用于选定某个 AP 作为 BSP
  • EnableDisableAP 服务用于启用或禁用某个 AP

(1)StartupThisAP 服务
StartupThisAP 服务只能在 BSP上执行,用于在指定的 AP(此 AP 必须没有被禁用)上执行调用者提供的函数。调用者可以指定Timeout时间。
如果逾期时 AP 上的任务还未完成,那么 AP 上的任务将被终止;
如果 AP 未处于 IDLE 状态,那么该服务会返回 EFI_NOT_READY
如果 AP 未处于 Enable 状态,那么该服务会返回EFI_INVALID_PARAMETER
在这里插入图片描述

此服务有阻塞和异步两种模式。参数 WaitEventNULL时,该服务使用阻塞模式;否则,使用异步模式。
阻塞模式下,该服务向 AP 发出指令后,等待 AP 把调用者提供的函数执行完毕,然后该服务成功返回。若 AP 完成任务前已逾期,则逾期时服务返回 EFI_TIMEOUT
异步模式下,该服务向 AP 发出指令后立即返回。AP 执行完任务后触发该服务提供的事件 WaitEvent,并将Finished标志设为TRUE;若 AP 完成任务前已逾期,则逾期时终止 AP上的任务,触发事件 WaitEvent,并将Finished标志设为FALSE

系统事件 EFI_EVENT_GROUP_READY_TO_BOOT 被触发后,该服务仅提供阻塞模式。

(2)StartupAIlAPS
StartupAllAPs 用于在所有的 AP上执行指定的函数。如果有任何 AP 未处于 IDLE 状态,则该函数返回EFI_NOT_READY。如果参数SingleThreadTRUE,则 AP 会依次执行Procedure函数,前一 AP 从 Procedure 返回后下一 AP 才会执行Procedure。如果参数SingleThreadFALSE,则所有的 AP 同时执行 Procedure,开发者负责 Procedure 的线程安全。
StartupAIlAPS 服务有阻塞和异步两种模式。参数 WaitEventNULL时,该服务使用阻塞模式;否则,使用异步模式。

阻塞模式下,所有 AP 从 Procedure 返回或超时后,StartupAllAPs 返回。FailedCpuList 列表返回未成功执行 Procedure 的 CPU 的编号,系统为 FailedCpuList 分配内存,调用者负责释放该内存。
异步模式下,所有 AP 从 Procedure 返回或超时后,WaitEvent 事件触发,系统同样会设置 FailedCpuList 列表。

在这里插入图片描述

(3)SwitchBSP服务
SwitchBSP 用于将指定的 AP 切换为 BSP。成功切换后,该服务返回EFI_SUCCESS,新的 BSP 将无缝接管原 BSP 的工作。当系统事件EFI_EVENT_GROUP_READY_TO_BOOT触发后,该服务不再有效。
在这里插入图片描述

(4)EnableDisableAP 服务
EnableDisableAP 服务用于启动或禁用指定的 AP。
在这里插入图片描述

启动 AP 的过程

1.通过发送 IPIs 消息启动 AP

每个处理器 Core 上都有一个 APIC (Advanced Programmable Interrupt Controller) 芯片,称为本地 APIC。它接收来自本地或外部的中断信号,发送给 Core 上的处理器处理这个中断。
这些中断信号包括:来自处理器 Core 中断引脚的信号、来自 I/O APIC 的中断、来自性能监视寄存器的中断、本地 APIC 时钟中断、本地 APIC 错误中断、温度传感器中断、来自其他处理器的中断 (Inter-Processor Interrupts,简称 IPIS)

AP 的启动是通过在 BSP 上向 AP 发送特定的 IPIs 完成的,而发送 IPIs 是通过写本地 APIC 的 ICR(Interrupt Command Register)完成的。

多处理器系统启动时,首先根据 MP 初始化协议选择一个处理器为 BSP,其他处理器作为 AP。BSP 执行初始化代码,初始化系统的 APIC 环境,建立系统的全局数据结构,初始化 AP(向 AP 发送 INIT-SIPI-SIPI IPIs)。等 BSP 和 AP 初始化完成后,BSP 会执行 OS Loader 加载操作系统。

AP 重置(收到 INIT IPI 中断信号)或加电后,首先简单地进行自我配置,然后等待来自 BSP 的启动信号(来自 BSP 的 IPI),这个启动信号称为 SIPI。AP 收到 SIPI 后,会从实模式 0x000XX000 地址处开始执行。XX是 SIPI 消息中的 8bit 的地址向量。

(1)寄存器 ICR 及 IPI 类型
发送 IPI 是通过写寄存器 ICR 完成的,ICR是 64 位寄存器,可分为两个 32 位寄存器。其中低 32 位的寄存器偏移为0x300,高32位的寄存器偏移为0x310
在这里插入图片描述

可用 IPI 类型(DeliveryMode)共有7种:
0:向目的处理器发送 Vector 指定的中断。
1:同 000,但仅向目标处理器中优先级最低的处理器发送。
2:向目标处理器发送 SMI 中断,Vector 必须是 0。
4:向目标处理器发送 NMI中断,Vector被忽略。
5:向目标处理器发送 INIT 中断(称为 INITIPI),目标处理器收到 INITIPI 后进行初始化,然后等待 SIPI
6:向目标处理器发送 SIPI(startup) 中断,目标处理器收到 SIPI 后执行 Vector 指定的代码。
7:向目标处理器发送信号,目标处理器收到信号后向外部 8259A 控制器发出请求从而获得 Vector

在这里插入图片描述

(2)向目标处理器发送 IPI
发送 IPI 是通过写寄存器 ICR 实现的:
a.写 ICR 高 32 位的寄存器XAPIC_ICR_HIGH_OFFSET,该寄存器包含了目的处理器的 APCI 地址;
b.写 ICR 低 32 位的寄存器XAPIC_ICR_LOW_OFFSET,写入该寄存器后 IPI 被发送,目的 CPU 收到消息后,发送方的XAPIC_ICR_LOW_OFFSETDeliveryStatus 会设置为 0
c.检查XAPIC_ICR_LOW_OFFSETDeliveryStatus,直到该值变为 0

Sendlpi函数实现了这个流程:
在这里插入图片描述
在这里插入图片描述

(3)启动 AP 的 IPI 序列
启动 AP 是通过向 AP 发送 INIT-SIPI-SIPI 列完成的,SendInitlpi 函数用于发送 INIT IPI 消息。在 SendInitlpi 函数中,首先构造 INIT IPI 消息,然后调用 SendIpi 函数发送该消息。
在这里插入图片描述

SendInitSipiSipi 函数用于发送 INIT-SIPI-SIPI 序列,发送过程分为三步:发送 INIT IPI 消息,发送 SIPI 消息,再次发送 SIPI 消息。在 SIPI 消息中包含了 AP 启动向量 StartupRoutine。目标处理器接收 IPI 序列后 SendInitSipiSipi 函数返回。目标 AP 接收到 INIT-SIPI-SIPI IPI 序列后,从实模式物理地址 StartupRoutine 处开始执行代码。StartupRoutine 必须在 1MB 地址之内,并且必须按 4KB 对齐。
在这里插入图片描述

2.AP 启动向量

使用函数 SendInitSipiSipi(TargetCpu, mStartup Vector)启动一个 AP。AP 收到启动消息后会执行 mStartupVector

启动向量 mStartupVector是一段代码的基址,在程序中它定义为 EFI_PHYSICAL_ADDRESS 类型的变量。地址 mStartupVector 必须在1MB地址之内,并且必须按4KB对齐。

(1)BSP 首先要为启动向量mStartupVector分配内存AllocateStartupVector 函数在物理地址为0x02000~0x7F000的内存中找到可供使用的内存并分配给mStartupVector 使用。
(2)BSP 使用PrepareAPStartupVector 函数用于初始化启动向量mStartupVector。该函数首先取得启动代码的地址、大小等信息,这些信息包含在 MP_ASSEMBLY_ADDRESS_MAP类型的变量 AddressMap中。然后根据启动代码的大小调用AllocateStartupVector(…)为启动向量mStartupVector分配内存。接着将启动代码复制到mStartupVector指向的内存,并设置启动向量中的相关跳转地址,为 AP分配 GDT(全局描述符表)IDT(中断描述符表) 并存入中断向量。
(3)AsmGetAddressMap 取得启动代码地址和大小。

多线程

UEFI Spec 没有提供多线程机制,如果在开发 UEFI 应用的过程中需要多线程,那么需要用户自己实现多线程库。

编写多线程库,线程的两个核心内容:
(1)线程切换时机
切换分两种,一种是主动切换,另一种是被动切换。当某个线程需要等待某个事件的发生,如网络应用等待远程服务器响应,可以主动切换到其他线程。当线程时间片用完时,需要切换到其他线程,这是被动切换。
(2)线程切换机制
要理解线程切换机制,首先要清楚每个线程执行过程中都拥有哪些资源。每个线程拥有独立的栈,还拥有执行上下文即寄存器环境。将旧的线程切换到新的线程时,需要保存旧线程的寄存器上下文,加载新线程的寄存器上下文,在切换寄存器上下文的同时发生了栈的切换。寄存器切换使用 SetJump/LongJump 函数。

1.生成线程:分配线程所需的资源,包括线程结构体及栈,以及初始化栈及线程寄存器上下文。
2.调度线程:线程的被动调度在定时器回调函数中完成。因此,在创建线程之前要先初始化Timer。
3.等待线程结束:在主线程退出之前一定要确保其他线程已经结束,并关闭定时器事件。因为主线程结束意味着程序结束,若不关闭定时器时间,会造成系统崩溃。

《UEFI原理与编程》。。。。有些东西,等用到的时候再学吧,这里大概了解一下。。。

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

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

相关文章

人工智能与物联网:从智慧家居到智能城市的未来蓝图

引言:未来已来,智能化的世界 想象一下,一个早晨,智能闹钟根据你的睡眠状态自动调整叫醒时间,咖啡机早已备好热腾腾的咖啡,窗帘缓缓拉开,迎接清晨的阳光。这不是科幻小说中的场景,而是…

【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity

文章目录 前言**游戏引擎是什么?****游戏引擎对于我们的意义**1、**降低游戏开发的门槛**2、**提升游戏开发效率** **以前做游戏****现在做游戏****主流的游戏引擎有哪些?**Unity 相比其他游戏引擎的优势?**为什么选择Unity?**Uni…

Xcode 16 编译弹窗问题、编译通过无法,编译通过打包等问题汇总

问题1:打包的过程中不断提示 :codesign 想要访问你的钥匙串中的密钥“develop 或者distribution 证书” 解决:打开钥匙串,点击证书---显示简介---信任----改为始终信任 (记住 :不能只修改钥匙的显示简介的…

RabbitMQ中的Topic模式

在现代分布式系统中,消息队列(Message Queue)是实现异步通信、解耦系统组件的重要工具。RabbitMQ 是一个广泛使用的开源消息代理,支持多种消息传递模式,其中 Topic 模式 是一种灵活且强大的模式,允许生产者…

OpenEuler 22.03 安装 flink-1.17.2 集群

零:规划 本次计划安装三台OpenEuler 22.03 版本操作系统的服务器,用于搭建 flink 集群。这里使用flink1.17.2 的原因,是便于后续与springboot的整合 服务器名IP地址作用其他应用flink01192.168.159.133主jdk11、flink-1.17.2flink02192.168.…

国标GB28181公网直播EasyGBS与国标GB28181协议融合,助力应急救援指挥无线视频监控系统建设

随着信息技术的飞速发展,视频监控领域正经历从传统安防向智能化、网络化安防的深刻转变。在这一转变过程中,国标GB28181协议以其强大的功能和广泛的应用场景,成为了公共安全视频监控联网系统的核心标准。 应急救援指挥系统要求能够迅速响应各…

VisionPro开发使用交互反馈系统(Affordance System)

XR Interaction Toolkit 提供了一个affordance system 可供性系统,使用户能够创建对交互状态的视觉和听觉反馈。一般的信息流从向Affordance State Provider场景中添加一个(通常是可交互的)并将其指向我们要监视其交互状态的可交互对象开始。…

SpringCloud 入门(4)—— 网关

上一篇:SpringCloud 入门(3)—— Nacos配置中心-CSDN博客 Spring Cloud Gateway 作为 Spring Cloud 生态系统的一部分,主要在微服务架构中充当 API 网关的角色。它提供了统一的入口点来处理所有的 HTTP 请求,并将这些请…

在linux系统的docker中安装GitLab

一、安装GitLab: 在安装了docker之后就是下载安装GitLab了,在linux系统中输入命令:docker search gitlab就可以看到很多项目,一般安装第一个,它是英文版的,如果英文不好可以安装twang2218/gitlab-ce-zh。 …

vscode打开下一个文件的时候上一个文件会关闭

解决方法: 你可以通过设置 workbench.editor.enablePreview 来控制在 VS Code 中打开文件时是否会关闭上一个文件。将其设置为 false 可以防止这种行为。 {"workbench.editor.enablePreview": false } 在设置编辑器中显示 "workbench.editor.enab…

PostgreSQL编译安装教程

下载安装 1.在家目录创建一个文件夹放下载安装包 mkdir softwarecd software 2.下载文件压缩包 wget https://ftp.postgresql.org/pub/source/v16.0/postgresql-16.0.tar.gz 3.解压 tar -xzvf postgresql-16.0.tar.gz 4.编译 在software/postgresql-16.0下 cd software…

访谈积鼎科技总经理:国产CFD软件发展与未来趋势展望

傅彦国,上海积鼎信息科技有限公司创始人 记者:请傅总介绍下我国流体仿真行业的发展现状是怎样的? 傅彦国:自2018年政府加大了对核心技术自主研发的支持力度,国产CFD软件逐渐步入发展正轨。 首先,从市场规…

重温设计模式--代理模式

文章目录 定义UML图代理模式主要有以下几种常见类型:代理模式涉及的主要角色有:C 代码示例 定义 代理模式(Proxy Pattern)属于结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。 通过引入代理对象&am…

R语言数据分析案例46-不同区域教育情况回归分析和探索

一、研究背景 教育是社会发展的基石,对国家和地区的经济、文化以及社会进步起着至关重要的作用。在全球一体化进程加速的今天,不同区域的教育发展水平呈现出多样化的态势。这种差异不仅体现在教育资源的分配上,还表现在教育成果、教育投入与…

uni-app使用组件button遇到的问题

在HBuilder X工具中新建一个空白项目, 1、新建一个about页 然后在pages.json文件里加上路由 2、然后看下导航的方法,发现找不到navigateTo方法 参考:button | uni-app官网 第3行和第4行的代码倒是没问题的,第5行的代码有问题执行…

git自己模拟多人协作

目录 一、项目克隆 二、多人协作 1.创建林冲仓库 2.协作处理 3.冲突处理 三、分支推送协作 1.创建develop分支 2.发现git push无法把develop推送到远程 ​编辑 3.本地的分支推送到远程分支 四、分支拉取协作 五、远程分支的删除 远程仓库用的gitee 一、项目克隆 …

基于springboot+vue实现的卷烟营销统计分析系统 (源码+L文+ppt)4-129

摘 要 卷烟行业的快速发展使得卷烟营销统计分析系统成为了一个必不可少的工具。基于Java的卷烟营销统计分析系统旨在提供高效、准确和便捷的适用卷烟营销服务。本文讲述了基于java语言开发,后台数据库选择MySQL进行数据的存储。该软件的主要功能是进行卷烟营销统计…

解析CGI(通用网关接口)技术

在互联网技术飞速发展的今天,CGI(Common Gateway Interface,通用网关接口)作为一种常见的服务器端脚本技术,依然在许多老旧网站和小型网站中广泛使用。尽管如今有许多更现代的技术替代了CGI,但它仍然是理解…

OPPO C++面试题及参考答案

五层协议每层包含的协议 在计算机网络的五层协议体系结构(自下而上为物理层、数据链路层、网络层、传输层和应用层)中,各层包含多种协议。 物理层主要负责在物理介质上传输原始的比特流,包括像 RJ - 45 接口标准等物理接口规范&am…

OpenAI 普及 ChatGPT,开通热线电话,近屿智能深耕AI培训

12月19日,在OpenAI直播活动的第10天,宣布允许用户通过电话或WhatsApp与ChatGPT进行交互。并在美国推出 ChatGPT 热线电话,用户拨打后可与 ChatGPT 进行语音对话。 这项服务的一个亮点在于它兼容各种类型的通信设备——不论是现代智能手机如iP…