arch_task.c
2026/7/20大约 3 分钟附录源码附录
arch_task.c
路径: arch\arm\armv7m\arch_task.c
功能: ARM Cortex-M 架构相关的任务栈初始化和栈溢出检测实现。本文件是 OneOS 任务切换的底层基础,提供 os_hw_stack_init(任务栈初始化)和 os_hw_stack_max_used(栈最大使用量检测)以及 os_task_stack_is_overflow(栈溢出检测)三个核心函数。
核心函数:
| 函数 | 说明 |
|---|---|
os_hw_stack_init | 初始化任务栈帧:填充寄存器初始值(R0-R3/R12/LR/PC/PSR),设置 EXC_RETURN 值 |
os_hw_stack_max_used | 计算任务栈最大使用量:从栈底扫描 $ 标记字节 |
os_task_stack_is_overflow | 检测任务栈是否溢出(编译条件:OS_USING_OVERFLOW_CHECK) |
关键设计点:
- 栈帧布局: 按照 ARM Cortex-M 异常入栈顺序(xPSR/PC/LR/R12/R3/R2/R1/R0)初始化栈帧,确保
PendSV异常返回时自动恢复 - EXC_RETURN: 设置为
0xFFFFFFFD(返回 Thread 模式 + 使用 PSP + 无 FPU),兼容硬件浮点自动切换 - 栈签名: 使用
$(0x24)填充栈空间,通过扫描非$字节计算最大使用量 - 栈溢出检测: 检查栈顶是否在合法范围(
stack_begin~stack_end)内,以及栈底部$签名是否被覆盖
/**
***********************************************************************************************************************
* Copyright (c) 2020, China Mobile Communications Group Co.,Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* @file arch_task.c
*
* @brief This file provides functions related to the task stack.
*
* @revision
* Date Author Notes
* 2021-10-22 OneOS Team First version.
***********************************************************************************************************************
*/
#include <os_types.h>
#include <os_task.h>
#include <string.h>
#include <os_assert.h>
#include <arch_task.h>
/* Stack down(栈向下增长) */
void *os_hw_stack_init(void (*task_entry)(void *arg),
void *arg,
void *stack_begin,
uint32_t stack_size,
void (*task_exit)(void))
{
struct stack_frame_nofpu *stack_frame;
uint8_t *stack_top;
uint32_t index;
/* 用 '$' 填充整个栈空间,用于后续栈使用量检测 */
memset(stack_begin, '$', stack_size);
/* 计算栈顶地址(向下增长,栈顶 = 栈底 + 栈大小) */
stack_top = (uint8_t *)stack_begin + stack_size;
/* 对齐到架构要求的栈对齐边界 */
stack_top = (uint8_t *)OS_ALIGN_DOWN((os_ubase_t)stack_top, OS_ARCH_STACK_ALIGN_SIZE);
/* 预留栈帧空间 */
stack_top -= sizeof(struct stack_frame_nofpu);
/* TODO: Need to check stack size */
stack_frame = (struct stack_frame_nofpu *)stack_top;
/* 初始化所有寄存器为 0xDEADBEEF(调试用魔数) */
for (index = 0; index < sizeof(struct stack_frame_nofpu) / sizeof(uint32_t); index++)
{
((uint32_t *)stack_frame)[index] = 0xDEADBEEF;
}
/* 设置异常返回时的寄存器初始值 */
stack_frame->r0 = (uint32_t)arg; /* r0 : 任务入口参数 */
stack_frame->r1 = 0; /* r1 */
stack_frame->r2 = 0; /* r2 */
stack_frame->r3 = 0; /* r3 */
stack_frame->r12 = 0; /* r12 */
stack_frame->lr = (uint32_t)task_exit; /* lr : 任务退出函数 */
stack_frame->pc = (uint32_t)task_entry; /* pc : 任务入口函数 */
stack_frame->psr = 0x01000000UL; /* PSR : 默认 Thumb 状态 */
/*
* EXC_RETURN = 0xFFFFFFFD:
* - 返回 Thread 模式
* - 使用 PSP(进程栈指针)
* - 无浮点上下文(FPU 由硬件自动管理)
*/
stack_frame->exc_return = 0xFFFFFFFDUL;
return (void *)stack_top;
}
/**
* 计算任务栈最大使用量
* 从栈底开始扫描,找到第一个非 '$' 标记的字节,计算已使用空间
*/
uint32_t os_hw_stack_max_used(void *stack_begin, uint32_t stack_size)
{
uint8_t *addr;
uint32_t max_used;
addr = (uint8_t *)stack_begin;
while (*addr == '$')
{
addr++;
}
max_used = (uint32_t)((os_ubase_t)stack_begin + stack_size - (os_ubase_t)addr);
return max_used;
}
#ifdef OS_USING_OVERFLOW_CHECK
/**
***********************************************************************************************************************
* @brief 检测任务栈是否溢出
*
* @param[in] stack_top 当前栈顶指针
* @param[in] stack_begin 栈起始地址
* @param[in] stack_end 栈结束地址
*
* @return 是否溢出
* @retval OS_TRUE 栈溢出
* @retval OS_FALSE 栈未溢出
***********************************************************************************************************************
*/
os_bool_t os_task_stack_is_overflow(void *stack_top, void *stack_begin, void *stack_end)
{
os_bool_t is_overflow;
OS_ASSERT(OS_NULL != stack_top);
OS_ASSERT(OS_NULL != stack_begin);
OS_ASSERT(OS_NULL != stack_end);
/* 检查栈顶是否在合法范围,以及栈底 '$' 签名是否被覆盖 */
if ((*((uint8_t *)stack_begin) != '$') ||
((os_ubase_t)stack_top < (os_ubase_t)stack_begin) ||
((os_ubase_t)stack_top >= (os_ubase_t)stack_end))
{
is_overflow = OS_TRUE;
}
else
{
is_overflow = OS_FALSE;
}
return is_overflow;
}
#endif /* OS_USING_OVERFLOW_CHECK