内核移植学习

news2024/12/26 11:27:38

内核移植

内核移植就是指将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		PROC
	EXPORT rt_hw_interrupt_disable		
	MRS r0,PRIMASK
	CPSID I
	BX LR
	ENDP

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

打开全局中断

rt_hw_interrupt_enable PROC
	EXPORT rt_hw_interrupt_enable 
	MSR PRIMASK,r0
	BX LR
	ENDP

实现线程栈初始化

在动态创建线程和初始化线程的时候,会使用到内部的线程初始化函数_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] stack

PendSV_Handler PROC
	EXPORT PendSV_Handler 
	
	;关闭全局中断
	MRS r2,PRIMASK
	CPSID I
	
	; 检查 rt_thread_switch_interrupt_flag 变量是否为 0
    ; 如果为零就跳转到 pendsv_exit
    LDR     r0, =rt_thread_switch_interrupt_flag
    LDR     r1, [r0]
    CBZ     r1, pendsv_exit         ; pendsv already handled

	清零 rt_thread_switch_interrupt_flag 变量
    MOV     r1, #0x00
    STR     r1, [r0]

    ; 检查 rt_interrupt_from_thread 变量是否为 0
    ; 如果为 0,就不进行 from 线程的上下文保存
    LDR     r0, =rt_interrupt_from_thread
    LDR     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_thread
    LDR     r1, =rt_interrupt_to_thread
    LDR     r1, [r1]
    LDR     r1, [r1]                ; 获取 to 线程的栈指针

    LDMFD   r1!, {r4 - r11}       ; 从 to 线程的栈里恢复 to 线程的寄存器值
    MSR     psp, r1                 ; 更新 r1 的值到 psp


pendsv_exit
	MSR PRIMASK,r2
	;修改lr寄存器的bit2,确保进程使用PSP堆栈指针
	ORR lr,lr,#0x04
	;退出中断函数
	BX lr
	ENDP

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

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

相关文章

【软件架构】01-架构的概述

1、定义 软件架构就是软件的顶层结构 RUP&#xff08;统一过程开发&#xff09;4 1 视图 1&#xff09;逻辑视图&#xff1a; 描述系统的功能、组件和它们之间的关系。它主要关注系统的静态结构&#xff0c;包括类、接口、包、模块等&#xff0c;并用于表示系统的组织结构…

Android基础Adapter适配器详解

一、概念 Adapter是后端数据和前端显示UI的适配器接口。常见的View如ListView、GridView等需要用到Adapter. BaseAdapter&#xff1a;抽象类&#xff0c;实际开发中继承这个类并且重写相关方法&#xff0c;用得最多的一个Adapter&#xff01; ArrayAdapter&#xff1a;支持泛型…

Gradle统一管理依赖

背景 随着项目越来越大&#xff0c;module 越来越多&#xff0c;依赖的库也越来越多&#xff0c;依赖管理也越来越混乱。 我们一般会有以下需求&#xff1a; 1. 项目依赖统一管理&#xff0c;在单独文件中配置 2. 不同 Module 中的依赖版本号统一 管理 Gradle 依赖 说明&a…

Vue3学习——标签的ref属性

在HTML标签上&#xff0c;可以使用相同的ref名称&#xff0c;得到DOM元素ref放在组件上时&#xff0c;拿到的是组件实例&#xff08;组件defineExpose暴露谁&#xff0c;ref才可以看到谁&#xff09; <script setup lang"ts"> import RefPractice from /compo…

C++/C函数指针及函数指针数组

文章目录 什么是函数指针函数指针的使用为什么要使用函数指针&#xff1f;回调函数函数指针数组及使用阅读两段有趣的代码指向成员函数的指针&#xff08;C特有&#xff09; 什么是函数指针 首先它是一个指针&#xff0c;一个指向函数的指针&#xff0c;在内存空间中存放的是函…

Camunda快速入门(五):设计一个带DMN业务规则的流程

接上一篇文章&#xff1a;Camunda快速入门&#xff08;四&#xff09;&#xff1a;设计一个带网关的流程 在本节中&#xff0c;您将学习如何使用 BPMN 2.0 业务规则任务和 DMN 1.3 决策表将决策自动化添加到流程中。 1、将业务规则任务添加到流程 使用 Camunda Modeler 打开…

Python学习-if else及比较运算符、while循环结构、random生成随机数模块

五、if else及比较运算符 1、if else语法 if 条件&#xff1a; 如果条件为真&#xff08;Ture&#xff09;执行这里的语句 else: 如果条件为假&#xff08;False&#xff09;执行这里的语句 2、比较运算符 运算符含义<判断左边是否小于右边<判断左边是否小于或等于右…

《nvm 安装》nodejs 版本管理工具

一.前言 如果先于 nvm 安装了 node&#xff0c;一定要先卸载&#xff01; 两种卸载方式&#xff1a; 方式一 控制面板 -> 程序和功能 -> nodejs 删除 方式二 下载的 node 安装包有卸载选项 二. 安装 nvm 下载地址 中找到对应的安装包&#xff0c;我本机使用 window…

关于公司私有gitlab拉去项目中遇到的问题

新进公司都会遇到拉去项目代码问题&#xff0c;新账号新环境&#xff1b;怎么拉去代码才是最有效的呢&#xff1f; 在此某些大神会给你一个地址&#xff1a;一句你自己来取吧&#xff1b;拉下来看看逻辑就行了&#xff1b;这样的人挺不错&#xff1b;会让你陷入无限的BUG循环中…

安卓adb调试备忘录

由于 MAC 的 USB 口全被占用着&#xff0c;采用无线连接刚方便&#xff0c;记录一下&#xff0c;以防忘记~ ADB原理 adb devices -l ## 列出连接的设备adb tcpip [端口号] adb tcpip 6666 # 将当前已连接USB上的Mobile端切换为TCP/IP模式&#xff0c;以6666端口进行监听. adb…

数字孪生与智慧城市:共筑未来城市的科技基石

一、引言 随着科技的飞速发展&#xff0c;数字孪生与智慧城市已成为未来城市建设的两大关键技术。数字孪生为城市提供了一个虚拟的数字镜像&#xff0c;使我们能全面、深入地了解城市的运行状态。而智慧城市则借助先进的信息通信技术&#xff0c;提升城市的智能化水平&#xf…

机器学习基础(三)监督学习的进阶探索

导语&#xff1a;上一节我们深入地探讨监督学习和非监督学习的知识&#xff0c;重点关注它们的理论基础、常用算法及实际应用场景&#xff0c;详情可见&#xff1a; 机器学习基础&#xff08;二&#xff09;监督与非监督学习-CSDN博客文章浏览阅读769次&#xff0c;点赞15次&a…

明御运维审计与风险控制系统漏洞复现

简介 明御运维审计与风险控制系统是安恒信息在多年运维安全管理的理论和实践经验积累的基础上,采用B/S架构,集“身份认证、账户管理、控制权限、日志审计”于一体,支持多种字符终端协议、文件传输协议、图形终端协议、远程应用协议的安全监控与历史查询,具备全方位运维风险…

springboot+vue的飘香水果购物网站(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

JavaScript 设计模式之组合模式

组合模式 在我们日常中肯呢个会将一个表单用这种模式来创建 const Car function () { } Car.prototype.getName function () { throw new Error("需要重写该方法") } Car.prototype.getPrice function () {throw new Error("需要重写该方法") } const…

05_i2c_controller内核模块

01_basicLinux内核模块-CSDN博客文章浏览阅读304次&#xff0c;点赞3次&#xff0c;收藏3次。环境IDubuntuMakefilemodules:clean:basic.creturn 0;运行效果。https://blog.csdn.net/m0_37132481/article/details/136157384i2c_controller.c rootT:/media/sf_D_DRIVE/kmodule/…

书生·浦语大模型实战营第五节课作业

基础作业 本地部署300字的小故事在这里插入图片描述

Easyx的学习1

使用easys的相关函数需要包含头文件#include<easyx.h>或#include<graphics.h>&#xff08;#include<graphics.h>包含了<easyx.h>和一些不推荐使用的函数&#xff09; 目录 窗口创建背景颜色 基本图形绘制 1.点 2.线 3.矩形 圆角矩形 4. 圆形 椭圆…

一文彻底搞懂Java对象什么时候被垃圾器回收

文章目录 1. 简介2. 引用计数法2.1 优点2.2 缺点 3. 可达性分析算法3.1 虚拟机栈&#xff08;栈帧中的本地变量表&#xff09;中引用的对象3.2 方法区中静态属性引用的对象3.3 方法区中常量引用的对象3.4 本地方法栈中 JNI&#xff08;即一般说的 Native 方法&#xff09;引用的…

Day23--learning English

一、积累 1.straw 2.umami | tangy | bland 3.lactose dairy 4.fatigue 5.stumble | curb 6.pore 7.toll 8.arrear 9.robe 10.stylish 11.dash 12.mischief 13.ranch 14.sponsorship 15.podcast 16.villian 17.clutch 18.envision 二、练习 1.牛津原译 1.straw /strɔː/ 1…