内核移植学习

内核移植

内核移植就是指将RT-Thread内核在不同的芯片架构、不同的板卡上运行起来。

移植可分为CPU架构移植和BSP板级支持包移植两部分。

CPU架构移植

在嵌入式领域有多种不同CPU架构,例如Cortex-M、ARM920T、MIPS32、RISC-V等等。

为了使RT-Thread能够在不同CPU架构的芯片上运行,RT-Thread提供了一个libcpu抽象层来适配不同的CPU架构。
libcpu层向上对内核提供统一的接口,包括全局中断的开关,线程栈的初始化,上下文切换等。

RT-Thread 的 libcpu 抽象层向下提供了一套统一的 CPU 架构移植接口,这部分接口包含了全局中断开关函数、线程上下文切换函数、时钟节拍的配置和中断函数、Cache 等等内容。下表是 CPU 架构移植需要实现的接口和变量。

libcpu移植相关API
在这里插入图片描述
rt_uint32_t rt_thread_switch_interrupt_flag;表示需要再中断里进行切换的标志

rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; 在线程进行上下文切换时候,用来保存 from 和 to 线程

实现全局中断开关

无论内核代码还是用户的代码,都可能存在一些变量,需要在多个线程或者中断里面使用,如果没有相应的保护机制,那就可能导致临界区问题。
RT-Thread里为了解决这个问题,提供了一系列的线程间同步和通信机制来解决。但是这些机制都需要用到libcpu里提供的全局中断开关函数。

rt_base_t rt_hw_interrupt_disbale(void);void rt_hw_interrupt_enable(rt_base_t level);

关闭全局中断

在rt_hw_interrupt_disable()函数里需要依次完成的功能是:

  1. 保存当前的全局中断状态,并把状态作为函数的返回值
  2. 关闭全局中断
rt_hw_interrupt_disable		PROCEXPORT rt_hw_interrupt_disable		MRS r0,PRIMASKCPSID IBX LRENDP

r0存储的数据就是函数的返回值。

打开全局中断

rt_hw_interrupt_enable PROCEXPORT rt_hw_interrupt_enable MSR PRIMASK,r0BX LRENDP

实现线程栈初始化

在动态创建线程和初始化线程的时候,会使用到内部的线程初始化函数_rt_thread_init(),这个函数会调用栈初始化函数rt_hw_stack_init(),在栈初始化函数里会手动构造一个上下文内容,这个上下文内容将被作为每个线程第一次执行的初始值。
在这里插入图片描述

rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, rt_uint8_t *stack_addr, void *texit)
{struct stack_frame *stack_frame;rt_uint8_t *stk;unsigned long i;/* 对传入的栈指针做对齐处理 */stk = stack_addr + sizeof(rt_uint32_t);stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);stk -= sizeof(struct stack_frame);stack_frame = (struct stack_frame *)stk;for(i=0; i<sizeof(struct stack_frame)/sizeof(rt_uint32_t); i++){((rt_uint32_t *)stack_frame)[i] = oxdeadbeef;}//将一个参数保存在r0寄存器stack_frame->exception_stack_frame.r0  = (unsigned long)parameter;/* 将剩下的参数寄存器都设置为 0 */stack_frame->exception_stack_frame.r1  = 0;                 /* r1 寄存器 */stack_frame->exception_stack_frame.r2  = 0;                 /* r2 寄存器 */stack_frame->exception_stack_frame.r3  = 0;                 /* r3 寄存器 */stack_frame->exception_stack_frame.r12 = 0;stack_frame->exception_stack_frame.lr = (unsigned long)texit;stack_frame->exception_stack_frame.pc = (unsigned long)tentry;stack_frame->exception_stack_frame.psr = 0x01000000L;//设置psr的值为这个,表示默认切换过去是Thumb模式return stk;
}

实现上下文切换

在不同的CPU架构里,线程之间的上下文切换和中断到线程的上下文切换,上下文的寄存器部分可能是有差异的,也可能是一样的。
在Cortex-M里面上下文切换都是统一使用PendSV异常来完成,切换部分并没有差异。

但是为了能适应不同的CPU架构,RT-Thread的libcpu抽象层还是需要实现三个线程切换相关的函数:
1) rt_hw_context_switch_to():没有来源线程,切换到目标线程,在调度器启动第一个线程的时候被调用。

2) rt_hw_context_switch():在线程环境下,从当前线程切换到目标线程。

3) rt_hw_context_switch_interrupt ():在中断环境下,从当前线程切换到目标线程。

在线程环境下进行切换和在中断环境进行切换是存在差异的。
线程环境下,如果调用rt_hw_context_switch()函数,那么可以马上进行上下文切换;而在中断环境下,需要等待中断处理函数完成之后才能进行切换。

由于这种差异,在 ARM9 等平台,rt_hw_context_switch() 和 rt_hw_context_switch_interrupt() 的实现并不一样。

在中断处理程序里如果触发了线程的调度,调度函数里会调用rt_hw_context_switch_interrupt()触发上下文切换。
中断处理程序里处理完中断事务之后,中断退出之前,检查flag变量,如果变量的值为1,就根据from_thread和to_thread变量,完成线程的上下文切换。

在Cortex-M处理器架构里,基于自动部分压栈和PendSV的特性,上下文切换可以实现地更加简洁。

在这里插入图片描述
硬件在进入PendSV中断之前自动保存了from线程的PSR、PC、LR、R12、R3-R0寄存器,然后PendSV里保存from线程的R4-R11寄存器,以及恢复to线程的R4-R11寄存器,最后硬件在退出 PendSV 中断之后,自动恢复 to 线程的 R0~R3、R12、LR、PC、PSR 寄存器。

中断到线程的上下文切换:
在这里插入图片描述
硬件在进入中断之前自动保存了 from 线程的 PSR、PC、LR、R12、R3-R0 寄存器,然后触发了 PendSV 异常。在 PendSV 异常处理函数里保存 from 线程的 R11~R4 寄存器,以及恢复 to 线程的 R4~R11 寄存器,最后硬件在退出 PendSV 中断之后,自动恢复 to 线程的 R0~R3、R12、PSR、PC、LR 寄存器。

显然,在Cortex-M内核里rt_hw_context_switch() 和 rt_hw_context_switch_interrupt() 功能一致,都是在 PendSV 里完成剩余上下文的保存和回复。所以我们仅仅需要实现一份代码,简化移植的工作。

实现PendSV中断

在Cortex-M3里,PendSV中断处理函数是PendSV_Handler()

在这里插入图片描述

; r0 --> switch from thread stack
; r1 --> switch to thread stack
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stackPendSV_Handler PROCEXPORT PendSV_Handler ;关闭全局中断MRS r2,PRIMASKCPSID I; 检查 rt_thread_switch_interrupt_flag 变量是否为 0; 如果为零就跳转到 pendsv_exitLDR     r0, =rt_thread_switch_interrupt_flagLDR     r1, [r0]CBZ     r1, pendsv_exit         ; pendsv already handled清零 rt_thread_switch_interrupt_flag 变量MOV     r1, #0x00STR     r1, [r0]; 检查 rt_interrupt_from_thread 变量是否为 0; 如果为 0,就不进行 from 线程的上下文保存LDR     r0, =rt_interrupt_from_threadLDR     r1, [r0]CBZ     r1, switch_to_thread; 保存 from 线程的上下文MRS     r1, psp                 ; 获取 from 线程的栈指针STMFD   r1!, {r4 - r11}       ; 将 r4~r11 保存到线程的栈里LDR     r0, [r0]STR     r1, [r0]                ; 更新线程的控制块的 SP 指针switch_to_threadLDR     r1, =rt_interrupt_to_threadLDR     r1, [r1]LDR     r1, [r1]                ; 获取 to 线程的栈指针LDMFD   r1!, {r4 - r11}       ; 从 to 线程的栈里恢复 to 线程的寄存器值MSR     psp, r1                 ; 更新 r1 的值到 psppendsv_exitMSR PRIMASK,r2;修改lr寄存器的bit2,确保进程使用PSP堆栈指针ORR lr,lr,#0x04;退出中断函数BX lrENDP

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最新 Vue3、TypeScript、组合式API、setup语法糖 学习笔记

最新 Vue3、TypeScript、组合式API、setup语法糖 学习笔记 1、创建 Vue3 工程基于 `vue-cli` 创建(基于webpack实现)基于 `vite` 创建(推荐)2、Vue3 项目开发 `vscode` 插件推荐3、`Vue3` 核心语法【optionsAPI】与【CompositionAPI】Options API 的弊端Composition API 的…

提取游戏音频文件.bnk

提取游戏音频文件.bnk 什么是.bnk准备Wwise-Unpacker工具使用Wwise-Unpacker工具总结 什么是.bnk .bnk其实是一种对音频的加密方式&#xff0c;一个.bnk文件中通常包含了多个语音文件&#xff0c;一般可以使用Wwise-Unpacker来解码.bnk格式文件 准备Wwise-Unpacker工具 Wwis…

《Go 简易速速上手小册》第7章:包管理与模块(2024 最新版)

文章目录 7.1 使用 Go Modules 管理依赖 - 掌舵向未来7.1.1 基础知识讲解7.1.2 重点案例&#xff1a;Web 服务功能描述实现步骤扩展功能 7.1.3 拓展案例 1&#xff1a;使用数据库功能描述实现步骤扩展功能 7.1.4 拓展案例 2&#xff1a;集成 Redis 缓存功能描述实现步骤扩展功能…

OpenAI 发布文生视频大模型 Sora,AI 视频要变天了,视频创作重新洗牌!AGI 还远吗?

一、一觉醒来&#xff0c;AI 视频已变天 早上一觉醒来&#xff0c;群里和朋友圈又被刷屏了。 今年开年 AI 界最大的震撼事件&#xff1a;OpenAI 发布了他们的文生视频大模型 Sora。 OpenAI 文生视频大模型 Sora 的横空出世&#xff0c;预示着 AI 视频要变天了&#xff0c;视…

python 笔记:shapely(形状篇)

主要是点&#xff08;point&#xff09;、线&#xff08;linestring&#xff09;、面&#xff08;surface&#xff09; 1 基本方法和属性 object.area 返回对象的面积&#xff08;浮点数&#xff09; object.bounds 返回一个&#xff08;minx, miny, maxx, maxy&#xff09;元…

MySQL - 增量同步和全量同步

增量同步和全量同步是数据同步过程中常用的两种方式&#xff0c;它们在定义、区别以及适用场景上有一些明显的差异。 一、定义 增量同步是指在数据同步中仅同步更新或新增的数据&#xff0c;而不包括已经同步过的数据。全量同步则是指将所有数据进行一次完整的同步&#xff0c…

网络原理 - HTTP/HTTPS(3)

HTTP请求 认识请求"报头" header的整体的格式也是"键值对"的结构. 每个键值对占一行,键和值之间使用分号进行分割. 报头的种类有很多,此处仅介绍几个常见的. Host 表示服务器主机的地址和端口.(Host和URL中的ip地址端口啥的,绝大部分情况下都是一样的,少…

智慧城市驿站:智慧公厕升级版,打造现代化城市生活的便捷配套

随着城市化进程的加速&#xff0c;人们对城市生活质量的要求也越来越高。作为智慧城市建设的一项重要组成部分&#xff0c;多功能城市智慧驿站应运而生。它集合了信息技术、设计美学、结构工艺、系统集成、环保节能等多个亮点&#xff0c;将现代科技与城市生活相融合&#xff0…

qt - 19种精美软件样式

qt - 19种精美软件样式 一、效果演示二、核心程序三、下载链接 一、效果演示 二、核心程序 #include "mainwindow.h"#include <QtAdvancedStylesheet.h> #include <QmlStyleUrlInterceptor.h>#include "ui_mainwindow.h" #include <QDir&g…

OpenCV 4基础篇| 色彩空间类型转换

目录 1. 色彩空间基础2. 色彩空间类型2.1 GRAY 色彩空间2.2 BGR 色彩空间2.3 CMY(K) 色彩空间2.4 XYZ 色彩空间2.5 HSV 色彩空间2.6 HLS 色彩空间2.7 CIEL*a*b* 色彩空间2.8 CIEL*u*v* 色彩空间2.9 YCrCb 色彩空间 3. 类型转换函数3.1 cv2.cvtColor3.2 cv2.inRange 1. 色彩空间…

你真的了解—————NumPy吗

&#x1f308;个人主页&#xff1a;小田爱学编程 &#x1f525; 系列专栏&#xff1a;opencv &#x1f3c6;&#x1f3c6;关注博主&#xff0c;随时获取更多关于IT的优质内容&#xff01;&#x1f3c6;&#x1f3c6; &#x1f600;欢迎来到小田代码世界~ &#x1f601; 喜欢的…

Linux 基础/子目录分配/文件路径

在Linux系统中&#xff0c;整个系统只具有一个根目录“/”&#xff0c;用斜杠表示。根目录是整个文件系统的顶层目录&#xff0c;在他下面可以创建其他的目录和文件。 Linux中的子目录分配&#xff1a; /bin - 基本命令的二进制文件&#xff0c;这些命令可供所有用户使用&am…

行人重识别综述

Deep Learning for Person Re-identification: A Survey and Outlook 论文地址https://arxiv.org/pdf/2001.04193 1. 摘要 we categorize it into the closed-world and open-world settings. closed-world&#xff1a;学术环境下 open-world &#xff1a;实际应用场景下 2…

Linux 驱动开发基础知识——APP 怎么读取按键值(十二)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…

【Linux】Linux权限

Linux权限 Linux下用户的分类切换用户su 和 su - 的区别 对命令提权 权限的概念Linux权限管理文件访问者的分类&#xff08;人&#xff09;1️⃣拥有者u→user2️⃣其他人o→others3️⃣所属组group 文件类型和访问权限&#xff08;事物属性&#xff09;文件文件类型文件的基本…

基于RBAC的权限管理的理论实现和权限管理的实现

权限管理的理论 首先需要两个页面支持&#xff0c;分别是角色管理和员工管理&#xff0c;其中角色管理对应的是角色和权限的配合&#xff0c;员工管理则是将登录的员工账号和员工所处的角色进行对应&#xff0c;即通过新增角色这个概念&#xff0c;让权限和员工并不直接关联&a…

Unity求物体关于平面镜像对称后坐标以及旋转

前言&#xff1a;如题&#xff0c;我在已知一个平面L和物体A&#xff0c;我希望得到镜像后的物体B的位置和旋转。 效果&#xff1a; 推导&#xff1a; 首先我们需要知道物体的对称坐标A&#xff0c;我们现在能已知A坐标以及平面L的法线&#xff0c;如果我们能得到B的坐标&…

【后端高频面试题--Linux篇】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;后端高频面试题 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 后端高频面试题--Linux篇 往期精彩内容Windows和Linux的区别&#xff1f;Unix和Linux有什么区别…

利用nbsp设置空格

想要实现上面效果&#xff0c;一开始直接<el-col :span"8" >{{ item.name }} </el-col> 或者<el-col :span"8" >{{ item.name }}</el-col>或者<el-col :span"8" >{{ item.name }}</el-col> 都无…

生产力工具——JNPF开发平台

风流数年&#xff0c;只看今朝&#xff0c;Linux 让我们看到了开源驱动下的生产力&#xff0c;其实低代码和它一样&#xff0c;都是提高效率、降低成本的工具。 近 10 年间&#xff0c;JNPF 低代码平台如火如荼的发展起来&#xff0c;堪称黑马也不为过。这款广受好评的低代码平…