内核移植笔记 Cortex-M移植

常用寄存器

PRIMASK寄存器
为1位宽的中断屏蔽寄存器。在置位时,它会阻止不可屏蔽中断(NMI)和HardFault异常之外的所有异常(包括中断)。
实际上,它是将当前异常优先级提升为0,这也是可编程异常/中断的最高优先级。

FAULTMASK寄存器
FAULTMASK与PRIMASK相类似,但同时它能屏蔽HardFault异常,它实际上是将异常优先级提升到了-1。

程序状态寄存器(xPSR)
xPSR包含:

  • 应用PSR(APSR)
  • 执行PSR(EPSR)
  • 中断PSR(IPSR)

在这里插入图片描述
注:GE 在 Cortex-M4 等 ARMv7E-M 处理器中存在,在 Cortex-M3 处理器中则不可用。

  • N:负标志
  • Z:零标志
  • C:进位(或者非借位)标志
  • V:溢出标志
  • Q:包含标志
  • GE:大于或等于标志
  • ICI/IT:中断继续指令位
  • T:Thumb状态,总是1,清除此位会引起错误异常
  • 异常变化:表示处理器正在处理的异常

中断向量表
Cortex-M系列处理器的中断向量表位于0x00000000,单Cortex-M3/4系列提供了SCB_VTOR,所以中断向量表的位置位于0x00000000+SCB_VTOR。

异常相关指令

  • CPSIE I:使能中断(清除PRIMASK)
  • CPSID I:禁止中断(设置PRIMASK),NMI和HardFault不受影响
  • CPSIE F:使能中断(清除FAULTMASK)
  • CPSID F:禁止中断(设置FAULTMASK),NMI不受影响

移植过程

在嵌入式领域有多种不同CPU架构,例如Cortex-M,ARM920T、MIPS、RISC-V等等。
为了使RT-Thread能够在不同CPU架构的芯片上运行,RT-Thread提供了一个libcpu抽象层适配不同的CPU架构

libcpu层向上对内核提供统一的接口,包括全局中断的开关,线程栈的初始化,上下文切换等。

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

libcpu移植相关API,要对CPU进行移植只需要实现这些接口

关闭全局中断

/*rt_base_t rt_hw_interrupt_disable(void);*/

.global rt_hw_interrupt_disable
.type rt_hw_interrupt_disable,%function

rt_hw_interrupt_disable:
	MRS R0,PRIMASK ;将PRIMASK关中断前的状态存入R0,并作为函数返回值返回
	CPSID I	;关闭中断
	BX LR
/*void rt_hw_interrupt_enable(rt_base_t level); level是调用关中断函数时的返回值,代表关中断前PRIMASK的值*/
.global rt_hw_interrupt_enable
.type rt_hw_interrupt_enable,%function

rt_hw_interrupt_enable:
	MSR PRIMASK,R0 ;将level写入PRIMASK寄存器,恢复关中断前的状态
	BX LR

实现线程栈初始化

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

    /* init all register */
    for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++)
    {
        ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef;
    }
     /* 根据 ARM  APCS 调用标准,将第一个参数保存在 r0 寄存器 */
    stack_frame->exception_stack_frame.r0  = (unsigned long)parameter; 
    stack_frame->exception_stack_frame.r1  = 0;                        /* r1 */
    stack_frame->exception_stack_frame.r2  = 0;                        /* r2 */
    stack_frame->exception_stack_frame.r3  = 0;                        /* r3 */
    /* 将 IP(Intra-Procedure-call scratch register.) 设置为 0 */
    stack_frame->exception_stack_frame.r12 = 0;    
    //将线程退出函数的地址保存在lr寄存器
    stack_frame->exception_stack_frame.lr = (unsigned long) texit;
    //将线程入口函数的地址保存在pc寄存器
    stack_frame->exception_stack_frame.pc = (unsigned long) tentry;
    /* 设置 psr 的值为 0x01000000L,表示默认切换过去是 Thumb 模式 */
    stack_frame->exception_stack_frame.psr = 0x01000000L;              /* PSR */
    return stk;
}

实现上下文切换

在Cortex-M里面上下文切换都是统一使用PendSV异常来完成。
为了能适应不同的CPU架构,RT-Thread的libcpu抽象层需要实现三个线程相关的函数:

  1. rt_hw_context_switch_to():没有来源线程,切换到目标线程,在调度器启动第一个线程的时候被调用。
  2. rt_hw_context_switch():在线程环境下,从当前线程切换到目标线程。
  3. rt_hw_context_switch_intrrupt():在中断环境下,从当前线程切换到目标线程。

PendSV_Handler

产生PendSV异常时,Cortex-M系列处理器硬件会自动将from线程的PSR、PC、LR、R12、R3-R0压栈,因此在PendSV_Handler中,我们需要把from线程的R11-R4压栈,并把to线程的R11-R4弹出。修改PSP为to线程的栈地址,在退出PendSV中断时,硬件会自动弹出R3-R0、R12、LR、PC、PSR寄存器。

/*R0->保存from线程的栈,R1->保存to线程的栈*/
/*PSR PC LR...被放入from线程的栈*/
.global PendSV_Handler
.type PendSV_Handler, %function

PendCV_Handler:
	MRS R2,PRIMASK
	CPSID	I

	LDR R0, =rt_thread_switch_interrupt_flag
	LDR R1,[R0]
	CBZ R1,pendsv_exit 

	MOV R1,#0
	STR R1,[R0]

	LDR R0,=rt_interrupt_from_thread
	LDR R1,[R0]
	CBZ R1,switch_to_thread

	MRS R1,PSP
	STMFD R1!,{R4-R11} //将from线程的数据寄存器R4-R11压栈
	LDR R0,[R0] 
	STR R1,[R0]

switch_to_thread:
	LDR R1,=rt_interrupt_to_thread
	LDR R1,[R1]
	LDR R1,[R1]

	LDMFD R1!,{R4-R11} //将to线程寄存器弹出
	MSR PSP,R1 //更新栈指针

pendsv_exit:
	MSR PRIMASK,R2
	ORR LR,LR,#0X4
	BX LR

rt_hw_context_switch_to

在这里插入图片描述

.global rt_hw_context_switch_to
.type rt_hw_context_switch_to,%function

rt_hw_context_switch_to:
	LDR R1,=rt_interrupt_to_thread
	STR R0,[R1]

	LDR R1,=rt_interrupt_from_thread
	MOV R0,#0
	STR R0,[R1]
	
	LDR R1,=rt_thread_switch_interrupt_flag
	MOV R0,#1
	STR R0,[R1]

	
	LDR R0,=SHPR3
	LDR R1,=PENDSV_PRI_LOWEST
	LDR.W R2,[R0,#0]
	ORR     R1, R1, R2              /* modify */
    STR     R1, [R0]                /* write-back */

	LDR     R0, =ICSR               /* trigger the PendSV exception (causes context switch) */
    LDR     R1, =PENDSVSET_BIT        ;0x10000000,ICSR 的第 28 位为 PendSV set-pending bit.
    STR     R1, [R0]                ;Writing 1 to this bit is the only way to set the PendSV exception state to pending.

	//恢复MSP 
	LDR R0,=SCB_VTOR
	LDR R0,[R0] //读取中断向量表的位置
	LDR R0,[R0] //读取 SP初始值
	NOP
	MSR MSP,R0 ;将SP初始值赋给MSP

	   /* enable interrupts at processor level */
    CPSIE   F
    CPSIE   I

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

K8S知识点(五)

&#xff08;1&#xff09;资源管理介绍 Pod控制器的作用&#xff0c;就是为了最终产生各种各样的Pod&#xff0c;Pod里面运行容器&#xff0c;容器里面运行程序 程序需要数据持久化&#xff0c;可以用数据存储卷来存储 Pod想要让外部访问需要通过Service代理&#xff0c;外部…

SAP-PP-报错:工作中心 7333_JQ 工厂 7331 对任务清单类型 N 不存在

创建工艺路线时报错&#xff1a;工作中心 7333_JQ 工厂 7331 对任务清单类型 N 不存在&#xff0c; 这是因为在创建工作中心时未维护控制键值导致的

latex加密符号怎么打|同态加密|Paillier

最近在写论文的时候遇到了一点阻碍&#xff0c;因为论文中需要用到paillier加密算法&#xff0c;想用一个公式表达加密的过程&#xff0c;但是不知道怎么打加密符号。 加密符号如下所示&#xff1a; 其中a是被加密的数字 $[\![a]\!] $ 公式&#xff1a; \begin{equation} …

【编程语言发展史】SQL的发展历史

目录 目录 SQL概述 SQL发展历史 SQL特点 SQL基本语句 SQL是结构化查询语言(Structure Query Language)的缩写&#xff0c;它是使用关系模型的数据库应用语言&#xff0c;由IBM在70年代开发出来&#xff0c;作为IBM关系数据库原型System R的原型关系语言&#xff0c;实现了…

单链表详解

今天我们继续来学习我们的链表&#xff0c;今天我们来学习单链表&#xff0c;什么是单链表呢&#xff0c;我们逻辑结构上可以认为是下面这个图。 然后我们结构体的定义就是下面这个 typedef int SLDateType; typedef struct SList {SLDateType x;struct SList* next; }SL;为什么…

(14)学习笔记:动手深度学习(Pytorch神经网络基础)

文章目录 神经网络的层与块块的基本概念自定义块 问答 神经网络的层与块 块的基本概念 以多层感知机为例&#xff0c; 整个模型接受原始输入&#xff08;特征&#xff09;&#xff0c;生成输出&#xff08;预测&#xff09;&#xff0c; 并包含一些参数&#xff08;所有组成层…

vue3 开启 https

1、安装mkcert证书创建器 npm i mkcert -g 2、检验是否安装成功 mkcert --version 有版本好出现则成功 3、创建证书颁发机构 mkcert create-ca 会在当前目录生成&#xff0c;ca.crt 和 ca.key 两个文件 4、创建证书 mkcert create-cert 会在当前目录生成&#xff0c;…

【2023.11.6】OpenAI发布会——近期chatgpt被攻击,不能使用

OpenAI发布会 写在最前面发布会内容GPT-4 Turbo 具有 128K 上下文函数调用更新改进了指令遵循和 JSON 模式可重现的输出和对数概率更新了 GPT-3.5 Turbo 助手 API、检索和代码解释器API 中的新模式GPT-4 Turbo 带视觉DALLE 3文字转语音 &#xff08;TTS&#xff09;收听语音样本…

Linux第一个小程序进度条

缓冲区 ​ 在写进度条程序之前我们需要介绍一下缓冲区&#xff0c;缓冲区有两种&#xff0c;输入和输出缓冲区&#xff0c;这里主要介绍输出缓冲区。在我们用C语言写代码时&#xff0c;输出一些信息&#xff0c;实际上是先输出到输出缓冲区里&#xff0c;然后才输出到我们的显…

AI系统ChatGPT程序源码+AI绘画系统源码+支持GPT4.0+Midjourney绘画+已支持OpenAI GPT全模型+国内AI全模型

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

3D全景技术,为我们打开全新宣传领域

随着科技的发展&#xff0c;3D全景技术正在融入我们的生活&#xff0c;这种全新视觉体验方式为我们打开了一扇全新的宣传领域&#xff0c;可以让我们多方位、多视角地探索各个行业&#xff0c;无论是对教育、商业、还是其他领域&#xff0c;都产生了深远的影响。 3D全景技术结合…

【云备份|| 日志 day5】文件热点管理模块

云备份day5 热点管理模块 热点管理模块 服务器端的热点文件管理是对上传的非热点文件进行压缩存储&#xff0c;节省磁盘空间。 而热点文件的判断在于上传的文件的最后一次访问时间是否在热点判断时间之内&#xff0c;比如如果一个文件一天都没有被访问过我们就认为这是一个非…

多VLAN之间的通信,静态路由

一、适用场景 1、多个C类网络&#xff08;不同网段&#xff09;之间需要通信&#xff0c;每个网段有1个网关ip。 2、当网络结构比较简单时&#xff0c;只需配置静态路由就可以使网络正常工作。本例采用简单网络结构 3、在复杂网络环境中&#xff0c;配置静态路由可以改进网络的…

牛客出bug(华为机试HJ71)

Hj71&#xff1a;字符串通配符 描述 问题描述&#xff1a;在计算机中&#xff0c;通配符一种特殊语法&#xff0c;广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。 要求&#xff1a; 实现如下2个通配符&#xff1a; *&#xff1a;匹配0个…

Java --- Mybatis的动态sql标签

一、if标签 <select id"queryEmpByCondition" resultType"User">select * from t_user where 11<if test"username ! null and username ! ">and username #{username}</if></select> if&#xff1a;根据标签中的test…

AWTK 与 Qt 的异同点比较

相似之处&#xff1a; 跨平台支持&#xff1a; AWTK 和 Qt 都提供了跨平台的支持&#xff0c;可以在多种操作系统上进行开发和部署&#xff0c;包括 Windows、Linux、macOS 等。丰富的组件库&#xff1a; 两者都提供了丰富的图形界面组件库&#xff0c;能够满足各种应用程序的…

pytest全局变量的使用

这里重新阐述下PageObject设计模式&#xff1a; PageObject设计模式是selenium自动化最成熟&#xff0c;最受欢迎的一种模式&#xff0c;这里用pytest同样适用 这里直接提供代码&#xff1a; 全局变量 conftest.py """ conftest.py 全局变量&#xff0c;主要实…

华为eNSP实验-三层交换机的不同网段通信(通过OSPF路由方式)

1.拓扑图 2.过程如下 2.1 首先PC1和PC2配置好IP地址 2.2 在SW1上配置虚拟网关及VLAN <Huawei>system-view [Huawei]sysname SW1 [SW1]undo info-center enable [SW1] [SW1]vlan batch 10 20 [SW1]interface GigabitEthernet 0/0/1 [SW1-GigabitEthernet0/0/1]port li…

docker.service配置docker镜像加速

加速器配置方法很多&#xff0c;小白我用的是docker.service文件&#xff0c;所以直接在里面配置啊 配置以后&#xff0c;要systemctl daemon-reload下 &#xff0c;然后docker info 下看下镜像地址是否是自己已配置的 docker run --privilegedtrue --name mytomcat -p 8080…

利用QT画图像的直方图

1.什么是直方图 直方图是一种图形化展示数据频率分布的方式。它将样本数据分成一系列相邻的区间&#xff0c;统计每个区间内数据所占比例或数量&#xff0c;并用矩形条形图表现出来。直方图可以反映样本数据的分布情况&#xff0c;例如它们的集中趋势、对称性和离散程度等。 …