一、代碼實現的解釋
rt-thread線程棧的初始化代碼如下,其中註釋已經給出了一些說明。
rt_uint8_t *rt_hw_stack_init(void *tentry, //線程入口函數
void *parameter, //線程入口參數
rt_uint8_t *stack_addr, //線程棧頂地址-4,是棧頂!!!
void *texit) //線程退出函數
{
struct stack_frame *stack_frame;
rt_uint8_t *stk;
unsigned long i;
/* 對傳入的棧指針做對齊處理 */
/* 獲取棧頂指針rt_hw_stack_init 在調用的時候,傳給 stack_addr 的是(棧頂指針-4)*/
stk = stack_addr + sizeof(rt_uint32_t);
/* 讓 stk 指針向下 8 字節對齊 */
stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8);
/* stk 指針繼續向下(向棧底)移動 sizeof(struct stack_frame)個偏移 */
stk -= sizeof(struct stack_frame);
/* 將 stk 指針強制轉化爲 stack_frame 類型後存到 stack_frame,得到上下文的棧底的指針 */
stack_frame = (struct stack_frame *)stk;
/* 把所有寄存器的默認值設置爲 0xdeadbeef */
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;//入口函數的參數
/* 將 剩 下 的 參 數 寄 存 器 都 設 置 爲 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 寄 存 器 */
/* 將 IP(Intra-Procedure-call scratch register.) 設 置 爲 0 */
stack_frame->exception_stack_frame.r12 = 0; /* r12 寄 存 器 */
/* 將 線 程 退 出 函 數 的 地 址 保 存 在 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;
/* 返 回 當 前 線 程 的 棧 地 址 */
return stk;
}
該函數實現的效果如下:
二、看懂代碼需要的關鍵信息
1、字節對齊的代碼如下:
#define RT_ALIGN_DOWN(size, align) ((size) & ~((align) - 1))
RT_ALIGN_DOWN((rt_uint32_t)stk, 8);的作用是保證stack_frame棧(用來保存寄存器的值)的起始地址爲8字節對齊,字節對齊的意義見https://blog.csdn.net/zkf11387/article/details/7662450。實現的原理見下圖,就是通過相與抵消低的幾個比特(8字節對齊就使低三位比特爲0),從而實現字節對齊,實現的過程可能會造成我們分配的棧的棧頂會出現空閒,因爲爲了8字節對齊。
2、 struct stack_frame 類型的定義,佔據的空間爲16*4=64字節,對應的是CPU中的寄存器。
struct exception_stack_frame
{
/* 異常發生時,自動加載到 CPU 寄存器的內容 */
rt_uint32_t r0;
rt_uint32_t r1;
rt_uint32_t r2;
rt_uint32_t r3;
rt_uint32_t r12;
rt_uint32_t lr;
rt_uint32_t pc;
rt_uint32_t psr;
};
struct stack_frame
{
/* 異常發生時,需手動加載到 CPU 寄存器的內容 */
/* r4 ~ r11 register */
rt_uint32_t r4;
rt_uint32_t r5;
rt_uint32_t r6;
rt_uint32_t r7;
rt_uint32_t r8;
rt_uint32_t r9;
rt_uint32_t r10;
rt_uint32_t r11;
struct exception_stack_frame exception_stack_frame;
};