手写RTOS(课程回顾)

什么是程序

X86
X86在调用函数的时候传递在参数是从栈中取出的,需要哪些参数提前按一定顺序入栈即可。第一个出栈的就对应第一个参数,依次类推。函数返回值存在eax中。
ARM
arm函数调用参数传递顺序是从r0~r3,第一个参数在r0中,第二个参数在r1中,依次类推。参数超过4个,则要先入栈,从第五个参数开始从栈中取。函数返回值放在r0中。

手写RTOS(课程回顾)

基于模板https://gitee.com/zeng-hanhan/hand-write-rtos
模板已经实现
1)自定义串口输出打印函数,2)定时器中断功能,3)可在模拟器运行 。。。。。

创建目录: rtos 文件:task.c task.h

工程目录结构:
请添加图片描述

核心

请添加图片描述

task.c文件:

实现创建任务函数

第一次运行任务,需要初始化栈,将 返回地址 设置为 任务函数指针。
中断结束就跳转到 该地址 执行。

请添加图片描述

void create_task(task_function *f, void *param, char *stack, int stack_len){
	int *top = (int *)(stack + stack_len);
	/* 伪造现场 */
	top -= 16;
	// r4~r11
	top[0] = 0;
	top[1] = 0;
	top[2] = 0;
	top[3] = 0;
	top[4] = 0;
	top[5] = 0;
	top[6] = 0;
	top[7] = 0;
	// r0~r3
	top[8] = (int)param;
	top[9] = 0;
	top[10] = 0;
	top[11] = 0;
	// r12 lr
	top[12] = 0;
	top[13] = 0;
	// 返回地址 任务入口
	top[14] = (int)f;
	//psr
	top[15] = (1<<24);//指令集
	/* 记录栈的位置 */
	task_stacks[task_count++] = (int)top;
}

开始任务函数: 将全局变量 task_running 置为1 ,实际在中断中开启执行任务
定时器中断时检测该变量,是否创建任务,避免还没创建任务就在中断运行。

void task_start(void){
	task_running = 1;
	while(1);
}

中断

中断函数为汇编,

保存现场后调用c函数 SysTick_Handler

SysTick_Handler_asm PROC
				;保存r4~r11
				STMDB SP!,{R4 - R11}
				STMDB SP!,{LR}
				
				MOV R0, LR	;LR是特殊值
				ADD R1, SP, #4
				
				BL SysTick_Handler	;不破坏r4~r11
				
				LDMIA SP!, {R0} 
				LDMIA SP!, {R4 - R11} 
				
				BX R0
				ENDP

SysTick_Handler 函数:
int cur_task:全局变量 当前任务
int is_task_running(void): 函数 判断是否有任务已经创建
int get_stack (int task_index): 获取任务的栈
void set_task_stack(int task,int sp): 修改 task 的栈顶为sp
均在 task.c 实现

判断要 ”创建任务” 还是 ”启动第一个任务” 还是 ”切换任务”
如果还没创建任务直接返回, 相当于啥也不做
启动第一个任务设置当前任务 cur_task = 0,
跳到 StartTask_asm运行,从当前任务的栈中恢复寄存器
效果是把伪造的现场写入寄存器后结束中断并从伪造的 返回地址(任务入口函数) 运行。
** 切换任务 **在中断发生就已经保存了所有寄存器
只需要获取下一个任务栈,把栈和特殊的 lr 值交给 StartTask_asm 汇编函数 恢复下一个任务的寄存器 开始下一个任务的执行。

void SysTick_Handler(int LR,int old_sp)
{
	int stack, pre_task, new_task;
	
	SCB_Type * SCB = (SCB_Type *)SCB_BASE_ADDR;
	
	/* clear exception status */
	SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk;
	
	/* 如果还没创建任务  */
	if(!is_task_running()){
		return;
	}
	/* 启动第一个任务或者切换 */	
	if(cur_task == -1){
		/* 启动第一个任务 */
		cur_task = 0;
		/* 从栈恢复寄存器 */
		//
		stack = get_stack(cur_task);
		StartTask_asm(stack, LR);		/* 开始任务需要把栈中的值读入到 寄存器 用汇编做 */
	}
	else{
		/* 切换任务 */
		pre_task = cur_task;
		new_task = get_next_task();	//下一个任务
		
		if(pre_task != new_task){
			/* 保存pre_task:r4~r11 
			 * 在汇编中已经保存
			 */
			
			/* 更新sp */
			set_task_stack(pre_task, old_sp);
			
			/* 切换new_task */
			stack = get_stack(new_task);
			cur_task = new_task;
			StartTask_asm(stack, LR);
		}
	}

StartTask_asm

从任务栈恢复寄存器

StartTask_asm PROC
				;从任务的栈 把r4-r11读出来写入寄存器
				;r0存有任务的栈 r1有LR(特殊的值)
				LDMIA R0!, {R4 - R11} 		
				;更新SP
				MSR MSP, R0
				;触发硬件中断返回; 
				BX R1
				
				ENDP
ROC
				;从任务的栈 把r4-r11读出来写入寄存器
				;r0存有任务的栈 r1有LR(特殊的值)
				LDMIA R0!, {R4 - R11} 		
				;更新SP
				MSR MSP, R0
				;触发硬件中断返回; 
				BX R1
				
				ENDP
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值