RT-Thread內核移植關鍵代碼解析(2) ---- 實現線程棧初始化

一、代碼實現的解釋

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;
};

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章