# leos **Repository Path**: shi-src-2021/leos ## Basic Information - **Project Name**: leos - **Description**: leos是一个以学习为目的的协程操作系统 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-07-26 - **Last Updated**: 2025-10-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README leos是一个参考rtthread编写的一个以学习为目的的实时嵌入式系统,原计划编写一个事件驱动的操作系统,也就是little event operation system的由来。但后续发现qpc项目,已有完整的层次式状态机 + 事件驱动 + 线程调度内核框架,但项目过大且代码可读性不高,等后续学习完qpc项目后,融合两种框架,继续进行leos的项目开发。目前编写一下开发记录。 #### 工作进度 目前仅编写了支持cortex-m3内核启动代码与线程切换汇编函数,基本是照抄rtthread的代码并添加注释,实现了基本的线程静态创建、线程调度、内核定时器功能,线程间通信仅做了信号量的实现。出于学习的目的,项目中未考虑内核、编译器等兼容性处理,也没有添加相应的调试支持和钩子函数的实现。 ---- 2024/7/31 #### 过程笔记 cortex-m3架构相关资料可以参考《ARM Cortex-M3与Cortex-M4权威指南》,如果想深入理解m3内核这本书非常推荐。 ##### (1)MSP 与 PSP * cortex-m3内核中SP寄存器可使用MSP、PSP两种堆栈指针 * 中断中必定使用主堆栈指针MSP,无操作系统程序中也使用MSP做为堆栈指针; * os系统的线程中则需要使用PSP,这样可以隔离操作系统与线程,当任务堆栈出问题的时候不会影响系统的堆栈,保证中断使用的堆栈不会被线程影响。 * 可以通过MSR汇编指令编辑特殊寄存器CONTROL中某一位的方式,修改使用MSP还是PSP;也可以通过中断返回的方式进行设置MSP还是PSP。通常采用中断返回的方式,在中断中编辑特定的LR寄存器值来设置。 ##### (2)PendSV * PendSV 的主要作用是实现任务上下文切换。它是一个优先级最低的系统异常,可以在任意时刻触发任务切换,而不影响系统的其他中断和任务执行, * PendSV 可以被挂起和延迟处理,这使得它非常适合在处理完高优先级的中断后再进行任务切换。这样任务切换就不会影响系统高优先级的中断运行。 * 可以通过设置中断控制状态寄存器(0xE000ED04)中PENDSVSET位进行异常触发 ##### (3)SVC * FreeRTOS中启动第一个任务是通过SVC的方式触发的,rtthread使用的是PendSV的方式。 * 一般用于OS中线程向系统请求系统服务 ##### (4)AAPCS * 即 ARM架构过程调用标准,参考 [[AAPCS]] * 主要包括 参数传递、返回值、调用者与被调用者寄存器的保存规则、堆栈管理 * 从这里也就理解了为什么函数调用时入参不是入参本身,是入参的拷贝;所以想修改一个变量,传参时就需要传这个变量的地址,这样汇编中才可以修改这个变量的值;如果入参只有一个变量的值,汇编代码是无法找到这个变量的地址的,也就无法修改这个变量的值。 ##### (5)上下文切换 * 上下文切换是在PendSV中执行的 * cortex-m3内核中进入中断时会对R0 - R3、R12、R14(LR)、EXC_RETURN 以及PSR进行压栈,这是由处理器硬件执行的,所以切换上下文时只需要保存R4 - R11即可。 * 采用中断返回的方式,在中断中编辑特定的LR寄存器值来设置使用PSP。 ##### (6)可移植组件 * 在项目中实现了侵入式双向链表、软件定时器等功能,是独立于系统的,可以单独移植到新项目中。 ##### (7)线程调度 * rtthread是通过优先级位图的方式可以快速找到最高优先级,从而从优先级链表数组中快速找到对应的链表来执行当前最高优先级的任务。 * 位图操作中,可以使用 `__builtin_ffs()` 内建函数快速找到第一个置位的1;同时还有很多其他的内建函数用于位运算,具体可以参考 [[__builtin 位运算]] ##### (8)线程间通信 * rtthread的线程间通信基本是通过各个通信方式中的阻塞链表实现的。这样在take且无资源时,将线程从就绪链表中移除、并挂入阻塞链表,如果需要定时器,会调用线程内部的定时器,然后启动调度;release时,把线程从阻塞链表中移除,重新调度。几种通信方式基本都是这个套路,根据特性不同会添加对应的特性,比如互斥量的优先级反转控制、队列的写入阻塞链表等。 #### 主要功能: ##### (1)leos_thread * **线程初始化** 初始化线程链表、初始化栈帧、初始化线程定时器 * **线程yield** 如果当前优先级有别的线程,就移除自身,并插入当前优先级链表末尾,启动调度 * **线程挂起** 从优先级链表中移除自身,更新优先级位图,关闭线程定时器 * **线程恢复** 线程链表移除自身(防止任务挂在阻塞链表),关闭定时器,插入优先级链表,更新位图 * **线程休眠** 挂起当前线程,启动线程定时器,启动调度 * **空闲线程创建** #### (2)leos_scheduler * 使用优先级链表,把各个就绪线程挂在此链表中 * 移除或新增线程时,更新位图,从位图获取最高优先级任务进行调度 * 使用nest计数,判断是否处于临界段内,nest == 0时,才可以进行调度 #### (3)leos_clock * 获取当前tick * 检查当前线程剩余tick,剩余tick为0时,调用线程yield * 遍历软件定时器,调用对应回调函数 #### (4)leos_ipc * rtthread的线程间通信基本是通过各个通信方式中的阻塞链表实现的。 * 这样在take且无资源时,将线程从就绪链表中移除、并挂入阻塞链表, * 如果需要定时器,会调用线程内部的定时器,然后启动调度; * release时,把线程从阻塞链表中移除,重新调度。 * 几种通信方式基本都是这个套路,根据特性不同会添加对应的特性,比如互斥量的优先级反转控制、队列的写入阻塞链表等。